| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/client_cert_store_mac.h" | 5 #include "net/ssl/client_cert_store_mac.h" |
| 6 | 6 |
| 7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
| 8 #include <CoreFoundation/CFArray.h> | 8 #include <CoreFoundation/CFArray.h> |
| 9 #include <CoreServices/CoreServices.h> | 9 #include <CoreServices/CoreServices.h> |
| 10 #include <Security/SecBase.h> | 10 #include <Security/SecBase.h> |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 | 42 |
| 43 // Create an SSL policy ref configured for client cert evaluation. | 43 // Create an SSL policy ref configured for client cert evaluation. |
| 44 SecPolicyRef ssl_policy; | 44 SecPolicyRef ssl_policy; |
| 45 OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy); | 45 OSStatus result = x509_util::CreateSSLClientPolicy(&ssl_policy); |
| 46 if (result) | 46 if (result) |
| 47 return result; | 47 return result; |
| 48 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | 48 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); |
| 49 | 49 |
| 50 // Create a SecTrustRef. | 50 // Create a SecTrustRef. |
| 51 ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( | 51 ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( |
| 52 NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), | 52 NULL, |
| 53 1, &kCFTypeArrayCallBacks)); | 53 const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), |
| 54 1, |
| 55 &kCFTypeArrayCallBacks)); |
| 54 SecTrustRef trust_ref = NULL; | 56 SecTrustRef trust_ref = NULL; |
| 55 { | 57 { |
| 56 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | 58 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
| 57 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, | 59 result = |
| 58 &trust_ref); | 60 SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref); |
| 59 } | 61 } |
| 60 if (result) | 62 if (result) |
| 61 return result; | 63 return result; |
| 62 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); | 64 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); |
| 63 | 65 |
| 64 // Evaluate trust, which creates the cert chain. | 66 // Evaluate trust, which creates the cert chain. |
| 65 SecTrustResultType status; | 67 SecTrustResultType status; |
| 66 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | 68 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; |
| 67 { | 69 { |
| 68 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | 70 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 92 if (result) { | 94 if (result) { |
| 93 OSSTATUS_LOG(ERROR, result) << "CopyCertChain error"; | 95 OSSTATUS_LOG(ERROR, result) << "CopyCertChain error"; |
| 94 return false; | 96 return false; |
| 95 } | 97 } |
| 96 | 98 |
| 97 if (!cert_chain) | 99 if (!cert_chain) |
| 98 return false; | 100 return false; |
| 99 | 101 |
| 100 X509Certificate::OSCertHandles intermediates; | 102 X509Certificate::OSCertHandles intermediates; |
| 101 for (CFIndex i = 1, chain_count = CFArrayGetCount(cert_chain); | 103 for (CFIndex i = 1, chain_count = CFArrayGetCount(cert_chain); |
| 102 i < chain_count; ++i) { | 104 i < chain_count; |
| 105 ++i) { |
| 103 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( | 106 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( |
| 104 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); | 107 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); |
| 105 intermediates.push_back(cert); | 108 intermediates.push_back(cert); |
| 106 } | 109 } |
| 107 | 110 |
| 108 scoped_refptr<X509Certificate> new_cert(X509Certificate::CreateFromHandle( | 111 scoped_refptr<X509Certificate> new_cert( |
| 109 cert_handle, intermediates)); | 112 X509Certificate::CreateFromHandle(cert_handle, intermediates)); |
| 110 CFRelease(cert_chain); // Also frees |intermediates|. | 113 CFRelease(cert_chain); // Also frees |intermediates|. |
| 111 | 114 |
| 112 if (!new_cert->IsIssuedByEncoded(valid_issuers)) | 115 if (!new_cert->IsIssuedByEncoded(valid_issuers)) |
| 113 return false; | 116 return false; |
| 114 | 117 |
| 115 cert->swap(new_cert); | 118 cert->swap(new_cert); |
| 116 return true; | 119 return true; |
| 117 } | 120 } |
| 118 | 121 |
| 119 // Examines the certificates in |preferred_cert| and |regular_certs| to find | 122 // Examines the certificates in |preferred_cert| and |regular_certs| to find |
| 120 // all certificates that match the client certificate request in |request|, | 123 // all certificates that match the client certificate request in |request|, |
| 121 // storing the matching certificates in |selected_certs|. | 124 // storing the matching certificates in |selected_certs|. |
| 122 // If |query_keychain| is true, Keychain Services will be queried to construct | 125 // If |query_keychain| is true, Keychain Services will be queried to construct |
| 123 // full certificate chains. If it is false, only the the certificates and their | 126 // full certificate chains. If it is false, only the the certificates and their |
| 124 // intermediates (available via X509Certificate::GetIntermediateCertificates()) | 127 // intermediates (available via X509Certificate::GetIntermediateCertificates()) |
| 125 // will be considered. | 128 // will be considered. |
| 126 void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, | 129 void GetClientCertsImpl(const scoped_refptr<X509Certificate>& preferred_cert, |
| 127 const CertificateList& regular_certs, | 130 const CertificateList& regular_certs, |
| 128 const SSLCertRequestInfo& request, | 131 const SSLCertRequestInfo& request, |
| 129 bool query_keychain, | 132 bool query_keychain, |
| 130 CertificateList* selected_certs) { | 133 CertificateList* selected_certs) { |
| 131 CertificateList preliminary_list; | 134 CertificateList preliminary_list; |
| 132 if (preferred_cert.get()) | 135 if (preferred_cert.get()) |
| 133 preliminary_list.push_back(preferred_cert); | 136 preliminary_list.push_back(preferred_cert); |
| 134 preliminary_list.insert(preliminary_list.end(), regular_certs.begin(), | 137 preliminary_list.insert( |
| 135 regular_certs.end()); | 138 preliminary_list.end(), regular_certs.begin(), regular_certs.end()); |
| 136 | 139 |
| 137 selected_certs->clear(); | 140 selected_certs->clear(); |
| 138 for (size_t i = 0; i < preliminary_list.size(); ++i) { | 141 for (size_t i = 0; i < preliminary_list.size(); ++i) { |
| 139 scoped_refptr<X509Certificate>& cert = preliminary_list[i]; | 142 scoped_refptr<X509Certificate>& cert = preliminary_list[i]; |
| 140 if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) | 143 if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) |
| 141 continue; | 144 continue; |
| 142 | 145 |
| 143 // Skip duplicates (a cert may be in multiple keychains). | 146 // Skip duplicates (a cert may be in multiple keychains). |
| 144 const SHA1HashValue& fingerprint = cert->fingerprint(); | 147 const SHA1HashValue& fingerprint = cert->fingerprint(); |
| 145 size_t pos; | 148 size_t pos; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 165 CertificateList::iterator sort_end = selected_certs->end(); | 168 CertificateList::iterator sort_end = selected_certs->end(); |
| 166 if (preferred_cert.get() && sort_begin != sort_end && | 169 if (preferred_cert.get() && sort_begin != sort_end && |
| 167 sort_begin->get() == preferred_cert.get()) { | 170 sort_begin->get() == preferred_cert.get()) { |
| 168 ++sort_begin; | 171 ++sort_begin; |
| 169 } | 172 } |
| 170 sort(sort_begin, sort_end, x509_util::ClientCertSorter()); | 173 sort(sort_begin, sort_end, x509_util::ClientCertSorter()); |
| 171 } | 174 } |
| 172 | 175 |
| 173 } // namespace | 176 } // namespace |
| 174 | 177 |
| 175 ClientCertStoreMac::ClientCertStoreMac() {} | 178 ClientCertStoreMac::ClientCertStoreMac() { |
| 179 } |
| 176 | 180 |
| 177 ClientCertStoreMac::~ClientCertStoreMac() {} | 181 ClientCertStoreMac::~ClientCertStoreMac() { |
| 182 } |
| 178 | 183 |
| 179 void ClientCertStoreMac::GetClientCerts(const SSLCertRequestInfo& request, | 184 void ClientCertStoreMac::GetClientCerts(const SSLCertRequestInfo& request, |
| 180 CertificateList* selected_certs, | 185 CertificateList* selected_certs, |
| 181 const base::Closure& callback) { | 186 const base::Closure& callback) { |
| 182 std::string server_domain = request.host_and_port.host(); | 187 std::string server_domain = request.host_and_port.host(); |
| 183 | 188 |
| 184 ScopedCFTypeRef<SecIdentityRef> preferred_identity; | 189 ScopedCFTypeRef<SecIdentityRef> preferred_identity; |
| 185 if (!server_domain.empty()) { | 190 if (!server_domain.empty()) { |
| 186 // See if there's an identity preference for this domain: | 191 // See if there's an identity preference for this domain: |
| 187 ScopedCFTypeRef<CFStringRef> domain_str( | 192 ScopedCFTypeRef<CFStringRef> domain_str( |
| 188 base::SysUTF8ToCFStringRef("https://" + server_domain)); | 193 base::SysUTF8ToCFStringRef("https://" + server_domain)); |
| 189 SecIdentityRef identity = NULL; | 194 SecIdentityRef identity = NULL; |
| 190 // While SecIdentityCopyPreferences appears to take a list of CA issuers | 195 // While SecIdentityCopyPreferences appears to take a list of CA issuers |
| 191 // to restrict the identity search to, within Security.framework the | 196 // to restrict the identity search to, within Security.framework the |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 if (err) | 229 if (err) |
| 225 break; | 230 break; |
| 226 ScopedCFTypeRef<SecIdentityRef> scoped_identity(identity); | 231 ScopedCFTypeRef<SecIdentityRef> scoped_identity(identity); |
| 227 | 232 |
| 228 SecCertificateRef cert_handle; | 233 SecCertificateRef cert_handle; |
| 229 err = SecIdentityCopyCertificate(identity, &cert_handle); | 234 err = SecIdentityCopyCertificate(identity, &cert_handle); |
| 230 if (err != noErr) | 235 if (err != noErr) |
| 231 continue; | 236 continue; |
| 232 ScopedCFTypeRef<SecCertificateRef> scoped_cert_handle(cert_handle); | 237 ScopedCFTypeRef<SecCertificateRef> scoped_cert_handle(cert_handle); |
| 233 | 238 |
| 234 scoped_refptr<X509Certificate> cert( | 239 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromHandle( |
| 235 X509Certificate::CreateFromHandle(cert_handle, | 240 cert_handle, X509Certificate::OSCertHandles())); |
| 236 X509Certificate::OSCertHandles())); | |
| 237 | 241 |
| 238 if (preferred_identity && CFEqual(preferred_identity, identity)) { | 242 if (preferred_identity && CFEqual(preferred_identity, identity)) { |
| 239 // Only one certificate should match. | 243 // Only one certificate should match. |
| 240 DCHECK(!preferred_cert.get()); | 244 DCHECK(!preferred_cert.get()); |
| 241 preferred_cert = cert; | 245 preferred_cert = cert; |
| 242 } else { | 246 } else { |
| 243 regular_certs.push_back(cert); | 247 regular_certs.push_back(cert); |
| 244 } | 248 } |
| 245 } | 249 } |
| 246 | 250 |
| 247 if (err != errSecItemNotFound) { | 251 if (err != errSecItemNotFound) { |
| 248 OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error"; | 252 OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error"; |
| 249 selected_certs->clear(); | 253 selected_certs->clear(); |
| 250 callback.Run(); | 254 callback.Run(); |
| 251 return; | 255 return; |
| 252 } | 256 } |
| 253 | 257 |
| 254 GetClientCertsImpl(preferred_cert, regular_certs, request, true, | 258 GetClientCertsImpl( |
| 255 selected_certs); | 259 preferred_cert, regular_certs, request, true, selected_certs); |
| 256 callback.Run(); | 260 callback.Run(); |
| 257 } | 261 } |
| 258 | 262 |
| 259 bool ClientCertStoreMac::SelectClientCertsForTesting( | 263 bool ClientCertStoreMac::SelectClientCertsForTesting( |
| 260 const CertificateList& input_certs, | 264 const CertificateList& input_certs, |
| 261 const SSLCertRequestInfo& request, | 265 const SSLCertRequestInfo& request, |
| 262 CertificateList* selected_certs) { | 266 CertificateList* selected_certs) { |
| 263 GetClientCertsImpl(NULL, input_certs, request, false, selected_certs); | 267 GetClientCertsImpl(NULL, input_certs, request, false, selected_certs); |
| 264 return true; | 268 return true; |
| 265 } | 269 } |
| 266 | 270 |
| 267 bool ClientCertStoreMac::SelectClientCertsGivenPreferredForTesting( | 271 bool ClientCertStoreMac::SelectClientCertsGivenPreferredForTesting( |
| 268 const scoped_refptr<X509Certificate>& preferred_cert, | 272 const scoped_refptr<X509Certificate>& preferred_cert, |
| 269 const CertificateList& regular_certs, | 273 const CertificateList& regular_certs, |
| 270 const SSLCertRequestInfo& request, | 274 const SSLCertRequestInfo& request, |
| 271 CertificateList* selected_certs) { | 275 CertificateList* selected_certs) { |
| 272 GetClientCertsImpl( | 276 GetClientCertsImpl( |
| 273 preferred_cert, regular_certs, request, false, selected_certs); | 277 preferred_cert, regular_certs, request, false, selected_certs); |
| 274 return true; | 278 return true; |
| 275 } | 279 } |
| 276 | 280 |
| 277 } // namespace net | 281 } // namespace net |
| OLD | NEW |