OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/base/x509_certificate.h" | 5 #include "net/base/x509_certificate.h" |
6 | 6 |
7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
8 #include <Security/Security.h> | 8 #include <Security/Security.h> |
9 #include <time.h> | 9 #include <time.h> |
10 | 10 |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 name_type == GNT_URI); | 215 name_type == GNT_URI); |
216 | 216 |
217 CSSMFields fields; | 217 CSSMFields fields; |
218 OSStatus status = GetCertFields(cert_handle, &fields); | 218 OSStatus status = GetCertFields(cert_handle, &fields); |
219 if (status) | 219 if (status) |
220 return; | 220 return; |
221 | 221 |
222 for (size_t field = 0; field < fields.num_of_fields; ++field) { | 222 for (size_t field = 0; field < fields.num_of_fields; ++field) { |
223 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { | 223 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { |
224 CSSM_X509_EXTENSION_PTR cssm_ext = | 224 CSSM_X509_EXTENSION_PTR cssm_ext = |
225 (CSSM_X509_EXTENSION_PTR)fields.fields[field].FieldValue.Data; | 225 reinterpret_cast<CSSM_X509_EXTENSION_PTR>( |
| 226 fields.fields[field].FieldValue.Data); |
226 CE_GeneralNames* alt_name = | 227 CE_GeneralNames* alt_name = |
227 (CE_GeneralNames*) cssm_ext->value.parsedValue; | 228 reinterpret_cast<CE_GeneralNames*>(cssm_ext->value.parsedValue); |
228 | 229 |
229 for (size_t name = 0; name < alt_name->numNames; ++name) { | 230 for (size_t name = 0; name < alt_name->numNames; ++name) { |
230 const CE_GeneralName& name_struct = alt_name->generalName[name]; | 231 const CE_GeneralName& name_struct = alt_name->generalName[name]; |
231 // All of the general name types we support are encoded as | 232 // All of the general name types we support are encoded as |
232 // IA5String. In general, we should be switching off | 233 // IA5String. In general, we should be switching off |
233 // |name_struct.nameType| and doing type-appropriate conversions. See | 234 // |name_struct.nameType| and doing type-appropriate conversions. See |
234 // certextensions.h and the comment immediately preceding | 235 // certextensions.h and the comment immediately preceding |
235 // CE_GeneralNameType for more information. | 236 // CE_GeneralNameType for more information. |
236 if (name_struct.nameType == name_type) { | 237 if (name_struct.nameType == name_type) { |
237 const CSSM_DATA& name_data = name_struct.name; | 238 const CSSM_DATA& name_data = name_struct.name; |
238 std::string value = | 239 std::string value = std::string( |
239 std::string(reinterpret_cast<std::string::value_type*> | 240 reinterpret_cast<const char*>(name_data.Data), |
240 (name_data.Data), | 241 name_data.Length); |
241 name_data.Length); | |
242 result->push_back(value); | 242 result->push_back(value); |
243 } | 243 } |
244 } | 244 } |
245 } | 245 } |
246 } | 246 } |
247 } | 247 } |
248 | 248 |
249 void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle, | 249 void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle, |
250 CSSM_OID oid, Time* result) { | 250 CSSM_OID oid, Time* result) { |
251 *result = Time::Time(); | 251 *result = Time::Time(); |
252 | 252 |
253 CSSMFields fields; | 253 CSSMFields fields; |
254 OSStatus status = GetCertFields(cert_handle, &fields); | 254 OSStatus status = GetCertFields(cert_handle, &fields); |
255 if (status) | 255 if (status) |
256 return; | 256 return; |
257 | 257 |
258 for (size_t field = 0; field < fields.num_of_fields; ++field) { | 258 for (size_t field = 0; field < fields.num_of_fields; ++field) { |
259 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { | 259 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { |
260 CSSM_X509_TIME* x509_time = | 260 CSSM_X509_TIME* x509_time = reinterpret_cast<CSSM_X509_TIME*>( |
261 reinterpret_cast<CSSM_X509_TIME *> | 261 fields.fields[field].FieldValue.Data); |
262 (fields.fields[field].FieldValue.Data); | 262 if (x509_time->timeType != BER_TAG_UTC_TIME && |
263 std::string time_string = | 263 x509_time->timeType != BER_TAG_GENERALIZED_TIME) { |
264 std::string(reinterpret_cast<std::string::value_type*> | 264 LOG(ERROR) << "Unsupported date/time format " |
265 (x509_time->time.Data), | 265 << x509_time->timeType; |
266 x509_time->time.Length); | |
267 | |
268 DCHECK(x509_time->timeType == BER_TAG_UTC_TIME || | |
269 x509_time->timeType == BER_TAG_GENERALIZED_TIME); | |
270 | |
271 struct tm time; | |
272 const char* parse_string; | |
273 if (x509_time->timeType == BER_TAG_UTC_TIME) | |
274 parse_string = "%y%m%d%H%M%SZ"; | |
275 else if (x509_time->timeType == BER_TAG_GENERALIZED_TIME) | |
276 parse_string = "%y%m%d%H%M%SZ"; | |
277 else { | |
278 // Those are the only two BER tags for time; if neither are used then | |
279 // this is a rather broken cert. | |
280 return; | 266 return; |
281 } | 267 } |
282 | 268 |
283 strptime(time_string.c_str(), parse_string, &time); | 269 base::StringPiece time_string( |
284 | 270 reinterpret_cast<const char*>(x509_time->time.Data), |
285 Time::Exploded exploded; | 271 x509_time->time.Length); |
286 exploded.year = time.tm_year + 1900; | 272 CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? |
287 exploded.month = time.tm_mon + 1; | 273 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; |
288 exploded.day_of_week = time.tm_wday; | 274 if (!ParseCertificateDate(time_string, format, result)) |
289 exploded.day_of_month = time.tm_mday; | 275 LOG(ERROR) << "Invalid certificate date/time " << time_string; |
290 exploded.hour = time.tm_hour; | 276 return; |
291 exploded.minute = time.tm_min; | |
292 exploded.second = time.tm_sec; | |
293 exploded.millisecond = 0; | |
294 | |
295 *result = Time::FromUTCExploded(exploded); | |
296 break; | |
297 } | 277 } |
298 } | 278 } |
299 } | 279 } |
300 | 280 |
301 // Creates a SecPolicyRef for the given OID, with optional value. | 281 // Creates a SecPolicyRef for the given OID, with optional value. |
302 OSStatus CreatePolicy(const CSSM_OID* policy_OID, | 282 OSStatus CreatePolicy(const CSSM_OID* policy_OID, |
303 void* option_data, | 283 void* option_data, |
304 size_t option_length, | 284 size_t option_length, |
305 SecPolicyRef* policy) { | 285 SecPolicyRef* policy) { |
306 SecPolicySearchRef search; | 286 SecPolicySearchRef search; |
(...skipping 20 matching lines...) Expand all Loading... |
327 return noErr; | 307 return noErr; |
328 } | 308 } |
329 | 309 |
330 // Gets the issuer for a given cert, starting with the cert itself and | 310 // Gets the issuer for a given cert, starting with the cert itself and |
331 // including the intermediate and finally root certificates (if any). | 311 // including the intermediate and finally root certificates (if any). |
332 // This function calls SecTrust but doesn't actually pay attention to the trust | 312 // This function calls SecTrust but doesn't actually pay attention to the trust |
333 // result: it shouldn't be used to determine trust, just to traverse the chain. | 313 // result: it shouldn't be used to determine trust, just to traverse the chain. |
334 // Caller is responsible for releasing the value stored into *out_cert_chain. | 314 // Caller is responsible for releasing the value stored into *out_cert_chain. |
335 OSStatus CopyCertChain(SecCertificateRef cert_handle, | 315 OSStatus CopyCertChain(SecCertificateRef cert_handle, |
336 CFArrayRef* out_cert_chain) { | 316 CFArrayRef* out_cert_chain) { |
337 DCHECK(cert_handle && out_cert_chain); | 317 DCHECK(cert_handle); |
| 318 DCHECK(out_cert_chain); |
338 // Create an SSL policy ref configured for client cert evaluation. | 319 // Create an SSL policy ref configured for client cert evaluation. |
339 SecPolicyRef ssl_policy; | 320 SecPolicyRef ssl_policy; |
340 OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy); | 321 OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy); |
341 if (result) | 322 if (result) |
342 return result; | 323 return result; |
343 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | 324 ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy); |
344 | 325 |
345 // Create a SecTrustRef. | 326 // Create a SecTrustRef. |
346 ScopedCFTypeRef<CFArrayRef> input_certs( | 327 ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate( |
347 CFArrayCreate(NULL, (const void**)&cert_handle, 1, | 328 NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)), |
348 &kCFTypeArrayCallBacks)); | 329 1, &kCFTypeArrayCallBacks)); |
349 SecTrustRef trust_ref = NULL; | 330 SecTrustRef trust_ref = NULL; |
350 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref); | 331 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref); |
351 if (result) | 332 if (result) |
352 return result; | 333 return result; |
353 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); | 334 ScopedCFTypeRef<SecTrustRef> trust(trust_ref); |
354 | 335 |
355 // Evaluate trust, which creates the cert chain. | 336 // Evaluate trust, which creates the cert chain. |
356 SecTrustResultType status; | 337 SecTrustResultType status; |
357 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | 338 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; |
358 result = SecTrustEvaluate(trust, &status); | 339 result = SecTrustEvaluate(trust, &status); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 } | 374 } |
394 | 375 |
395 // Parses |data| of length |length|, attempting to decode it as the specified | 376 // Parses |data| of length |length|, attempting to decode it as the specified |
396 // |format|. If |data| is in the specified format, any certificates contained | 377 // |format|. If |data| is in the specified format, any certificates contained |
397 // within are stored into |output|. | 378 // within are stored into |output|. |
398 void AddCertificatesFromBytes(const char* data, size_t length, | 379 void AddCertificatesFromBytes(const char* data, size_t length, |
399 SecExternalFormat format, | 380 SecExternalFormat format, |
400 X509Certificate::OSCertHandles* output) { | 381 X509Certificate::OSCertHandles* output) { |
401 SecExternalFormat input_format = format; | 382 SecExternalFormat input_format = format; |
402 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( | 383 ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( |
403 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), | 384 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length, |
404 length, kCFAllocatorNull)); | 385 kCFAllocatorNull)); |
405 | 386 |
406 CFArrayRef items = NULL; | 387 CFArrayRef items = NULL; |
407 OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format, | 388 OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format, |
408 NULL, 0, NULL, NULL, &items); | 389 NULL, 0, NULL, NULL, &items); |
409 if (status) { | 390 if (status) { |
410 DLOG(WARNING) << status << " Unable to import items from data of length " | 391 DLOG(WARNING) << status << " Unable to import items from data of length " |
411 << length; | 392 << length; |
412 return; | 393 return; |
413 } | 394 } |
414 | 395 |
(...skipping 30 matching lines...) Expand all Loading... |
445 | 426 |
446 } // namespace | 427 } // namespace |
447 | 428 |
448 void SetMacTestCertificate(X509Certificate* cert) { | 429 void SetMacTestCertificate(X509Certificate* cert) { |
449 g_mac_trusted_certificates.Get().SetTestCertificate(cert); | 430 g_mac_trusted_certificates.Get().SetTestCertificate(cert); |
450 } | 431 } |
451 | 432 |
452 void X509Certificate::Initialize() { | 433 void X509Certificate::Initialize() { |
453 const CSSM_X509_NAME* name; | 434 const CSSM_X509_NAME* name; |
454 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); | 435 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); |
455 if (!status) { | 436 if (!status) |
456 subject_.Parse(name); | 437 subject_.Parse(name); |
457 } | 438 |
458 status = SecCertificateGetIssuer(cert_handle_, &name); | 439 status = SecCertificateGetIssuer(cert_handle_, &name); |
459 if (!status) { | 440 if (!status) |
460 issuer_.Parse(name); | 441 issuer_.Parse(name); |
461 } | |
462 | 442 |
463 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, | 443 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, |
464 &valid_start_); | 444 &valid_start_); |
465 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, | 445 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, |
466 &valid_expiry_); | 446 &valid_expiry_); |
467 | 447 |
468 fingerprint_ = CalculateFingerprint(cert_handle_); | 448 fingerprint_ = CalculateFingerprint(cert_handle_); |
469 } | 449 } |
470 | 450 |
471 // static | 451 // static |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 632 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
653 for (uint32 status_code_index = 0; | 633 for (uint32 status_code_index = 0; |
654 status_code_index < chain_info[index].NumStatusCodes; | 634 status_code_index < chain_info[index].NumStatusCodes; |
655 ++status_code_index) { | 635 ++status_code_index) { |
656 got_certificate_error = true; | 636 got_certificate_error = true; |
657 int cert_status = CertStatusFromOSStatus( | 637 int cert_status = CertStatusFromOSStatus( |
658 chain_info[index].StatusCodes[status_code_index]); | 638 chain_info[index].StatusCodes[status_code_index]); |
659 if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) { | 639 if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) { |
660 std::vector<std::string> names; | 640 std::vector<std::string> names; |
661 GetDNSNames(&names); | 641 GetDNSNames(&names); |
662 if (OverrideHostnameMismatch(hostname, &names)) { | 642 if (OverrideHostnameMismatch(hostname, &names)) |
663 cert_status = 0; | 643 cert_status = 0; |
664 } | |
665 } | 644 } |
666 verify_result->cert_status |= cert_status; | 645 verify_result->cert_status |= cert_status; |
667 } | 646 } |
668 } | 647 } |
669 // Be paranoid and ensure that we recorded at least one certificate | 648 // Be paranoid and ensure that we recorded at least one certificate |
670 // status on receiving kSecTrustResultRecoverableTrustFailure. The | 649 // status on receiving kSecTrustResultRecoverableTrustFailure. The |
671 // call to SecTrustGetCssmResultCode() should pick up when the chain | 650 // call to SecTrustGetCssmResultCode() should pick up when the chain |
672 // is not trusted and the loop through CSSM_TP_APPLE_EVIDENCE_INFO | 651 // is not trusted and the loop through CSSM_TP_APPLE_EVIDENCE_INFO |
673 // should pick up everything else, but let's be safe. | 652 // should pick up everything else, but let's be safe. |
674 if (!verify_result->cert_status && !got_certificate_error) { | 653 if (!verify_result->cert_status && !got_certificate_error) { |
675 verify_result->cert_status |= CERT_STATUS_INVALID; | 654 verify_result->cert_status |= CERT_STATUS_INVALID; |
676 NOTREACHED(); | 655 NOTREACHED(); |
677 } | 656 } |
678 break; | 657 break; |
679 | 658 |
680 default: | 659 default: |
681 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); | 660 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); |
682 if (status) | 661 if (status) |
683 return NetErrorFromOSStatus(status); | 662 return NetErrorFromOSStatus(status); |
684 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); | 663 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); |
685 if (!verify_result->cert_status) { | 664 if (!verify_result->cert_status) |
686 verify_result->cert_status |= CERT_STATUS_INVALID; | 665 verify_result->cert_status |= CERT_STATUS_INVALID; |
687 } | |
688 break; | 666 break; |
689 } | 667 } |
690 | 668 |
691 // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be | 669 // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be |
692 // compatible with Windows, which in turn implements this behavior to be | 670 // compatible with Windows, which in turn implements this behavior to be |
693 // compatible with WinHTTP, which doesn't report this error (bug 3004). | 671 // compatible with WinHTTP, which doesn't report this error (bug 3004). |
694 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; | 672 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; |
695 | 673 |
696 if (IsCertStatusError(verify_result->cert_status)) | 674 if (IsCertStatusError(verify_result->cert_status)) |
697 return MapCertStatusToNetError(verify_result->cert_status); | 675 return MapCertStatusToNetError(verify_result->cert_status); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
811 SHA1Fingerprint X509Certificate::CalculateFingerprint( | 789 SHA1Fingerprint X509Certificate::CalculateFingerprint( |
812 OSCertHandle cert) { | 790 OSCertHandle cert) { |
813 SHA1Fingerprint sha1; | 791 SHA1Fingerprint sha1; |
814 memset(sha1.data, 0, sizeof(sha1.data)); | 792 memset(sha1.data, 0, sizeof(sha1.data)); |
815 | 793 |
816 CSSM_DATA cert_data; | 794 CSSM_DATA cert_data; |
817 OSStatus status = SecCertificateGetData(cert, &cert_data); | 795 OSStatus status = SecCertificateGetData(cert, &cert_data); |
818 if (status) | 796 if (status) |
819 return sha1; | 797 return sha1; |
820 | 798 |
821 DCHECK(NULL != cert_data.Data); | 799 DCHECK(cert_data.Data); |
822 DCHECK(0 != cert_data.Length); | 800 DCHECK_NE(cert_data.Length, 0U); |
823 | 801 |
824 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); | 802 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); |
825 | 803 |
826 return sha1; | 804 return sha1; |
827 } | 805 } |
828 | 806 |
829 bool X509Certificate::SupportsSSLClientAuth() const { | 807 bool X509Certificate::SupportsSSLClientAuth() const { |
830 CSSMFields fields; | 808 CSSMFields fields; |
831 if (GetCertFields(cert_handle_, &fields) != noErr) | 809 if (GetCertFields(cert_handle_, &fields) != noErr) |
832 return false; | 810 return false; |
(...skipping 30 matching lines...) Expand all Loading... |
863 return false; | 841 return false; |
864 return true; | 842 return true; |
865 } | 843 } |
866 | 844 |
867 bool X509Certificate::IsIssuedBy( | 845 bool X509Certificate::IsIssuedBy( |
868 const std::vector<CertPrincipal>& valid_issuers) { | 846 const std::vector<CertPrincipal>& valid_issuers) { |
869 // Get the cert's issuer chain. | 847 // Get the cert's issuer chain. |
870 CFArrayRef cert_chain = NULL; | 848 CFArrayRef cert_chain = NULL; |
871 OSStatus result; | 849 OSStatus result; |
872 result = CopyCertChain(os_cert_handle(), &cert_chain); | 850 result = CopyCertChain(os_cert_handle(), &cert_chain); |
873 if (result != noErr) | 851 if (result) |
874 return false; | 852 return false; |
875 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); | 853 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); |
876 | 854 |
877 // Check all the certs in the chain for a match. | 855 // Check all the certs in the chain for a match. |
878 int n = CFArrayGetCount(cert_chain); | 856 int n = CFArrayGetCount(cert_chain); |
879 for (int i = 0; i < n; ++i) { | 857 for (int i = 0; i < n; ++i) { |
880 SecCertificateRef cert_handle = reinterpret_cast<SecCertificateRef>( | 858 SecCertificateRef cert_handle = reinterpret_cast<SecCertificateRef>( |
881 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); | 859 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); |
882 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromHandle( | 860 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromHandle( |
883 cert_handle, | 861 cert_handle, |
(...skipping 15 matching lines...) Expand all Loading... |
899 NULL, | 877 NULL, |
900 CSSM_APPLE_TP_SSL_CLIENT | 878 CSSM_APPLE_TP_SSL_CLIENT |
901 }; | 879 }; |
902 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, | 880 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, |
903 &tp_ssl_options, | 881 &tp_ssl_options, |
904 sizeof(tp_ssl_options), | 882 sizeof(tp_ssl_options), |
905 out_policy); | 883 out_policy); |
906 } | 884 } |
907 | 885 |
908 // static | 886 // static |
909 bool X509Certificate::GetSSLClientCertificates ( | 887 bool X509Certificate::GetSSLClientCertificates( |
910 const std::string& server_domain, | 888 const std::string& server_domain, |
911 const std::vector<CertPrincipal>& valid_issuers, | 889 const std::vector<CertPrincipal>& valid_issuers, |
912 std::vector<scoped_refptr<X509Certificate> >* certs) { | 890 CertificateList* certs) { |
913 ScopedCFTypeRef<SecIdentityRef> preferred_identity; | 891 ScopedCFTypeRef<SecIdentityRef> preferred_identity; |
914 if (!server_domain.empty()) { | 892 if (!server_domain.empty()) { |
915 // See if there's an identity preference for this domain: | 893 // See if there's an identity preference for this domain: |
916 ScopedCFTypeRef<CFStringRef> domain_str( | 894 ScopedCFTypeRef<CFStringRef> domain_str( |
917 base::SysUTF8ToCFStringRef("https://" + server_domain)); | 895 base::SysUTF8ToCFStringRef("https://" + server_domain)); |
918 SecIdentityRef identity = NULL; | 896 SecIdentityRef identity = NULL; |
919 if (SecIdentityCopyPreference(domain_str, | 897 // While SecIdentityCopyPreferences appears to take a list of CA issuers |
920 0, | 898 // to restrict the identity search to, within Security.framework the |
921 NULL, // validIssuers argument is ignored :( | 899 // argument is ignored and filtering unimplemented. See |
922 &identity) == noErr) | 900 // SecIdentity.cpp in libsecurity_keychain, specifically |
| 901 // _SecIdentityCopyPreferenceMatchingName(). |
| 902 if (SecIdentityCopyPreference(domain_str, 0, NULL, &identity) == noErr) |
923 preferred_identity.reset(identity); | 903 preferred_identity.reset(identity); |
924 } | 904 } |
925 | 905 |
926 // Now enumerate the identities in the available keychains. | 906 // Now enumerate the identities in the available keychains. |
927 SecIdentitySearchRef search = nil; | 907 SecIdentitySearchRef search = nil; |
928 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); | 908 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); |
929 ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search); | 909 ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search); |
930 while (!err) { | 910 while (!err) { |
931 SecIdentityRef identity = NULL; | 911 SecIdentityRef identity = NULL; |
932 err = SecIdentitySearchCopyNext(search, &identity); | 912 err = SecIdentitySearchCopyNext(search, &identity); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
990 if (result) { | 970 if (result) { |
991 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; | 971 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; |
992 return NULL; | 972 return NULL; |
993 } | 973 } |
994 ScopedCFTypeRef<CFMutableArrayRef> chain( | 974 ScopedCFTypeRef<CFMutableArrayRef> chain( |
995 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 975 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); |
996 CFArrayAppendValue(chain, identity); | 976 CFArrayAppendValue(chain, identity); |
997 | 977 |
998 CFArrayRef cert_chain = NULL; | 978 CFArrayRef cert_chain = NULL; |
999 result = CopyCertChain(cert_handle_, &cert_chain); | 979 result = CopyCertChain(cert_handle_, &cert_chain); |
1000 if (result) | 980 if (result) { |
1001 goto exit; | 981 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; |
| 982 return chain.release(); |
| 983 } |
1002 | 984 |
1003 // Append the intermediate certs from SecTrust to the result array: | 985 // Append the intermediate certs from SecTrust to the result array: |
1004 if (cert_chain) { | 986 if (cert_chain) { |
1005 int chain_count = CFArrayGetCount(cert_chain); | 987 int chain_count = CFArrayGetCount(cert_chain); |
1006 if (chain_count > 1) { | 988 if (chain_count > 1) { |
1007 CFArrayAppendArray(chain, | 989 CFArrayAppendArray(chain, |
1008 cert_chain, | 990 cert_chain, |
1009 CFRangeMake(1, chain_count - 1)); | 991 CFRangeMake(1, chain_count - 1)); |
1010 } | 992 } |
1011 CFRelease(cert_chain); | 993 CFRelease(cert_chain); |
1012 } | 994 } |
1013 exit: | 995 |
1014 if (result) | |
1015 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; | |
1016 return chain.release(); | 996 return chain.release(); |
1017 } | 997 } |
1018 | 998 |
1019 } // namespace net | 999 } // namespace net |
OLD | NEW |