| 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..1027aad86dc4b8321df5f6b6caafce2ce38549d9 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* kKeys[] = {
|
| + kSecClass, kSecMatchLimit, kSecReturnRef, kSecAttrCanSign,
|
| + };
|
| + static const void* kValues[] = {
|
| + kSecClassIdentity, kSecMatchLimitAll, kCFBooleanTrue, kCFBooleanTrue,
|
| + };
|
| + ScopedCFTypeRef<CFDictionaryRef> query(CFDictionaryCreate(
|
| + kCFAllocatorDefault, kKeys, kValues, arraysize(kValues),
|
| + &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);
|
|
|