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 <time.h> | 8 #include <time.h> |
9 | 9 |
10 #include "base/scoped_cftyperef.h" | 10 #include "base/scoped_cftyperef.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/sys_string_conversions.h" | |
wtc
2010/02/24 01:44:51
Nit: List "base/sys_string_conversions.h" after
"b
| |
12 #include "base/pickle.h" | 13 #include "base/pickle.h" |
13 #include "net/base/cert_status_flags.h" | 14 #include "net/base/cert_status_flags.h" |
14 #include "net/base/cert_verify_result.h" | 15 #include "net/base/cert_verify_result.h" |
15 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
16 | 17 |
17 using base::Time; | 18 using base::Time; |
18 | 19 |
19 namespace net { | 20 namespace net { |
20 | 21 |
21 class MacTrustedCertificates { | 22 class MacTrustedCertificates { |
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 exploded.minute = time.tm_min; | 350 exploded.minute = time.tm_min; |
350 exploded.second = time.tm_sec; | 351 exploded.second = time.tm_sec; |
351 exploded.millisecond = 0; | 352 exploded.millisecond = 0; |
352 | 353 |
353 *result = Time::FromUTCExploded(exploded); | 354 *result = Time::FromUTCExploded(exploded); |
354 break; | 355 break; |
355 } | 356 } |
356 } | 357 } |
357 } | 358 } |
358 | 359 |
359 // Returns true if this cert supports a given extended key usage. | |
360 bool CertSupportsUsage(SecCertificateRef cert, const CSSM_OID& usage_oid) { | |
361 CSSMFields fields; | |
362 if (GetCertFields(cert, &fields) != noErr) | |
363 return false; | |
364 for (unsigned f = 0; f < fields.num_of_fields; ++f) { | |
365 const CSSM_FIELD &field = fields.fields[f]; | |
366 if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_ExtendedKeyUsage)) { | |
367 const CSSM_X509_EXTENSION* ext = | |
368 reinterpret_cast<const CSSM_X509_EXTENSION*>(field.FieldValue.Data); | |
369 const CE_ExtendedKeyUsage* usage = | |
370 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); | |
371 for (unsigned p = 0; p < usage->numPurposes; ++p) { | |
372 if (CSSMOIDEqual(&usage->purposes[p], &usage_oid)) | |
373 return true; | |
374 } | |
375 } | |
376 } | |
377 return false; | |
378 } | |
379 | |
380 // Creates a SecPolicyRef for the given OID, with optional value. | 360 // Creates a SecPolicyRef for the given OID, with optional value. |
381 OSStatus CreatePolicy(const CSSM_OID* policy_OID, | 361 OSStatus CreatePolicy(const CSSM_OID* policy_OID, |
382 void* option_data, | 362 void* option_data, |
383 size_t option_length, | 363 size_t option_length, |
384 SecPolicyRef* policy) { | 364 SecPolicyRef* policy) { |
385 SecPolicySearchRef search; | 365 SecPolicySearchRef search; |
386 OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_OID, NULL, | 366 OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_OID, NULL, |
387 &search); | 367 &search); |
388 if (err) | 368 if (err) |
389 return err; | 369 return err; |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
725 return sha1; | 705 return sha1; |
726 | 706 |
727 DCHECK(NULL != cert_data.Data); | 707 DCHECK(NULL != cert_data.Data); |
728 DCHECK(0 != cert_data.Length); | 708 DCHECK(0 != cert_data.Length); |
729 | 709 |
730 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); | 710 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); |
731 | 711 |
732 return sha1; | 712 return sha1; |
733 } | 713 } |
734 | 714 |
715 bool X509Certificate::SupportsSSLClientAuth() const { | |
716 CSSMFields fields; | |
717 if (GetCertFields(cert_handle_, &fields) != noErr) | |
718 return false; | |
719 for (unsigned f = 0; f < fields.num_of_fields; ++f) { | |
720 const CSSM_FIELD &field = fields.fields[f]; | |
wtc
2010/02/24 01:44:51
Nit: put & next to the type, CSSM_FIELD.
| |
721 const CSSM_X509_EXTENSION* ext = | |
722 reinterpret_cast<const CSSM_X509_EXTENSION*>(field.FieldValue.Data); | |
723 if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_ExtendedKeyUsage)) { | |
724 const CE_ExtendedKeyUsage* usage = | |
725 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); | |
726 for (unsigned p = 0; p < usage->numPurposes; ++p) { | |
727 if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ClientAuth)) | |
728 return true; | |
729 } | |
730 } else if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_NetscapeCertType)) { | |
731 uint16_t flags = | |
732 *reinterpret_cast<const uint16_t*>(ext->value.parsedValue); | |
733 if (flags & CE_NCT_SSL_Client) | |
734 return true; | |
735 } | |
736 } | |
737 return false; | |
738 } | |
739 | |
735 // static | 740 // static |
736 OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) { | 741 OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) { |
737 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | 742 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { |
738 CSSM_APPLE_TP_SSL_OPTS_VERSION, | 743 CSSM_APPLE_TP_SSL_OPTS_VERSION, |
739 0, | 744 0, |
740 NULL, | 745 NULL, |
741 CSSM_APPLE_TP_SSL_CLIENT | 746 CSSM_APPLE_TP_SSL_CLIENT |
742 }; | 747 }; |
743 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, | 748 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, |
744 &tp_ssl_options, | 749 &tp_ssl_options, |
745 sizeof(tp_ssl_options), | 750 sizeof(tp_ssl_options), |
746 out_policy); | 751 out_policy); |
747 } | 752 } |
748 | 753 |
749 // static | 754 // static |
750 bool X509Certificate::GetSSLClientCertificates ( | 755 bool X509Certificate::GetSSLClientCertificates ( |
756 std::string domain, | |
751 std::vector<scoped_refptr<X509Certificate> >* certs) { | 757 std::vector<scoped_refptr<X509Certificate> >* certs) { |
758 scoped_cftyperef<SecIdentityRef> preferred_identity; | |
759 if (domain != "") { | |
wtc
2010/02/24 01:44:51
Is it better to say
!domain.empty()
?
| |
760 // See if there's an identity preference for this domain: | |
761 scoped_cftyperef<CFStringRef> domain_str( | |
762 base::SysUTF8ToCFStringRef("https://" + domain)); | |
763 SecIdentityRef identity = NULL; | |
764 if (SecIdentityCopyPreference(domain_str, | |
wtc
2010/02/24 01:44:51
The first argument should also contain the port, i
wtc
2010/02/24 20:13:51
I see the difficulty of getting the port. I forgo
| |
765 0, | |
766 NULL, | |
767 &identity) == noErr) | |
768 preferred_identity.reset(identity); | |
769 } | |
770 | |
752 SecIdentitySearchRef search = nil; | 771 SecIdentitySearchRef search = nil; |
753 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); | 772 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); |
754 fprintf(stderr,"====Created SecIdentitySearch %p\n",search);//TEMP | 773 fprintf(stderr,"====Created SecIdentitySearch %p\n",search);//TEMP |
755 scoped_cftyperef<SecIdentitySearchRef> scoped_search(search); | 774 scoped_cftyperef<SecIdentitySearchRef> scoped_search(search); |
756 while (!err) { | 775 while (!err) { |
757 SecIdentityRef identity = NULL; | 776 SecIdentityRef identity = NULL; |
758 err = SecIdentitySearchCopyNext(search, &identity); | 777 err = SecIdentitySearchCopyNext(search, &identity); |
759 if (err) | 778 if (err) |
760 break; | 779 break; |
761 scoped_cftyperef<SecIdentityRef> scoped_identity(identity); | 780 scoped_cftyperef<SecIdentityRef> scoped_identity(identity); |
762 | 781 |
763 SecCertificateRef cert_handle; | 782 SecCertificateRef cert_handle; |
764 err = SecIdentityCopyCertificate(identity, &cert_handle); | 783 err = SecIdentityCopyCertificate(identity, &cert_handle); |
765 if (err != noErr) | 784 if (err != noErr) |
766 continue; | 785 continue; |
767 | 786 |
768 scoped_refptr<X509Certificate> cert( | 787 scoped_refptr<X509Certificate> cert( |
769 CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT)); | 788 CreateFromHandle(cert_handle, SOURCE_LONE_CERT_IMPORT)); |
770 // cert_handle is adoped by cert, so I don't need to release it myself. | 789 // cert_handle is adoped by cert, so I don't need to release it myself. |
771 if (cert->HasExpired() || | 790 if (cert->HasExpired() || !cert->SupportsSSLClientAuth()) |
772 !CertSupportsUsage(cert_handle, CSSMOID_ClientAuth)) | |
773 continue; | 791 continue; |
774 | 792 |
775 // Skip duplicates (a cert may be in multiple keychains). | 793 // Skip duplicates (a cert may be in multiple keychains). |
776 X509Certificate::Fingerprint fingerprint = cert->fingerprint(); | 794 X509Certificate::Fingerprint fingerprint = cert->fingerprint(); |
777 unsigned i; | 795 unsigned i; |
778 for (i = 0; i < certs->size(); ++i) { | 796 for (i = 0; i < certs->size(); ++i) { |
779 if ((*certs)[i]->fingerprint().Equals(fingerprint)) | 797 if ((*certs)[i]->fingerprint().Equals(fingerprint)) |
780 break; | 798 break; |
781 } | 799 } |
782 if (i < certs->size()) | 800 if (i < certs->size()) |
783 continue; | 801 continue; |
784 | 802 |
785 // The cert passes, so add it to the vector. | 803 // The cert passes, so add it to the vector. |
786 certs->push_back(cert); | 804 // If it's the preferred identity, add it at the start (so it'll be |
805 // selected by default in the UI.) | |
wtc
2010/02/24 01:44:51
Nit: the period (.) should be after the closing pa
| |
806 if (preferred_identity && CFEqual(preferred_identity, identity)) | |
807 certs->insert(certs->begin(), cert); | |
808 else | |
809 certs->push_back(cert); | |
787 } | 810 } |
788 | 811 |
789 if (err != errSecItemNotFound) { | 812 if (err != errSecItemNotFound) { |
790 LOG(ERROR) << "SecIdentitySearch error " << err; | 813 LOG(ERROR) << "SecIdentitySearch error " << err; |
791 return false; | 814 return false; |
792 } | 815 } |
793 return true; | 816 return true; |
794 } | 817 } |
795 | 818 |
796 CFArrayRef X509Certificate::CreateClientCertificateChain() { | 819 CFArrayRef X509Certificate::CreateClientCertificateChain() const { |
797 // Initialize the result array with just the IdentityRef of the receiver: | 820 // Initialize the result array with just the IdentityRef of the receiver: |
798 OSStatus result; | 821 OSStatus result; |
799 SecIdentityRef identity; | 822 SecIdentityRef identity; |
800 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); | 823 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); |
801 if (result) { | 824 if (result) { |
802 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; | 825 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; |
803 return NULL; | 826 return NULL; |
804 } | 827 } |
805 scoped_cftyperef<CFMutableArrayRef> chain( | 828 scoped_cftyperef<CFMutableArrayRef> chain( |
806 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 829 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
847 CFRelease(trust_chain); | 870 CFRelease(trust_chain); |
848 } | 871 } |
849 } | 872 } |
850 exit: | 873 exit: |
851 if (result) | 874 if (result) |
852 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; | 875 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; |
853 return chain.release(); | 876 return chain.release(); |
854 } | 877 } |
855 | 878 |
856 } // namespace net | 879 } // namespace net |
OLD | NEW |