Chromium Code Reviews| Index: net/ssl/client_cert_store_mac.cc |
| diff --git a/net/ssl/client_cert_store_mac.cc b/net/ssl/client_cert_store_mac.cc |
| index 7fadb337f1e7735ae8ffd340c81c93c95588d7c4..a6fbe68829b082fa5e259a03cc47ddf042dde5e1 100644 |
| --- a/net/ssl/client_cert_store_mac.cc |
| +++ b/net/ssl/client_cert_store_mac.cc |
| @@ -12,6 +12,8 @@ |
| #include <algorithm> |
| #include <string> |
| +#include <utility> |
| +#include <vector> |
| #include "base/callback.h" |
| #include "base/logging.h" |
| @@ -231,6 +233,37 @@ void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, |
| sort(sort_begin, sort_end, x509_util::ClientCertSorter()); |
| } |
| +// Given an |identity|, identifies its corresponding certificate, and either |
| +// adds it to |regular_certs| or assigns it to |preferred_cert|, if the |
| +// |identity| matches the |preferred_identity|. |
| +void AddIdentity(SecIdentityRef identity, |
| + SecIdentityRef preferred_identity, |
| + CertificateList* regular_certs, |
| + scoped_refptr<X509Certificate>* preferred_cert) { |
| + OSStatus err; |
| + ScopedCFTypeRef<SecCertificateRef> cert_handle; |
| + err = SecIdentityCopyCertificate(identity, cert_handle.InitializeInto()); |
| + if (err != noErr) |
| + return; |
| + |
| + if (!SupportsSSLClientAuth(cert_handle)) |
| + return; |
| + |
| + scoped_refptr<X509Certificate> cert( |
| + x509_util::CreateX509CertificateFromSecCertificate( |
| + cert_handle, std::vector<SecCertificateRef>())); |
| + if (!cert) |
| + return; |
| + |
| + if (preferred_identity && CFEqual(preferred_identity, identity)) { |
| + // Only one certificate should match. |
| + DCHECK(!preferred_cert->get()); |
| + *preferred_cert = cert; |
| + } else { |
| + regular_certs->push_back(cert); |
| + } |
| +} |
| + |
| } // namespace |
| ClientCertStoreMac::ClientCertStoreMac() {} |
| @@ -284,29 +317,7 @@ void ClientCertStoreMac::GetClientCerts( |
| if (err) |
| break; |
| ScopedCFTypeRef<SecIdentityRef> scoped_identity(identity); |
| - |
| - SecCertificateRef cert_handle; |
| - err = SecIdentityCopyCertificate(identity, &cert_handle); |
| - if (err != noErr) |
| - continue; |
| - ScopedCFTypeRef<SecCertificateRef> scoped_cert_handle(cert_handle); |
| - |
| - if (!SupportsSSLClientAuth(cert_handle)) |
| - continue; |
| - |
| - scoped_refptr<X509Certificate> cert( |
| - x509_util::CreateX509CertificateFromSecCertificate( |
| - cert_handle, std::vector<SecCertificateRef>())); |
| - if (!cert) |
| - continue; |
| - |
| - if (preferred_identity && CFEqual(preferred_identity, identity)) { |
| - // Only one certificate should match. |
| - DCHECK(!preferred_cert.get()); |
| - preferred_cert = cert; |
| - } else { |
| - regular_certs.push_back(cert); |
| - } |
| + AddIdentity(identity, preferred_identity, ®ular_certs, &preferred_cert); |
| } |
| if (err != errSecItemNotFound) { |
| @@ -315,6 +326,36 @@ void ClientCertStoreMac::GetClientCerts( |
| return; |
| } |
| + // macOS provides two ways to search for identities. SecIdentitySearchCreate() |
| + // is deprecated, as it relies on CSSM_KEYUSE_SIGN (part of the deprecated |
| + // CDSM/CSSA implementation), but is necessary to return some certificates |
| + // that would otherwise not be returned by SecItemCopyMatching(), which is the |
| + // non-deprecated way. However, SecIdentitySearchCreate() will not return all |
| + // items, particularly smart-card based identities, so it's necessary to call |
| + // both functions. |
| + static const void* keys[] = { |
|
awong
2017/06/07 21:21:08
Oh yeah...and if it's a constant, call it kKeys an
agaynor
2017/06/09 00:32:05
Done.
|
| + kSecClass, kSecMatchLimit, kSecReturnRef, kSecAttrCanSign, |
| + }; |
| + static const void* values[] = { |
| + kSecClassIdentity, kSecMatchLimitAll, kCFBooleanTrue, kCFBooleanTrue, |
| + }; |
| + ScopedCFTypeRef<CFDictionaryRef> query(CFDictionaryCreate( |
| + kCFAllocatorDefault, keys, values, arraysize(values), |
| + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); |
| + ScopedCFTypeRef<CFArrayRef> result; |
| + { |
| + base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
| + err = SecItemCopyMatching( |
| + query, reinterpret_cast<CFTypeRef*>(result.InitializeInto())); |
| + } |
| + if (!err) { |
| + for (CFIndex i = 0; i < CFArrayGetCount(result); i++) { |
| + void* item = const_cast<void*>(CFArrayGetValueAtIndex(result, i)); |
| + AddIdentity(reinterpret_cast<SecIdentityRef>(item), preferred_identity, |
| + ®ular_certs, &preferred_cert); |
| + } |
| + } |
| + |
| CertificateList selected_certs; |
| GetClientCertsImpl(preferred_cert, regular_certs, request, true, |
| &selected_certs); |