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

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

Issue 2566273008: Use SecKeyCreateSignature on macOS 10.12 and later. (Closed)
Patch Set: 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
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; \
Ryan Sleevi 2016/12/13 22:21:07 Is it really fatal if these can't be looked up?
davidben 2016/12/14 00:59:43 If it happens, we got the version check wrong. I t
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 = NULL;
Ryan Sleevi 2016/12/13 22:21:07 nullptr?
davidben 2016/12/14 00:59:43 Done.
154 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw = NULL;
155 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1 = NULL;
156 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256 = NULL;
157 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384 = NULL;
158 SecKeyAlgorithm kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512 = NULL;
159 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA1 = NULL;
160 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA256 = NULL;
161 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA384 = NULL;
162 SecKeyAlgorithm kSecKeyAlgorithmECDSASignatureDigestX962SHA512 = NULL;
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 static const SSLPrivateKey::Hash kHashes[] = {
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, 187 return std::vector<SSLPrivateKey::Hash>(kHashes,
111 kHashes + arraysize(kHashes)); 188 kHashes + arraysize(kHashes));
112 } 189 }
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 signature->resize(signature_data.Length); 276 signature->resize(signature_data.Length);
200 return OK; 277 return OK;
201 } 278 }
202 279
203 private: 280 private:
204 SSLPrivateKey::Type type_; 281 SSLPrivateKey::Type type_;
205 size_t max_length_; 282 size_t max_length_;
206 base::ScopedCFTypeRef<SecKeyRef> key_; 283 base::ScopedCFTypeRef<SecKeyRef> key_;
207 const CSSM_KEY* cssm_key_; 284 const CSSM_KEY* cssm_key_;
208 285
209 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyMac); 286 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeyCSSM);
287 };
288
289 class SSLPlatformKeySecKey : public ThreadedSSLPrivateKey::Delegate {
290 public:
291 SSLPlatformKeySecKey(SSLPrivateKey::Type type,
292 size_t max_length,
293 SecKeyRef key)
294 : type_(type),
295 max_length_(max_length),
296 key_(key, base::scoped_policy::RETAIN) {}
297
298 ~SSLPlatformKeySecKey() override {}
299
300 SSLPrivateKey::Type GetType() override { return type_; }
301
302 std::vector<SSLPrivateKey::Hash> GetDigestPreferences() override {
303 static const SSLPrivateKey::Hash kHashes[] = {
304 SSLPrivateKey::Hash::SHA512, SSLPrivateKey::Hash::SHA384,
305 SSLPrivateKey::Hash::SHA256, SSLPrivateKey::Hash::SHA1};
306 return std::vector<SSLPrivateKey::Hash>(kHashes,
307 kHashes + arraysize(kHashes));
Ryan Sleevi 2016/12/13 22:21:07 pedantry nit: Can you not std::begin(kHashes), std
davidben 2016/12/14 00:59:43 Done. (This was copy-pasted from code that predate
308 }
309
310 size_t GetMaxSignatureLengthInBytes() override { return max_length_; }
311
312 Error SignDigest(SSLPrivateKey::Hash hash,
313 const base::StringPiece& input,
314 std::vector<uint8_t>* signature) override {
315 const SecKeyAPIs& apis = g_sec_key_apis.Get();
316 if (!apis.valid) {
317 LOG(ERROR) << "SecKey APIs not found";
318 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
319 }
320
321 SecKeyAlgorithm algorithm = NULL;
322 if (type_ == SSLPrivateKey::Type::RSA) {
323 switch (hash) {
324 case SSLPrivateKey::Hash::SHA512:
325 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512;
326 break;
327 case SSLPrivateKey::Hash::SHA384:
328 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384;
329 break;
330 case SSLPrivateKey::Hash::SHA256:
331 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256;
332 break;
333 case SSLPrivateKey::Hash::SHA1:
334 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1;
335 break;
336 case SSLPrivateKey::Hash::MD5_SHA1:
337 algorithm = apis.kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw;
338 break;
339 }
340 } else if (SSLPrivateKey::IsECDSAType(type_)) {
341 switch (hash) {
342 case SSLPrivateKey::Hash::SHA512:
343 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA512;
344 break;
345 case SSLPrivateKey::Hash::SHA384:
346 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA384;
347 break;
348 case SSLPrivateKey::Hash::SHA256:
349 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA256;
350 break;
351 case SSLPrivateKey::Hash::SHA1:
352 algorithm = apis.kSecKeyAlgorithmECDSASignatureDigestX962SHA1;
353 break;
354 case SSLPrivateKey::Hash::MD5_SHA1:
355 // MD5-SHA1 is not used with ECDSA.
356 break;
357 }
358 }
359
360 if (!algorithm) {
361 NOTREACHED();
362 return ERR_FAILED;
363 }
364
365 base::ScopedCFTypeRef<CFDataRef> input_ref(CFDataCreateWithBytesNoCopy(
366 kCFAllocatorDefault, reinterpret_cast<const uint8_t*>(input.data()),
367 base::checked_cast<CFIndex>(input.size()), kCFAllocatorNull));
368
369 base::ScopedCFTypeRef<CFErrorRef> error;
370 base::ScopedCFTypeRef<CFDataRef> signature_ref(apis.SecKeyCreateSignature(
371 key_, algorithm, input_ref, error.InitializeInto()));
372 if (!signature_ref) {
373 LOG(ERROR) << error;
374 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED;
375 }
376
377 signature->assign(
378 CFDataGetBytePtr(signature_ref),
379 CFDataGetBytePtr(signature_ref) + CFDataGetLength(signature_ref));
380 return OK;
381 }
382
383 private:
384 SSLPrivateKey::Type type_;
385 size_t max_length_;
386 base::ScopedCFTypeRef<SecKeyRef> key_;
387
388 DISALLOW_COPY_AND_ASSIGN(SSLPlatformKeySecKey);
210 }; 389 };
211 390
212 } // namespace 391 } // namespace
213 392
214 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey( 393 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKeyFromKeychain(
215 X509Certificate* certificate) { 394 X509Certificate* certificate,
395 SecKeychainRef keychain) {
216 // Look up the private key. 396 // Look up the private key.
217 base::ScopedCFTypeRef<SecKeyRef> private_key( 397 base::ScopedCFTypeRef<SecKeyRef> private_key(
218 FetchSecKeyRefForCertificate(certificate)); 398 FetchSecKeyRefForCertificate(certificate, keychain));
219 if (!private_key) 399 if (!private_key)
220 return nullptr; 400 return nullptr;
221 401
402 SSLPrivateKey::Type key_type;
403 size_t max_length;
404 if (!GetClientCertInfo(certificate, &key_type, &max_length))
405 return nullptr;
406
407 if (base::mac::IsAtLeastOS10_12()) {
408 return make_scoped_refptr(
409 new ThreadedSSLPrivateKey(base::MakeUnique<SSLPlatformKeySecKey>(
410 key_type, max_length, private_key.get()),
411 GetSSLPlatformKeyTaskRunner()));
412 }
413
222 const CSSM_KEY* cssm_key; 414 const CSSM_KEY* cssm_key;
223 OSStatus status = SecKeyGetCSSMKey(private_key.get(), &cssm_key); 415 OSStatus status = SecKeyGetCSSMKey(private_key.get(), &cssm_key);
224 if (status != noErr) { 416 if (status != noErr) {
225 OSSTATUS_LOG(WARNING, status); 417 OSSTATUS_LOG(WARNING, status);
226 return nullptr; 418 return nullptr;
227 } 419 }
228 420
229 SSLPrivateKey::Type key_type; 421 return make_scoped_refptr(new ThreadedSSLPrivateKey(
230 size_t max_length; 422 base::MakeUnique<SSLPlatformKeyCSSM>(key_type, max_length,
231 if (!GetClientCertInfo(certificate, &key_type, &max_length)) 423 private_key.get(), cssm_key),
232 return nullptr; 424 GetSSLPlatformKeyTaskRunner()));
425 }
233 426
234 return make_scoped_refptr(new ThreadedSSLPrivateKey( 427 scoped_refptr<SSLPrivateKey> FetchClientCertPrivateKey(
235 base::MakeUnique<SSLPlatformKeyMac>(key_type, max_length, 428 X509Certificate* certificate) {
236 private_key.get(), cssm_key), 429 return FetchClientCertPrivateKeyFromKeychain(certificate, nullptr);
237 GetSSLPlatformKeyTaskRunner()));
238 } 430 }
239 431
240 #pragma clang diagnostic pop // "-Wdeprecated-declarations" 432 #pragma clang diagnostic pop // "-Wdeprecated-declarations"
241 433
242 } // namespace net 434 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698