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 |