xref: /aosp_15_r20/external/cronet/net/ssl/ssl_platform_key_mac.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/ssl/ssl_platform_key_mac.h"
6 
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <Security/SecBase.h>
9 #include <Security/SecCertificate.h>
10 #include <Security/SecIdentity.h>
11 #include <Security/SecKey.h>
12 
13 #include <memory>
14 #include <optional>
15 #include <utility>
16 #include <vector>
17 
18 #include "base/apple/foundation_util.h"
19 #include "base/apple/osstatus_logging.h"
20 #include "base/apple/scoped_cftyperef.h"
21 #include "base/containers/span.h"
22 #include "base/logging.h"
23 #include "base/mac/mac_util.h"
24 #include "base/memory/scoped_policy.h"
25 #include "base/numerics/safe_conversions.h"
26 #include "crypto/openssl_util.h"
27 #include "net/base/net_errors.h"
28 #include "net/cert/x509_certificate.h"
29 #include "net/cert/x509_util_apple.h"
30 #include "net/ssl/ssl_platform_key_util.h"
31 #include "net/ssl/ssl_private_key.h"
32 #include "net/ssl/threaded_ssl_private_key.h"
33 #include "third_party/boringssl/src/include/openssl/evp.h"
34 #include "third_party/boringssl/src/include/openssl/mem.h"
35 #include "third_party/boringssl/src/include/openssl/nid.h"
36 #include "third_party/boringssl/src/include/openssl/rsa.h"
37 #include "third_party/boringssl/src/include/openssl/ssl.h"
38 
39 namespace net {
40 
41 namespace {
42 
43 // Returns the corresponding SecKeyAlgorithm or nullptr if unrecognized.
GetSecKeyAlgorithm(uint16_t algorithm)44 SecKeyAlgorithm GetSecKeyAlgorithm(uint16_t algorithm) {
45   switch (algorithm) {
46     case SSL_SIGN_RSA_PKCS1_SHA512:
47       return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512;
48     case SSL_SIGN_RSA_PKCS1_SHA384:
49       return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384;
50     case SSL_SIGN_RSA_PKCS1_SHA256:
51       return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256;
52     case SSL_SIGN_RSA_PKCS1_SHA1:
53       return kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1;
54     case SSL_SIGN_ECDSA_SECP521R1_SHA512:
55       return kSecKeyAlgorithmECDSASignatureDigestX962SHA512;
56     case SSL_SIGN_ECDSA_SECP384R1_SHA384:
57       return kSecKeyAlgorithmECDSASignatureDigestX962SHA384;
58     case SSL_SIGN_ECDSA_SECP256R1_SHA256:
59       return kSecKeyAlgorithmECDSASignatureDigestX962SHA256;
60     case SSL_SIGN_ECDSA_SHA1:
61       return kSecKeyAlgorithmECDSASignatureDigestX962SHA1;
62     case SSL_SIGN_RSA_PSS_SHA512:
63       return kSecKeyAlgorithmRSASignatureDigestPSSSHA512;
64     case SSL_SIGN_RSA_PSS_SHA384:
65       return kSecKeyAlgorithmRSASignatureDigestPSSSHA384;
66     case SSL_SIGN_RSA_PSS_SHA256:
67       return kSecKeyAlgorithmRSASignatureDigestPSSSHA256;
68   }
69 
70   return nullptr;
71 }
72 
73 class SSLPlatformKeySecKey : public ThreadedSSLPrivateKey::Delegate {
74  public:
SSLPlatformKeySecKey(bssl::UniquePtr<EVP_PKEY> pubkey,SecKeyRef key)75   SSLPlatformKeySecKey(bssl::UniquePtr<EVP_PKEY> pubkey, SecKeyRef key)
76       : pubkey_(std::move(pubkey)), key_(key, base::scoped_policy::RETAIN) {
77     // Determine the algorithms supported by the key.
78     for (uint16_t algorithm : SSLPrivateKey::DefaultAlgorithmPreferences(
79              EVP_PKEY_id(pubkey_.get()), true /* include PSS */)) {
80       bool unused;
81       if (GetSecKeyAlgorithmWithFallback(algorithm, &unused)) {
82         preferences_.push_back(algorithm);
83       }
84     }
85   }
86 
87   SSLPlatformKeySecKey(const SSLPlatformKeySecKey&) = delete;
88   SSLPlatformKeySecKey& operator=(const SSLPlatformKeySecKey&) = delete;
89 
90   ~SSLPlatformKeySecKey() override = default;
91 
GetProviderName()92   std::string GetProviderName() override {
93     // TODO(https://crbug.com/900721): Is there a more descriptive name to
94     // return?
95     return "SecKey";
96   }
97 
GetAlgorithmPreferences()98   std::vector<uint16_t> GetAlgorithmPreferences() override {
99     return preferences_;
100   }
101 
Sign(uint16_t algorithm,base::span<const uint8_t> input,std::vector<uint8_t> * signature)102   Error Sign(uint16_t algorithm,
103              base::span<const uint8_t> input,
104              std::vector<uint8_t>* signature) override {
105     bool pss_fallback = false;
106     SecKeyAlgorithm sec_algorithm =
107         GetSecKeyAlgorithmWithFallback(algorithm, &pss_fallback);
108     if (!sec_algorithm) {
109       // The caller should not request a signature algorithm we do not support.
110       // However, it's possible `key_` previously reported it supported an
111       // algorithm but no longer does. A compromised network service could also
112       // request invalid algorithms, so cleanly fail.
113       LOG(ERROR) << "Unsupported signature algorithm: " << algorithm;
114       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
115     }
116 
117     const EVP_MD* md = SSL_get_signature_algorithm_digest(algorithm);
118     uint8_t digest_buf[EVP_MAX_MD_SIZE];
119     unsigned digest_len;
120     if (!md || !EVP_Digest(input.data(), input.size(), digest_buf, &digest_len,
121                            md, nullptr)) {
122       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
123     }
124     base::span<const uint8_t> digest = base::make_span(digest_buf, digest_len);
125 
126     std::optional<std::vector<uint8_t>> pss_storage;
127     if (pss_fallback) {
128       // Implement RSA-PSS by adding the padding manually and then using
129       // kSecKeyAlgorithmRSASignatureRaw.
130       DCHECK(SSL_is_signature_algorithm_rsa_pss(algorithm));
131       DCHECK_EQ(sec_algorithm, kSecKeyAlgorithmRSASignatureRaw);
132       pss_storage = AddPSSPadding(pubkey_.get(), md, digest);
133       if (!pss_storage) {
134         return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
135       }
136       digest = *pss_storage;
137     }
138 
139     base::apple::ScopedCFTypeRef<CFDataRef> digest_ref(
140         CFDataCreate(kCFAllocatorDefault, digest.data(),
141                      base::checked_cast<CFIndex>(digest.size())));
142 
143     base::apple::ScopedCFTypeRef<CFErrorRef> error;
144     base::apple::ScopedCFTypeRef<CFDataRef> signature_ref(SecKeyCreateSignature(
145         key_.get(), sec_algorithm, digest_ref.get(), error.InitializeInto()));
146     if (!signature_ref) {
147       LOG(ERROR) << error.get();
148       return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
149     }
150 
151     signature->assign(CFDataGetBytePtr(signature_ref.get()),
152                       CFDataGetBytePtr(signature_ref.get()) +
153                           CFDataGetLength(signature_ref.get()));
154     return OK;
155   }
156 
157  private:
158   // Returns the algorithm to use with |algorithm| and this key, or nullptr if
159   // not supported. If the resulting algorithm should be manually padded for
160   // RSA-PSS, |*out_pss_fallback| is set to true.
GetSecKeyAlgorithmWithFallback(uint16_t algorithm,bool * out_pss_fallback)161   SecKeyAlgorithm GetSecKeyAlgorithmWithFallback(uint16_t algorithm,
162                                                  bool* out_pss_fallback) {
163     SecKeyAlgorithm sec_algorithm = GetSecKeyAlgorithm(algorithm);
164     if (sec_algorithm &&
165         SecKeyIsAlgorithmSupported(key_.get(), kSecKeyOperationTypeSign,
166                                    sec_algorithm)) {
167       *out_pss_fallback = false;
168       return sec_algorithm;
169     }
170 
171     if (SSL_is_signature_algorithm_rsa_pss(algorithm) &&
172         SecKeyIsAlgorithmSupported(key_.get(), kSecKeyOperationTypeSign,
173                                    kSecKeyAlgorithmRSASignatureRaw)) {
174       *out_pss_fallback = true;
175       return kSecKeyAlgorithmRSASignatureRaw;
176     }
177 
178     return nullptr;
179   }
180 
181   std::vector<uint16_t> preferences_;
182   bssl::UniquePtr<EVP_PKEY> pubkey_;
183   base::apple::ScopedCFTypeRef<SecKeyRef> key_;
184 };
185 
186 }  // namespace
187 
CreateSSLPrivateKeyForSecKey(const X509Certificate * certificate,SecKeyRef key)188 scoped_refptr<SSLPrivateKey> CreateSSLPrivateKeyForSecKey(
189     const X509Certificate* certificate,
190     SecKeyRef key) {
191   bssl::UniquePtr<EVP_PKEY> pubkey = GetClientCertPublicKey(certificate);
192   if (!pubkey)
193     return nullptr;
194 
195   return base::MakeRefCounted<ThreadedSSLPrivateKey>(
196       std::make_unique<SSLPlatformKeySecKey>(std::move(pubkey), key),
197       GetSSLPlatformKeyTaskRunner());
198 }
199 
WrapUnexportableKey(const crypto::UnexportableSigningKey & unexportable_key)200 scoped_refptr<SSLPrivateKey> WrapUnexportableKey(
201     const crypto::UnexportableSigningKey& unexportable_key) {
202   bssl::UniquePtr<EVP_PKEY> pubkey =
203       ParseSpki(unexportable_key.GetSubjectPublicKeyInfo());
204   if (!pubkey) {
205     return nullptr;
206   }
207 
208   return base::MakeRefCounted<ThreadedSSLPrivateKey>(
209       std::make_unique<SSLPlatformKeySecKey>(std::move(pubkey),
210                                              unexportable_key.GetSecKeyRef()),
211       GetSSLPlatformKeyTaskRunner());
212 }
213 
214 }  // namespace net
215