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