1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/ssl/client_cert_store_mac.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <CommonCrypto/CommonDigest.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <CoreFoundation/CFArray.h> 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <CoreServices/CoreServices.h> 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <Security/SecBase.h> 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <Security/Security.h> 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm> 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string> 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/callback.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/mac/mac_logging.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/mac/scoped_cftyperef.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/synchronization/lock.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/mac_security_services_lock.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/host_port_pair.h" 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util.h" 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util_mac.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::ScopedCFTypeRef; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace net { 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Gets the issuer for a given cert, starting with the cert itself and 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// including the intermediate and finally root certificates (if any). 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This function calls SecTrust but doesn't actually pay attention to the trust 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// result: it shouldn't be used to determine trust, just to traverse the chain. 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Caller is responsible for releasing the value stored into *out_cert_chain. 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)OSStatus CopyCertChain(SecCertificateRef cert_handle, 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CFArrayRef* out_cert_chain) { 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(cert_handle); 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(out_cert_chain); 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create an SSL policy ref configured for client cert evaluation. 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SecPolicyRef ssl_policy; 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy); 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (result) 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return result; 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create a SecTrustRef. 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1, &kCFTypeArrayCallBacks)); 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SecTrustRef trust_ref = NULL; 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result = SecTrustCreateWithCertificates(input_certs, ssl_policy, 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &trust_ref); 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (result) 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return result; 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ScopedCFTypeRef<SecTrustRef> trust(trust_ref); 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Evaluate trust, which creates the cert chain. 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SecTrustResultType status; 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result = SecTrustEvaluate(trust, &status); 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (result) 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return result; 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) { 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) result = SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return result; 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true if |*cert| is issued by an authority in |valid_issuers| 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// according to Keychain Services, rather than using |cert|'s intermediate 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// certificates. If it is, |*cert| is updated to point to the completed 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// certificate 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool IsIssuedByInKeychain(const std::vector<std::string>& valid_issuers, 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_refptr<X509Certificate>* cert) { 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(cert); 877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(cert->get()); 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) X509Certificate::OSCertHandle cert_handle = (*cert)->os_cert_handle(); 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CFArrayRef cert_chain = NULL; 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OSStatus result = CopyCertChain(cert_handle, &cert_chain); 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (result) { 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) OSSTATUS_LOG(ERROR, result) << "CopyCertChain error"; 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!cert_chain) 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) X509Certificate::OSCertHandles intermediates; 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (CFIndex i = 1, chain_count = CFArrayGetCount(cert_chain); 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) i < chain_count; ++i) { 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) intermediates.push_back(cert); 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_refptr<X509Certificate> new_cert(X509Certificate::CreateFromHandle( 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cert_handle, intermediates)); 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CFRelease(cert_chain); // Also frees |intermediates|. 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!new_cert->IsIssuedByEncoded(valid_issuers)) 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cert->swap(new_cert); 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Examines the certificates in |preferred_cert| and |regular_certs| to find 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// all certificates that match the client certificate request in |request|, 121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// storing the matching certificates in |selected_certs|. 122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// If |query_keychain| is true, Keychain Services will be queried to construct 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// full certificate chains. If it is false, only the the certificates and their 124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// intermediates (available via X509Certificate::GetIntermediateCertificates()) 125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// will be considered. 1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CertificateList& regular_certs, 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SSLCertRequestInfo& request, 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool query_keychain, 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CertificateList* selected_certs) { 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CertificateList preliminary_list; 1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (preferred_cert.get()) 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) preliminary_list.push_back(preferred_cert); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) preliminary_list.insert(preliminary_list.end(), regular_certs.begin(), 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) regular_certs.end()); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) selected_certs->clear(); 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < preliminary_list.size(); ++i) { 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<X509Certificate>& cert = preliminary_list[i]; 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Skip duplicates (a cert may be in multiple keychains). 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SHA1HashValue& fingerprint = cert->fingerprint(); 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t pos; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (pos = 0; pos < selected_certs->size(); ++pos) { 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((*selected_certs)[pos]->fingerprint().Equals(fingerprint)) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (pos < selected_certs->size()) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check if the certificate issuer is allowed by the server. 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (request.cert_authorities.empty() || 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cert->IsIssuedByEncoded(request.cert_authorities) || 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (query_keychain && 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) IsIssuedByInKeychain(request.cert_authorities, &cert))) { 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selected_certs->push_back(cert); 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Preferred cert should appear first in the ui, so exclude it from the 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // sorting. 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CertificateList::iterator sort_begin = selected_certs->begin(); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CertificateList::iterator sort_end = selected_certs->end(); 1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (preferred_cert.get() && sort_begin != sort_end && 1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) sort_begin->get() == preferred_cert.get()) { 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++sort_begin; 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sort(sort_begin, sort_end, x509_util::ClientCertSorter()); 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ClientCertStoreMac::ClientCertStoreMac() {} 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ClientCertStoreMac::~ClientCertStoreMac() {} 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ClientCertStoreMac::GetClientCerts(const SSLCertRequestInfo& request, 1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CertificateList* selected_certs, 1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const base::Closure& callback) { 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string server_domain = request.host_and_port.host(); 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedCFTypeRef<SecIdentityRef> preferred_identity; 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!server_domain.empty()) { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // See if there's an identity preference for this domain: 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedCFTypeRef<CFStringRef> domain_str( 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::SysUTF8ToCFStringRef("https://" + server_domain)); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SecIdentityRef identity = NULL; 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // While SecIdentityCopyPreferences appears to take a list of CA issuers 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // to restrict the identity search to, within Security.framework the 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // argument is ignored and filtering unimplemented. See 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // SecIdentity.cpp in libsecurity_keychain, specifically 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // _SecIdentityCopyPreferenceMatchingName(). 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (SecIdentityCopyPreference(domain_str, 0, NULL, &identity) == noErr) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) preferred_identity.reset(identity); 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Now enumerate the identities in the available keychains. 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<X509Certificate> preferred_cert = NULL; 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CertificateList regular_certs; 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SecIdentitySearchRef search = NULL; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OSStatus err; 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (err) { 2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) selected_certs->clear(); 2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) callback.Run(); 2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (!err) { 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SecIdentityRef identity = NULL; 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) { 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) err = SecIdentitySearchCopyNext(search, &identity); 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (err) 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedCFTypeRef<SecIdentityRef> scoped_identity(identity); 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SecCertificateRef cert_handle; 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) err = SecIdentityCopyCertificate(identity, &cert_handle); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (err != noErr) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedCFTypeRef<SecCertificateRef> scoped_cert_handle(cert_handle); 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<X509Certificate> cert( 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) X509Certificate::CreateFromHandle(cert_handle, 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) X509Certificate::OSCertHandles())); 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (preferred_identity && CFEqual(preferred_identity, identity)) { 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Only one certificate should match. 2407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(!preferred_cert.get()); 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) preferred_cert = cert; 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) regular_certs.push_back(cert); 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (err != errSecItemNotFound) { 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error"; 2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) selected_certs->clear(); 2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) callback.Run(); 2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) GetClientCertsImpl(preferred_cert, regular_certs, request, true, 2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) selected_certs); 2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) callback.Run(); 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ClientCertStoreMac::SelectClientCertsForTesting( 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const CertificateList& input_certs, 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SSLCertRequestInfo& request, 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CertificateList* selected_certs) { 2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) GetClientCertsImpl(NULL, input_certs, request, false, selected_certs); 2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return true; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ClientCertStoreMac::SelectClientCertsGivenPreferredForTesting( 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const scoped_refptr<X509Certificate>& preferred_cert, 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const CertificateList& regular_certs, 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const SSLCertRequestInfo& request, 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CertificateList* selected_certs) { 2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) GetClientCertsImpl( 2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) preferred_cert, regular_certs, request, false, selected_certs); 2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return true; 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace net 278