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