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..d69ebbc0f1573001e6c79edf3a24e6199dbe1182 100644 |
--- a/net/ssl/client_cert_store_mac.cc |
+++ b/net/ssl/client_cert_store_mac.cc |
@@ -284,29 +284,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(regular_certs, preferred_cert, preferred_identity.get(), identity); |
} |
if (err != errSecItemNotFound) { |
@@ -315,12 +293,74 @@ void ClientCertStoreMac::GetClientCerts( |
return; |
} |
+ // For reasons I don't understand, macOS has two different ways of querying |
+ // for client certificate identities. The way we just tried will miss some |
+ // smart card based certificates, and this way misses some soft certificates. |
Ryan Sleevi
2017/05/30 18:00:01
We try to avoid pronouns in comments (I/we) and tr
agaynor
2017/05/31 02:37:33
Done.
|
+ const void *keys[] = { |
Ryan Sleevi
2017/05/30 18:00:01
You can use "git cl format" to ensure this is prop
Ryan Sleevi
2017/05/30 18:00:01
So, I _believe_ for correctness, that kSecAttrCanS
agaynor
2017/05/31 02:37:33
Done.
agaynor
2017/05/31 02:37:33
It's a boring old RSA key. I've added |kSecAttrCan
mattm
2017/06/05 23:34:27
Looking at that code a bit, it seems that SecItemC
|
+ kSecClass, |
+ kSecMatchLimit, |
+ kSecReturnRef, |
+ }; |
+ const void *values[] = { |
+ kSecClassIdentity, |
+ kSecMatchLimitAll, |
+ kCFBooleanTrue, |
+ }; |
+ CFDictionaryRef query = CFDictionaryCreate( |
Ryan Sleevi
2017/05/30 18:00:01
You can see we used the ScopedCFTypeRef C++ helper
agaynor
2017/05/31 02:37:33
Done.
|
+ kCFAllocatorDefault, |
+ keys, |
+ values, |
+ sizeof(values) / sizeof(values[0]), |
+ &kCFTypeDictionaryKeyCallBacks, |
+ &kCFTypeDictionaryValueCallBacks |
+ ); |
+ CFArrayRef result = NULL; |
+ err = SecItemCopyMatching(query, (CFTypeRef *)&result); |
Ryan Sleevi
2017/05/30 18:00:00
Note: Chromium explicitly uses C++ casts rather th
agaynor
2017/05/31 02:37:33
Done.
|
+ if (!err) { |
Ryan Sleevi
2017/05/30 18:00:01
In general, we try to handle the error case first,
|
+ for (CFIndex i = 0; i < CFArrayGetCount(result); i++) { |
+ CFTypeRef item = CFArrayGetValueAtIndex(result, i); |
+ AddIdentity(regular_certs, preferred_cert, preferred_identity, (SecIdentityRef)item); |
+ } |
+ } |
+ CFRelease(query); |
+ CFRelease(result); |
+ |
CertificateList selected_certs; |
GetClientCertsImpl(preferred_cert, regular_certs, request, true, |
&selected_certs); |
callback.Run(std::move(selected_certs)); |
} |
+void ClientCertStoreMac::AddIdentity( |
+ CertificateList& regular_certs, |
+ scoped_refptr<X509Certificate>& preferred_cert, |
+ SecIdentityRef preferred_identity, |
+ SecIdentityRef identity) { |
+ OSStatus err; |
+ SecCertificateRef cert_handle; |
Ryan Sleevi
2017/05/30 18:00:01
.InitializeInto :)
agaynor
2017/05/31 02:37:33
Done.
|
+ err = SecIdentityCopyCertificate(identity, &cert_handle); |
+ if (err != noErr) |
+ return; |
+ ScopedCFTypeRef<SecCertificateRef> scoped_cert_handle(cert_handle); |
+ |
+ 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); |
+ } |
+} |
+ |
bool ClientCertStoreMac::SelectClientCertsForTesting( |
const CertificateList& input_certs, |
const SSLCertRequestInfo& request, |