Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: net/ssl/ssl_platform_key_mac.cc

Issue 2566273008: Use SecKeyCreateSignature on macOS 10.12 and later. (Closed)
Patch Set: rsleevi comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/ssl/ssl_platform_key_mac.h ('k') | net/ssl/ssl_platform_key_mac_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/ssl/ssl_platform_key.h" 5 #include "net/ssl/ssl_platform_key_mac.h"
6 6
7 #include <dlfcn.h>
8 #include <CoreFoundation/CoreFoundation.h>
7 #include <Security/cssm.h> 9 #include <Security/cssm.h>
8 #include <Security/SecBase.h> 10 #include <Security/SecBase.h>
9 #include <Security/SecCertificate.h> 11 #include <Security/SecCertificate.h>
10 #include <Security/SecIdentity.h> 12 #include <Security/SecIdentity.h>
11 #include <Security/SecKey.h> 13 #include <Security/SecKey.h>
12 14
13 #include <memory> 15 #include <memory>
14 16
17 #include "base/lazy_instance.h"
15 #include "base/location.h" 18 #include "base/location.h"
16 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/mac/foundation_util.h"
17 #include "base/mac/mac_logging.h" 21 #include "base/mac/mac_logging.h"
22 #include "base/mac/mac_util.h"
18 #include "base/mac/scoped_cftyperef.h" 23 #include "base/mac/scoped_cftyperef.h"
19 #include "base/macros.h" 24 #include "base/macros.h"
20 #include "base/memory/ptr_util.h" 25 #include "base/memory/ptr_util.h"
21 #include "base/memory/scoped_policy.h" 26 #include "base/memory/scoped_policy.h"
27 #include "base/numerics/safe_conversions.h"
22 #include "base/synchronization/lock.h" 28 #include "base/synchronization/lock.h"
23 #include "crypto/mac_security_services_lock.h" 29 #include "crypto/mac_security_services_lock.h"
24 #include "crypto/openssl_util.h" 30 #include "crypto/openssl_util.h"
25 #include "net/base/net_errors.h" 31 #include "net/base/net_errors.h"
26 #include "net/cert/x509_certificate.h" 32 #include "net/cert/x509_certificate.h"
33 #include "net/ssl/ssl_platform_key.h"
27 #include "net/ssl/ssl_platform_key_util.h" 34 #include "net/ssl/ssl_platform_key_util.h"
28 #include "net/ssl/ssl_private_key.h" 35 #include "net/ssl/ssl_private_key.h"
29 #include "net/ssl/threaded_ssl_private_key.h" 36 #include "net/ssl/threaded_ssl_private_key.h"
30 #include "third_party/boringssl/src/include/openssl/ecdsa.h" 37 #include "third_party/boringssl/src/include/openssl/ecdsa.h"
31 #include "third_party/boringssl/src/include/openssl/mem.h" 38 #include "third_party/boringssl/src/include/openssl/mem.h"
32 #include "third_party/boringssl/src/include/openssl/nid.h" 39 #include "third_party/boringssl/src/include/openssl/nid.h"
33 #include "third_party/boringssl/src/include/openssl/rsa.h" 40 #include "third_party/boringssl/src/include/openssl/rsa.h"
34 41
42 // TODO(davidben): Remove this after https://crbug.com/669240 is fixed.
43 #if !defined(MAC_OS_X_VERSION_10_12) || \
44 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
45 typedef CFStringRef SecKeyAlgorithm;
46 #endif
47
35 namespace net { 48 namespace net {
36 49
37 // CSSM functions are deprecated as of OSX 10.7, but have no replacement. 50 // CSSM functions are deprecated as of OSX 10.7, but have no replacement.
38 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1 51 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1
39 #pragma clang diagnostic push 52 #pragma clang diagnostic push
40 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 53 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
41 54
42 namespace { 55 namespace {
43 56
44 class ScopedCSSM_CC_HANDLE { 57 class ScopedCSSM_CC_HANDLE {
(...skipping 10 matching lines...) Expand all
55 CSSM_DeleteContext(handle_); 68 CSSM_DeleteContext(handle_);
56 handle_ = 0; 69 handle_ = 0;
57 } 70 }
58 71
59 private: 72 private:
60 CSSM_CC_HANDLE handle_; 73 CSSM_CC_HANDLE handle_;
61 74
62 DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE); 75 DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE);
63 }; 76 };
64 77
65 // Looks up the private key for |certificate| in KeyChain and returns 78 // Looks up the private key for |certificate| in |keychain| and returns
66 // a SecKeyRef or nullptr on failure. The caller takes ownership of the 79 // a SecKeyRef or nullptr on failure. The caller takes ownership of the
67 // result. 80 // result.
68 SecKeyRef FetchSecKeyRefForCertificate(const X509Certificate* certificate) { 81 SecKeyRef FetchSecKeyRefForCertificate(const X509Certificate* certificate,
82 SecKeychainRef keychain) {
69 OSStatus status; 83 OSStatus status;
70 base::ScopedCFTypeRef<SecIdentityRef> identity; 84 base::ScopedCFTypeRef<SecIdentityRef> identity;
71 { 85 {
72 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 86 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
73 status = SecIdentityCreateWithCertificate( 87 status = SecIdentityCreateWithCertificate(
74 nullptr, certificate->os_cert_handle(), identity.InitializeInto()); 88 keychain, certificate->os_cert_handle(), identity.InitializeInto());
75 } 89 }
76 if (status != noErr) { 90 if (status != noErr) {
77 OSSTATUS_LOG(WARNING, status); 91 OSSTATUS_LOG(WARNING, status);
78 return nullptr; 92 return nullptr;
79 } 93 }
80 94
81 base::ScopedCFTypeRef<SecKeyRef> private_key; 95 base::ScopedCFTypeRef<SecKeyRef> private_key;
82 status = SecIdentityCopyPrivateKey(identity, private_key.InitializeInto()); 96 status = SecIdentityCopyPrivateKey(identity, private_key.InitializeInto());
83 if (status != noErr) { 97 if (status != noErr) {
84 OSSTATUS_LOG(WARNING, status); 98 OSSTATUS_LOG(WARNING, status);
85 return nullptr; 99 return nullptr;
86 } 100 }
87 101
88 return private_key.release(); 102 return private_key.release();
89 } 103 }
90 104
91 class SSLPlatformKeyMac : public ThreadedSSLPrivateKey::Delegate { 105 // These symbols were added in the 10.12 SDK, but we currently use an older SDK,
106 // so look them up with dlsym.
107 //
108 // TODO(davidben): After https://crbug.com/669240 is fixed, use the APIs
109 // directly.
110 struct SecKeyAPIs {
111 SecKeyAPIs() { Init(); }
112
113 void Init() {
114 SecKeyCreateSignature = reinterpret_cast<SecKeyCreateSignatureFunc>(
115 dlsym(RTLD_DEFAULT, "SecKeyCreateSignature"));
116 if (!SecKeyCreateSignature) {
117 NOTREACHED();
118 return;
119 }
120
121 #define LOOKUP_ALGORITHM(name) \
122 do { \
123 SecKeyAlgorithm* algorithm = \
124 reinterpret_cast<SecKeyAlgorithm*>(dlsym(RTLD_DEFAULT, #name)); \
125 if (!algorithm) { \
126 NOTREACHED(); \
127 return; \
128 } \
129 name = *algorithm; \
130 } while (0)
131
132 LOOKUP_ALGORITHM(kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw);
133 LOOKUP_ALGORITHM(kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1);
134 LOOKUP_ALGORITHM(kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256);
135 LOOKUP_ALGORITHM(kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384);
136 LOOKUP_ALGORITHM(kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512);
137 LOOKUP_ALGORITHM(kSecKeyAlgorithmECDSASignatureDigestX962SHA1);
138 LOOKUP_ALGORITHM(kSecKeyAlgorithmECDSASignatureDigestX962SHA256);
139 LOOKUP_ALGORITHM(kSecKeyAlgorithmECDSASignatureDigestX962SHA384);
140 LOOKUP_ALGORITHM(kSecKeyAlgorithmECDSASignatureDigestX962SHA512);
141
142 #undef LOOKUP_ALGORITHM
143
144 valid = true;
145 }
146
147 using SecKeyCreateSignatureFunc = CFDataRef (*)(SecKeyRef key,
148 SecKeyAlgorithm algorithm,
149 CFDataRef dataToSign,
150 CFErrorRef* error);
151
152 bool valid = false;
153 SecKeyCreateSignatureFunc SecKeyCreateSignature = nullptr;
154 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw = nullptr;
155 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 = nullptr;
156 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 = nullptr;
157 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 = nullptr;
158 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 = nullptr;
159 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA1 = nullptr;
160 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA256 = nullptr;
161 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA384 = nullptr;
162 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA512 = nullptr;
163 };
164
165 base::LazyInstance<SecKeyAPIs>::Leaky g_sec_key_apis =
166 LAZY_INSTANCE_INITIALIZER;
167
168 class SSLPlatformKeyCSSM : public ThreadedSSLPrivateKey::Delegate {
92 public: 169 public:
93 SSLPlatformKeyMac(SSLPrivateKey::Type type, 170 SSLPlatformKeyCSSM(SSLPrivateKey::Type type,
94 size_t max_length, 171 size_t max_length,
95 SecKeyRef key, 172 SecKeyRef key,
96 const CSSM_KEY* cssm_key) 173 const CSSM_KEY* cssm_key)
97 : type_(type), 174 : type_(type),
98 max_length_(max_length), 175 max_length_(max_length),
99 key_(key, base::scoped_policy::RETAIN), 176 key_(key, base::scoped_policy::RETAIN),
100 cssm_key_(cssm_key) {} 177 cssm_key_(cssm_key) {}
101 178
102 ~SSLPlatformKeyMac() override {} 179 ~SSLPlatformKeyCSSM() override {}
103 180
104 SSLPrivateKey::Type GetType() override { return type_; } 181 SSLPrivateKey::Type GetType() override { return type_; }
105 182
106 std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override { 183 std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override {
107 static const SSLPrivateKey::Hash kHashes[] = { 184 return std::vector<SSLPrivateKey::Hash>{
108 SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384, 185 SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384,
109 SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1}; 186 SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1};
110 return std::vector<SSLPrivateKey::Hash>(kHashes,
111 kHashes + arraysize(kHashes));
112 } 187 }
113 188
114 size_t GetMaxSignatureLengthInBytes() override { return max_length_; } 189 size_t GetMaxSignatureLengthInBytes() override { return max_length_; }
115 190
116 Error SignDigest(SSLPrivateKey::Hash hash, 191 Error SignDigest(SSLPrivateKey::Hash hash,
117 const base::StringPiece& input, 192 const base::StringPiece& input,
118 std::vector<uint8_t>* signature) override { 193 std::vector<uint8_t>* signature) override {
119 crypto::OpenSSLErrStackTracer tracer(FROM_HERE); 194 crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
120 195
121 CSSM_CSP_HANDLE csp_handle; 196 CSSM_CSP_HANDLE csp_handle;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 signature->resize(signature_data.Length); 274 signature->resize(signature_data.Length);
200 return OK; 275 return OK;
201 } 276 }
202 277
203 private: 278 private:
204 SSLPrivateKey::Type type_; 279 SSLPrivateKey::Type type_;
205 size_t max_length_; 280 size_t max_length_;
206 base::ScopedCFTypeRef<SecKeyRef> key_; 281 base::ScopedCFTypeRef<SecKeyRef> key_;
207 const CSSM_KEY* cssm_key_; 282 const CSSM_KEY* cssm_key_;
208 283
209 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyMac); 284 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyCSSM);
285 };
286
287 class SSLPlatformKeySecKey : public ThreadedSSLPrivateKey::Delegate {
288 public:
289 SSLPlatformKeySecKey(SSLPrivateKey::Type type,
290 size_t max_length,
291 SecKeyRef key)
292 : type_(type),
293 max_length_(max_length),
294 key_(key, base::scoped_policy::RETAIN) {}
295
296 ~SSLPlatformKeySecKey() override {}
297
298 SSLPrivateKey::Type GetType() override { return type_; }
299
300 std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override {
301 return std::vector<SSLPrivateKey::Hash>{
302 SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384,
303 SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1};
304 }
305
306 size_t GetMaxSignatureLengthInBytes() override { return max_length_; }
307
308 Error SignDigest(SSLPrivateKey::Hash hash,
309 const base::StringPiece& input,
310 std::vector<uint8_t>* signature) override {
311 const SecKeyAPIs& apis = g_sec_key_apis.Get();
312 if (!apis.valid) {
313 LOG(ERROR) << "SecKey APIs not found";
314 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
315 }
316
317 SecKeyAlgorithm algorithm = nullptr;
318 if (type_ == SSLPrivateKey::Type::RSA) {
319 switch (hash) {
320 case SSLPrivateKey::Hash::SHA512:
321 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512;
322 break;
323 case SSLPrivateKey::Hash::SHA384:
324 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384;
325 break;
326 case SSLPrivateKey::Hash::SHA256:
327 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256;
328 break;
329 case SSLPrivateKey::Hash::SHA1:
330 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1;
331 break;
332 case SSLPrivateKey::Hash::MD5_SHA1:
333 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw;
334 break;
335 }
336 } else if (SSLPrivateKey::IsECDSAType(type_)) {
337 switch (hash) {
338 case SSLPrivateKey::Hash::SHA512:
339 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA512;
340 break;
341 case SSLPrivateKey::Hash::SHA384:
342 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA384;
343 break;
344 case SSLPrivateKey::Hash::SHA256:
345 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA256;
346 break;
347 case SSLPrivateKey::Hash::SHA1:
348 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA1;
349 break;
350 case SSLPrivateKey::Hash::MD5_SHA1:
351 // MD5-SHA1 is not used with ECDSA.
352 break;
353 }
354 }
355
356 if (!algorithm) {
357 NOTREACHED();
358 return ERR_FAILED;
359 }
360
361 base::ScopedCFTypeRef<CFDataRef> input_ref(CFDataCreateWithBytesNoCopy(
362 kCFAllocatorDefault, reinterpret_cast<const uint8_t*>(input.data()),
363 base::checked_cast<CFIndex>(input.size()), kCFAllocatorNull));
364
365 base::ScopedCFTypeRef<CFErrorRef> error;
366 base::ScopedCFTypeRef<CFDataRef> signature_ref(apis.SecKeyCreateSignature(
367 key_, algorithm, input_ref, error.InitializeInto()));
368 if (!signature_ref) {
369 LOG(ERROR) << error;
370 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
371 }
372
373 signature->assign(
374 CFDataGetBytePtr(signature_ref),
375 CFDataGetBytePtr(signature_ref) + CFDataGetLength(signature_ref));
376 return OK;
377 }
378
379 private:
380 SSLPrivateKey::Type type_;
381 size_t max_length_;
382 base::ScopedCFTypeRef<SecKeyRef> key_;
383
384 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeySecKey);
210 }; 385 };
211 386
212 } // namespace 387 } // namespace
213 388
214 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey( 389 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKeyFromKeychain(
215 X509Certificate* certificate) { 390 const X509Certificate* certificate,
391 SecKeychainRef keychain) {
216 // Look up the private key. 392 // Look up the private key.
217 base::ScopedCFTypeRef<SecKeyRef> private_key( 393 base::ScopedCFTypeRef<SecKeyRef> private_key(
218 FetchSecKeyRefForCertificate(certificate)); 394 FetchSecKeyRefForCertificate(certificate, keychain));
219 if (!private_key) 395 if (!private_key)
220 return nullptr; 396 return nullptr;
221 397
398 SSLPrivateKey::Type key_type;
399 size_t max_length;
400 if (!GetClientCertInfo(certificate, &key_type, &max_length))
401 return nullptr;
402
403 if (base::mac::IsAtLeastOS10_12()) {
404 return make_scoped_refptr(
405 new ThreadedSSLPrivateKey(base::MakeUnique<SSLPlatformKeySecKey>(
406 key_type, max_length, private_key.get()),
407 GetSSLPlatformKeyTaskRunner()));
408 }
409
222 const CSSM_KEY* cssm_key; 410 const CSSM_KEY* cssm_key;
223 OSStatus status = SecKeyGetCSSMKey(private_key.get(), &cssm_key); 411 OSStatus status = SecKeyGetCSSMKey(private_key.get(), &cssm_key);
224 if (status != noErr) { 412 if (status != noErr) {
225 OSSTATUS_LOG(WARNING, status); 413 OSSTATUS_LOG(WARNING, status);
226 return nullptr; 414 return nullptr;
227 } 415 }
228 416
229 SSLPrivateKey::Type key_type; 417 return make_scoped_refptr(new ThreadedSSLPrivateKey(
230 size_t max_length; 418 base::MakeUnique<SSLPlatformKeyCSSM>(key_type, max_length,
231 if (!GetClientCertInfo(certificate, &key_type, &max_length)) 419 private_key.get(), cssm_key),
232 return nullptr; 420 GetSSLPlatformKeyTaskRunner()));
421 }
233 422
234 return make_scoped_refptr(new ThreadedSSLPrivateKey( 423 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
235 base::MakeUnique<SSLPlatformKeyMac>(key_type, max_length, 424 const X509Certificate* certificate) {
236 private_key.get(), cssm_key), 425 return FetchClientCertPrivateKeyFromKeychain(certificate, nullptr);
237 GetSSLPlatformKeyTaskRunner()));
238 } 426 }
239 427
240 #pragma clang diagnostic pop // "-Wdeprecated-declarations" 428 #pragma clang diagnostic pop // "-Wdeprecated-declarations"
241 429
242 } // namespace net 430 } // namespace net
OLDNEW
« no previous file with comments | « net/ssl/ssl_platform_key_mac.h ('k') | net/ssl/ssl_platform_key_mac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698