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