| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
| 9 #include <Security/Security.h> | 9 #include <Security/Security.h> |
| 10 #include <time.h> | 10 #include <time.h> |
| (...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 if (status == CSSM_OK && key_usage.field()) { | 705 if (status == CSSM_OK && key_usage.field()) { |
| 706 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); | 706 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); |
| 707 const CE_ExtendedKeyUsage* ext_key_usage = | 707 const CE_ExtendedKeyUsage* ext_key_usage = |
| 708 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); | 708 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); |
| 709 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) | 709 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) |
| 710 return false; | 710 return false; |
| 711 } | 711 } |
| 712 return true; | 712 return true; |
| 713 } | 713 } |
| 714 | 714 |
| 715 bool X509Certificate::IsIssuedBy( | |
| 716 const std::vector<CertPrincipal>& valid_issuers) { | |
| 717 // Get the cert's issuer chain. | |
| 718 CFArrayRef cert_chain = NULL; | |
| 719 OSStatus result = CopyCertChain(os_cert_handle(), &cert_chain); | |
| 720 if (result) | |
| 721 return false; | |
| 722 ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain); | |
| 723 | |
| 724 // Check all the certs in the chain for a match. | |
| 725 int n = CFArrayGetCount(cert_chain); | |
| 726 for (int i = 0; i < n; ++i) { | |
| 727 SecCertificateRef cert_handle = reinterpret_cast<SecCertificateRef>( | |
| 728 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); | |
| 729 scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromHandle( | |
| 730 cert_handle, X509Certificate::OSCertHandles())); | |
| 731 for (unsigned j = 0; j < valid_issuers.size(); j++) { | |
| 732 if (cert->issuer().Matches(valid_issuers[j])) | |
| 733 return true; | |
| 734 } | |
| 735 } | |
| 736 return false; | |
| 737 } | |
| 738 | |
| 739 // static | |
| 740 bool X509Certificate::GetSSLClientCertificates( | |
| 741 const std::string& server_domain, | |
| 742 const std::vector<CertPrincipal>& valid_issuers, | |
| 743 CertificateList* certs) { | |
| 744 ScopedCFTypeRef<SecIdentityRef> preferred_identity; | |
| 745 if (!server_domain.empty()) { | |
| 746 // See if there's an identity preference for this domain: | |
| 747 ScopedCFTypeRef<CFStringRef> domain_str( | |
| 748 base::SysUTF8ToCFStringRef("https://" + server_domain)); | |
| 749 SecIdentityRef identity = NULL; | |
| 750 // While SecIdentityCopyPreferences appears to take a list of CA issuers | |
| 751 // to restrict the identity search to, within Security.framework the | |
| 752 // argument is ignored and filtering unimplemented. See | |
| 753 // SecIdentity.cpp in libsecurity_keychain, specifically | |
| 754 // _SecIdentityCopyPreferenceMatchingName(). | |
| 755 { | |
| 756 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 757 if (SecIdentityCopyPreference(domain_str, 0, NULL, &identity) == noErr) | |
| 758 preferred_identity.reset(identity); | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 // Now enumerate the identities in the available keychains. | |
| 763 SecIdentitySearchRef search = NULL; | |
| 764 OSStatus err; | |
| 765 { | |
| 766 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 767 err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); | |
| 768 } | |
| 769 if (err) | |
| 770 return false; | |
| 771 ScopedCFTypeRef<SecIdentitySearchRef> scoped_search(search); | |
| 772 while (!err) { | |
| 773 SecIdentityRef identity = NULL; | |
| 774 { | |
| 775 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | |
| 776 err = SecIdentitySearchCopyNext(search, &identity); | |
| 777 } | |
| 778 if (err) | |
| 779 break; | |
| 780 ScopedCFTypeRef<SecIdentityRef> scoped_identity(identity); | |
| 781 | |
| 782 SecCertificateRef cert_handle; | |
| 783 err = SecIdentityCopyCertificate(identity, &cert_handle); | |
| 784 if (err != noErr) | |
| 785 continue; | |
| 786 ScopedCFTypeRef<SecCertificateRef> scoped_cert_handle(cert_handle); | |
| 787 | |
| 788 scoped_refptr<X509Certificate> cert( | |
| 789 CreateFromHandle(cert_handle, OSCertHandles())); | |
| 790 if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) | |
| 791 continue; | |
| 792 | |
| 793 // Skip duplicates (a cert may be in multiple keychains). | |
| 794 const SHA1HashValue& fingerprint = cert->fingerprint(); | |
| 795 unsigned i; | |
| 796 for (i = 0; i < certs->size(); ++i) { | |
| 797 if ((*certs)[i]->fingerprint().Equals(fingerprint)) | |
| 798 break; | |
| 799 } | |
| 800 if (i < certs->size()) | |
| 801 continue; | |
| 802 | |
| 803 bool is_preferred = preferred_identity && | |
| 804 CFEqual(preferred_identity, identity); | |
| 805 | |
| 806 // Make sure the issuer matches valid_issuers, if given. | |
| 807 if (!valid_issuers.empty() && !cert->IsIssuedBy(valid_issuers)) | |
| 808 continue; | |
| 809 | |
| 810 // The cert passes, so add it to the vector. | |
| 811 // If it's the preferred identity, add it at the start (so it'll be | |
| 812 // selected by default in the UI.) | |
| 813 if (is_preferred) | |
| 814 certs->insert(certs->begin(), cert); | |
| 815 else | |
| 816 certs->push_back(cert); | |
| 817 } | |
| 818 | |
| 819 if (err != errSecItemNotFound) { | |
| 820 OSSTATUS_LOG(ERROR, err) << "SecIdentitySearch error"; | |
| 821 return false; | |
| 822 } | |
| 823 return true; | |
| 824 } | |
| 825 | |
| 826 CFArrayRef X509Certificate::CreateClientCertificateChain() const { | 715 CFArrayRef X509Certificate::CreateClientCertificateChain() const { |
| 827 // Initialize the result array with just the IdentityRef of the receiver: | 716 // Initialize the result array with just the IdentityRef of the receiver: |
| 828 SecIdentityRef identity; | 717 SecIdentityRef identity; |
| 829 OSStatus result; | 718 OSStatus result; |
| 830 { | 719 { |
| 831 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | 720 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
| 832 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); | 721 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); |
| 833 } | 722 } |
| 834 if (result) { | 723 if (result) { |
| 835 OSSTATUS_LOG(ERROR, result) << "SecIdentityCreateWithCertificate error"; | 724 OSSTATUS_LOG(ERROR, result) << "SecIdentityCreateWithCertificate error"; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 936 *type = kPublicKeyTypeDH; | 825 *type = kPublicKeyTypeDH; |
| 937 break; | 826 break; |
| 938 default: | 827 default: |
| 939 *type = kPublicKeyTypeUnknown; | 828 *type = kPublicKeyTypeUnknown; |
| 940 *size_bits = 0; | 829 *size_bits = 0; |
| 941 break; | 830 break; |
| 942 } | 831 } |
| 943 } | 832 } |
| 944 | 833 |
| 945 } // namespace net | 834 } // namespace net |
| OLD | NEW |