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 |
| 11 #include "base/file_path.h" |
| 12 #include "base/file_util.h" |
11 #include "base/scoped_cftyperef.h" | 13 #include "base/scoped_cftyperef.h" |
12 #include "base/logging.h" | 14 #include "base/logging.h" |
13 #include "base/pickle.h" | 15 #include "base/pickle.h" |
14 #include "base/sys_string_conversions.h" | 16 #include "base/sys_string_conversions.h" |
15 #include "net/base/cert_status_flags.h" | 17 #include "net/base/cert_status_flags.h" |
16 #include "net/base/cert_verify_result.h" | 18 #include "net/base/cert_verify_result.h" |
17 #include "net/base/net_errors.h" | 19 #include "net/base/net_errors.h" |
18 | 20 |
19 using base::Time; | 21 using base::Time; |
20 | 22 |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 | 353 |
352 // Evaluate trust, which creates the cert chain. | 354 // Evaluate trust, which creates the cert chain. |
353 SecTrustResultType status; | 355 SecTrustResultType status; |
354 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | 356 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; |
355 result = SecTrustEvaluate(trust, &status); | 357 result = SecTrustEvaluate(trust, &status); |
356 if (result) | 358 if (result) |
357 return result; | 359 return result; |
358 return SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); | 360 return SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); |
359 } | 361 } |
360 | 362 |
| 363 void AddCertificatesFromData(const char* data, size_t length, |
| 364 SecExternalFormat format, |
| 365 X509Certificate::OSCertHandles* output) { |
| 366 // In order to use SecKeychainItemImport successfully, a destination |
| 367 // keychain must be specified to receive the created objects. Further, |
| 368 // the created objects remain valid only for as long as the keychain does. |
| 369 // In order to match the handling on Windows/NSS, which has the handles |
| 370 // valid for an arbitrary length of time, a temporary keychain is created, |
| 371 // the certificates are imported into it, and then free-standing |
| 372 // certificates are created from the DER representation of the original |
| 373 // keychain item. |
| 374 FilePath temp_file; |
| 375 if (!file_util::CreateTemporaryFile(&temp_file)) |
| 376 return; |
| 377 |
| 378 SecExternalFormat input_format = format; |
| 379 scoped_cftyperef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy( |
| 380 kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), |
| 381 length, kCFAllocatorDefault); |
| 382 |
| 383 scoped_cftyperef<SecKeychainRef> temp_keychain; |
| 384 SecKeychainRef keychain = NULL; |
| 385 OSStatus rv = SecKeychainCreate(temp_file.value().c_str(), 0, NULL, FALSE, |
| 386 NULL, &keychain); |
| 387 if (rv != noErr) { |
| 388 DLOG(WARNING) << rv << " Unable to create temporary keychain at " |
| 389 << temp_file.value(); |
| 390 return; |
| 391 } |
| 392 |
| 393 temp_keychain.reset(keychain); |
| 394 keychain = NULL; |
| 395 |
| 396 CFArrayRef items = NULL; |
| 397 rv = SecKeychainItemImport(local_data, NULL, &input_format, NULL, |
| 398 0, NULL, NULL, temp_keychain, &items); |
| 399 if (rv != noErr) { |
| 400 scoped_cftyperef<CFArrayRef> scoped_items(items); |
| 401 CFTypeID certTypeID = SecCertificateGetTypeID(); |
| 402 |
| 403 for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) { |
| 404 SecKeychainItemRef item = CFArrayGetValueAtIndex(items, i); |
| 405 |
| 406 // While inputFormat implies only certificates will be imported, if/when |
| 407 // other formats (eg: PKCS#12) are supported, this may also include |
| 408 // private keys or other items types, so filter appropriately. |
| 409 if (CFGetTypeID(item) == certTypeID) { |
| 410 // Create a freestanding SecCertificateRef from the keychain item. |
| 411 // Unfortunately, this invokes a double-parse of the DER data, which |
| 412 // is less than optimally efficient. |
| 413 scoped_cftyperef<CFDataRef> scoped_cert_data = |
| 414 SecCertificateCopyData(reinterpret_cast<SecCertificateRef>(item)); |
| 415 if (scoped_cert_data == NULL) |
| 416 continue; |
| 417 |
| 418 SecCertificateRef cert = SecCertificateCreateWithData(NULL, |
| 419 scoped_cert_data); |
| 420 if (cert == NULL) |
| 421 continue; |
| 422 |
| 423 output->push_back(cert); |
| 424 } |
| 425 } else { |
| 426 DLOG(WARNING) << rv << " Unable to import items from data of length " |
| 427 << length; |
| 428 } |
| 429 |
| 430 rv = SecKeychainDelete(temp_keychain); |
| 431 if (rv != noErr) { |
| 432 DLOG(WARNING) << rv << " Unable to remove temporary keychain at " |
| 433 << temp_file.value(); |
| 434 } |
| 435 } |
| 436 |
361 } // namespace | 437 } // namespace |
362 | 438 |
363 void X509Certificate::Initialize() { | 439 void X509Certificate::Initialize() { |
364 const CSSM_X509_NAME* name; | 440 const CSSM_X509_NAME* name; |
365 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); | 441 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); |
366 if (!status) { | 442 if (!status) { |
367 subject_.Parse(name); | 443 subject_.Parse(name); |
368 } | 444 } |
369 status = SecCertificateGetIssuer(cert_handle_, &name); | 445 status = SecCertificateGetIssuer(cert_handle_, &name); |
370 if (!status) { | 446 if (!status) { |
371 issuer_.Parse(name); | 447 issuer_.Parse(name); |
372 } | 448 } |
373 | 449 |
374 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, | 450 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, |
375 &valid_start_); | 451 &valid_start_); |
376 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, | 452 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, |
377 &valid_expiry_); | 453 &valid_expiry_); |
378 | 454 |
379 fingerprint_ = CalculateFingerprint(cert_handle_); | 455 fingerprint_ = CalculateFingerprint(cert_handle_); |
380 } | 456 } |
381 | 457 |
382 // static | 458 // static |
383 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, | 459 X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, |
384 void** pickle_iter) { | 460 void** pickle_iter) { |
385 const char* data; | 461 const char* data; |
386 int length; | 462 int length; |
387 if (!pickle.ReadData(pickle_iter, &data, &length)) | 463 if (!pickle.ReadData(pickle_iter, &data, &length)) |
388 return NULL; | 464 return NULL; |
389 | 465 |
390 return CreateFromBytes(data, length); | 466 return CreateFromBytes(data, length, X509Certificate::FORMAT_DER); |
391 } | 467 } |
392 | 468 |
393 void X509Certificate::Persist(Pickle* pickle) { | 469 void X509Certificate::Persist(Pickle* pickle) { |
394 CSSM_DATA cert_data; | 470 CSSM_DATA cert_data; |
395 OSStatus status = SecCertificateGetData(cert_handle_, &cert_data); | 471 OSStatus status = SecCertificateGetData(cert_handle_, &cert_data); |
396 if (status) { | 472 if (status) { |
397 NOTREACHED(); | 473 NOTREACHED(); |
398 return; | 474 return; |
399 } | 475 } |
400 | 476 |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 bool X509Certificate::VerifyEV() const { | 716 bool X509Certificate::VerifyEV() const { |
641 // We don't call this private method, but we do need to implement it because | 717 // We don't call this private method, but we do need to implement it because |
642 // it's defined in x509_certificate.h. We perform EV checking in the | 718 // it's defined in x509_certificate.h. We perform EV checking in the |
643 // Verify() above. | 719 // Verify() above. |
644 NOTREACHED(); | 720 NOTREACHED(); |
645 return false; | 721 return false; |
646 } | 722 } |
647 | 723 |
648 // static | 724 // static |
649 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | 725 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( |
650 const char* data, int length) { | 726 const char* data, size_t length) { |
651 CSSM_DATA cert_data; | 727 CSSM_DATA cert_data; |
652 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); | 728 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); |
653 cert_data.Length = length; | 729 cert_data.Length = length; |
654 | 730 |
655 OSCertHandle cert_handle = NULL; | 731 OSCertHandle cert_handle = NULL; |
656 OSStatus status = SecCertificateCreateFromData(&cert_data, | 732 OSStatus status = SecCertificateCreateFromData(&cert_data, |
657 CSSM_CERT_X_509v3, | 733 CSSM_CERT_X_509v3, |
658 CSSM_CERT_ENCODING_BER, | 734 CSSM_CERT_ENCODING_BER, |
659 &cert_handle); | 735 &cert_handle); |
660 if (status) | 736 if (status) |
661 return NULL; | 737 return NULL; |
662 | 738 |
663 return cert_handle; | 739 return cert_handle; |
664 } | 740 } |
665 | 741 |
666 // static | 742 // static |
| 743 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( |
| 744 const char* data, size_t length, CertificateFormat format) { |
| 745 OSCertHandles results; |
| 746 |
| 747 switch (format) { |
| 748 case FORMAT_DER: |
| 749 { |
| 750 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length); |
| 751 if (handle) |
| 752 results.push_back(handle); |
| 753 } |
| 754 break; |
| 755 case FORMAT_PKCS7: |
| 756 AddCertificatesFromData(data, length, kSecFormatPKCS7, &results); |
| 757 break; |
| 758 case FORMAT_LEGACY_NETSCAPE: |
| 759 AddCertificatesFromData(data, length, kSecFormatNetscapeCertSequence, |
| 760 &results); |
| 761 break; |
| 762 default: |
| 763 NOTREACHED() << "Certificate format " << format << " unimplemented"; |
| 764 break; |
| 765 } |
| 766 |
| 767 return results; |
| 768 } |
| 769 |
| 770 // static |
667 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | 771 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( |
668 OSCertHandle handle) { | 772 OSCertHandle handle) { |
669 if (!handle) | 773 if (!handle) |
670 return NULL; | 774 return NULL; |
671 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); | 775 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); |
672 } | 776 } |
673 | 777 |
674 // static | 778 // static |
675 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | 779 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { |
676 CFRelease(cert_handle); | 780 CFRelease(cert_handle); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 NULL, | 860 NULL, |
757 CSSM_APPLE_TP_SSL_CLIENT | 861 CSSM_APPLE_TP_SSL_CLIENT |
758 }; | 862 }; |
759 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, | 863 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, |
760 &tp_ssl_options, | 864 &tp_ssl_options, |
761 sizeof(tp_ssl_options), | 865 sizeof(tp_ssl_options), |
762 out_policy); | 866 out_policy); |
763 } | 867 } |
764 | 868 |
765 // static | 869 // static |
766 bool X509Certificate::GetSSLClientCertificates ( | 870 bool X509Certificate::GetSSLClientCertificates( |
767 const std::string& server_domain, | 871 const std::string& server_domain, |
768 const std::vector<Principal>& valid_issuers, | 872 const std::vector<Principal>& valid_issuers, |
769 std::vector<scoped_refptr<X509Certificate> >* certs) { | 873 std::vector<scoped_refptr<X509Certificate> >* certs) { |
770 scoped_cftyperef<SecIdentityRef> preferred_identity; | 874 scoped_cftyperef<SecIdentityRef> preferred_identity; |
771 if (!server_domain.empty()) { | 875 if (!server_domain.empty()) { |
772 // See if there's an identity preference for this domain: | 876 // See if there's an identity preference for this domain: |
773 scoped_cftyperef<CFStringRef> domain_str( | 877 scoped_cftyperef<CFStringRef> domain_str( |
774 base::SysUTF8ToCFStringRef("https://" + server_domain)); | 878 base::SysUTF8ToCFStringRef("https://" + server_domain)); |
775 SecIdentityRef identity = NULL; | 879 SecIdentityRef identity = NULL; |
776 if (SecIdentityCopyPreference(domain_str, | 880 if (SecIdentityCopyPreference(domain_str, |
777 0, | 881 0, |
778 NULL, // validIssuers argument is ignored :( | 882 NULL, // validIssuers argument is ignored :( |
779 &identity) == noErr) | 883 &identity) == noErr) |
780 preferred_identity.reset(identity); | 884 preferred_identity.reset(identity); |
781 } | 885 } |
782 | 886 |
783 // Now enumerate the identities in the available keychains. | 887 // Now enumerate the identities in the available keychains. |
784 SecIdentitySearchRef search = nil; | 888 SecIdentitySearchRef search = nil; |
785 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); | 889 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); |
786 scoped_cftyperef<SecIdentitySearchRef> scoped_search(search); | 890 scoped_cftyperef<SecIdentitySearchRef> scoped_search(search); |
787 while (!err) { | 891 while (!err) { |
788 SecIdentityRef identity = NULL; | 892 SecIdentityRef identity = NULL; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 // Append the intermediate certs from SecTrust to the result array: | 964 // Append the intermediate certs from SecTrust to the result array: |
861 if (cert_chain) { | 965 if (cert_chain) { |
862 int chain_count = CFArrayGetCount(cert_chain); | 966 int chain_count = CFArrayGetCount(cert_chain); |
863 if (chain_count > 1) { | 967 if (chain_count > 1) { |
864 CFArrayAppendArray(chain, | 968 CFArrayAppendArray(chain, |
865 cert_chain, | 969 cert_chain, |
866 CFRangeMake(1, chain_count - 1)); | 970 CFRangeMake(1, chain_count - 1)); |
867 } | 971 } |
868 CFRelease(cert_chain); | 972 CFRelease(cert_chain); |
869 } | 973 } |
870 exit: | 974 exit: |
871 if (result) | 975 if (result) |
872 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; | 976 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; |
873 return chain.release(); | 977 return chain.release(); |
874 } | 978 } |
875 | 979 |
876 } // namespace net | 980 } // namespace net |
OLD | NEW |