 Chromium Code Reviews
 Chromium Code Reviews Issue 1128008:
  Mac: Make client-cert picker only show certs the server will accept.  (Closed)
    
  
    Issue 1128008:
  Mac: Make client-cert picker only show certs the server will accept.  (Closed) 
  | 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 <time.h> | 9 #include <time.h> | 
| 9 | 10 | 
| 10 #include "base/scoped_cftyperef.h" | 11 #include "base/scoped_cftyperef.h" | 
| 11 #include "base/logging.h" | 12 #include "base/logging.h" | 
| 12 #include "base/pickle.h" | 13 #include "base/pickle.h" | 
| 13 #include "base/sys_string_conversions.h" | 14 #include "base/sys_string_conversions.h" | 
| 14 #include "net/base/cert_status_flags.h" | 15 #include "net/base/cert_status_flags.h" | 
| 15 #include "net/base/cert_verify_result.h" | 16 #include "net/base/cert_verify_result.h" | 
| 16 #include "net/base/net_errors.h" | 17 #include "net/base/net_errors.h" | 
| 17 | 18 | 
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 | 74 | 
| 74 void SetMacTestCertificate(X509Certificate* cert) { | 75 void SetMacTestCertificate(X509Certificate* cert) { | 
| 75 Singleton<MacTrustedCertificates>::get()->SetTestCertificate(cert); | 76 Singleton<MacTrustedCertificates>::get()->SetTestCertificate(cert); | 
| 76 } | 77 } | 
| 77 | 78 | 
| 78 namespace { | 79 namespace { | 
| 79 | 80 | 
| 80 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, | 81 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, | 
| 81 CFDictionaryRef*); | 82 CFDictionaryRef*); | 
| 82 | 83 | 
| 83 inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) { | |
| 84 return oid1->Length == oid2->Length && | |
| 85 (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0); | |
| 86 } | |
| 87 | |
| 88 int NetErrorFromOSStatus(OSStatus status) { | 84 int NetErrorFromOSStatus(OSStatus status) { | 
| 89 switch (status) { | 85 switch (status) { | 
| 90 case noErr: | 86 case noErr: | 
| 91 return OK; | 87 return OK; | 
| 92 case errSecNotAvailable: | 88 case errSecNotAvailable: | 
| 93 case errSecNoCertificateModule: | 89 case errSecNoCertificateModule: | 
| 94 case errSecNoPolicyModule: | 90 case errSecNoPolicyModule: | 
| 95 return ERR_NOT_IMPLEMENTED; | 91 return ERR_NOT_IMPLEMENTED; | 
| 96 case errSecAuthFailed: | 92 case errSecAuthFailed: | 
| 97 return ERR_ACCESS_DENIED; | 93 return ERR_ACCESS_DENIED; | 
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 c != hostname.end() && is_dotted_ip; ++c) | 162 c != hostname.end() && is_dotted_ip; ++c) | 
| 167 is_dotted_ip = (*c >= '0' && *c <= '9') || *c == '.'; | 163 is_dotted_ip = (*c >= '0' && *c <= '9') || *c == '.'; | 
| 168 if (is_dotted_ip) { | 164 if (is_dotted_ip) { | 
| 169 for (std::vector<std::string>::const_iterator name = dns_names->begin(); | 165 for (std::vector<std::string>::const_iterator name = dns_names->begin(); | 
| 170 name != dns_names->end() && !override_hostname_mismatch; ++name) | 166 name != dns_names->end() && !override_hostname_mismatch; ++name) | 
| 171 override_hostname_mismatch = (*name == hostname); | 167 override_hostname_mismatch = (*name == hostname); | 
| 172 } | 168 } | 
| 173 return override_hostname_mismatch; | 169 return override_hostname_mismatch; | 
| 174 } | 170 } | 
| 175 | 171 | 
| 176 void ParsePrincipal(const CSSM_X509_NAME* name, | |
| 177 X509Certificate::Principal* principal) { | |
| 178 std::vector<std::string> common_names, locality_names, state_names, | |
| 179 country_names; | |
| 180 | |
| 181 // TODO(jcampan): add business_category and serial_number. | |
| 182 const CSSM_OID* kOIDs[] = { &CSSMOID_CommonName, | |
| 183 &CSSMOID_LocalityName, | |
| 184 &CSSMOID_StateProvinceName, | |
| 185 &CSSMOID_CountryName, | |
| 186 &CSSMOID_StreetAddress, | |
| 187 &CSSMOID_OrganizationName, | |
| 188 &CSSMOID_OrganizationalUnitName, | |
| 189 &CSSMOID_DNQualifier }; // This should be "DC" | |
| 190 // but is undoubtedly | |
| 191 // wrong. TODO(avi): | |
| 192 // Find the right OID. | |
| 193 | |
| 194 std::vector<std::string>* values[] = { | |
| 195 &common_names, &locality_names, | |
| 196 &state_names, &country_names, | |
| 197 &(principal->street_addresses), | |
| 198 &(principal->organization_names), | |
| 199 &(principal->organization_unit_names), | |
| 200 &(principal->domain_components) }; | |
| 201 DCHECK(arraysize(kOIDs) == arraysize(values)); | |
| 202 | |
| 203 for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) { | |
| 204 CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn]; | |
| 205 for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) { | |
| 206 CSSM_X509_TYPE_VALUE_PAIR pair_struct = | |
| 207 rdn_struct.AttributeTypeAndValue[pair]; | |
| 208 for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { | |
| 209 if (CSSMOIDEqual(&pair_struct.type, kOIDs[oid])) { | |
| 210 std::string value = | |
| 211 std::string(reinterpret_cast<std::string::value_type*> | |
| 212 (pair_struct.value.Data), | |
| 213 pair_struct.value.Length); | |
| 214 values[oid]->push_back(value); | |
| 215 break; | |
| 216 } | |
| 217 } | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 // We don't expect to have more than one CN, L, S, and C. | |
| 222 std::vector<std::string>* single_value_lists[4] = { | |
| 223 &common_names, &locality_names, &state_names, &country_names }; | |
| 224 std::string* single_values[4] = { | |
| 225 &principal->common_name, &principal->locality_name, | |
| 226 &principal->state_or_province_name, &principal->country_name }; | |
| 227 for (size_t i = 0; i < arraysize(single_value_lists); ++i) { | |
| 228 DCHECK(single_value_lists[i]->size() <= 1); | |
| 229 if (single_value_lists[i]->size() > 0) | |
| 230 *(single_values[i]) = (*(single_value_lists[i]))[0]; | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 struct CSSMFields { | 172 struct CSSMFields { | 
| 235 CSSMFields() : cl_handle(NULL), num_of_fields(0), fields(NULL) {} | 173 CSSMFields() : cl_handle(NULL), num_of_fields(0), fields(NULL) {} | 
| 236 ~CSSMFields() { | 174 ~CSSMFields() { | 
| 237 if (cl_handle) | 175 if (cl_handle) | 
| 238 CSSM_CL_FreeFields(cl_handle, num_of_fields, &fields); | 176 CSSM_CL_FreeFields(cl_handle, num_of_fields, &fields); | 
| 239 } | 177 } | 
| 240 | 178 | 
| 241 CSSM_CL_HANDLE cl_handle; | 179 CSSM_CL_HANDLE cl_handle; | 
| 242 uint32 num_of_fields; | 180 uint32 num_of_fields; | 
| 243 CSSM_FIELD_PTR fields; | 181 CSSM_FIELD_PTR fields; | 
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 379 }; | 317 }; | 
| 380 err = SecPolicySetValue(*policy, &options_data); | 318 err = SecPolicySetValue(*policy, &options_data); | 
| 381 if (err) { | 319 if (err) { | 
| 382 CFRelease(*policy); | 320 CFRelease(*policy); | 
| 383 return err; | 321 return err; | 
| 384 } | 322 } | 
| 385 } | 323 } | 
| 386 return noErr; | 324 return noErr; | 
| 387 } | 325 } | 
| 388 | 326 | 
| 327 // Gets the issuer chain of intermediate and root certs for a given cert. | |
| 328 // This function calls SecTrust but doesn't actually pay attention to the trust | |
| 329 // result: it shouldn't be used to determine trust, just to traverse the chain. | |
| 330 // Caller is responsible for releasing the value stored into *out_trust_chain. | |
| 331 OSStatus CopyCertChain(SecCertificateRef cert_handle, | |
| 
wtc
2010/03/24 23:52:05
Nit: CopyCertChain also copies the entire cert cha
 | |
| 332 CFArrayRef* out_cert_chain) { | |
| 333 DCHECK(cert_handle && out_cert_chain); | |
| 334 // Create an SSL policy ref configured for client cert evaluation. | |
| 335 SecPolicyRef ssl_policy; | |
| 336 OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy); | |
| 337 if (result) | |
| 338 return result; | |
| 339 scoped_cftyperef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
| 340 | |
| 341 // Create a SecTrustRef. | |
| 342 scoped_cftyperef<CFArrayRef> input_certs( | |
| 343 CFArrayCreate(NULL, (const void**)&cert_handle, 1, | |
| 344 &kCFTypeArrayCallBacks)); | |
| 345 SecTrustRef trust_ref = NULL; | |
| 346 result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref); | |
| 347 if (result) | |
| 348 return result; | |
| 349 scoped_cftyperef<SecTrustRef> trust(trust_ref); | |
| 350 | |
| 351 // Evaluate trust, which creates the cert chain. | |
| 352 SecTrustResultType status; | |
| 353 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | |
| 354 result = SecTrustEvaluate(trust, &status); | |
| 355 if (result) | |
| 356 return result; | |
| 357 return SecTrustGetResult(trust, &status, out_cert_chain, &status_chain); | |
| 358 } | |
| 359 | |
| 389 } // namespace | 360 } // namespace | 
| 390 | 361 | 
| 391 void X509Certificate::Initialize() { | 362 void X509Certificate::Initialize() { | 
| 392 const CSSM_X509_NAME* name; | 363 const CSSM_X509_NAME* name; | 
| 393 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); | 364 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); | 
| 394 if (!status) { | 365 if (!status) { | 
| 395 ParsePrincipal(name, &subject_); | 366 subject_.Parse(name); | 
| 396 } | 367 } | 
| 397 status = SecCertificateGetIssuer(cert_handle_, &name); | 368 status = SecCertificateGetIssuer(cert_handle_, &name); | 
| 398 if (!status) { | 369 if (!status) { | 
| 399 ParsePrincipal(name, &issuer_); | 370 issuer_.Parse(name); | 
| 400 } | 371 } | 
| 401 | 372 | 
| 402 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, | 373 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, | 
| 403 &valid_start_); | 374 &valid_start_); | 
| 404 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, | 375 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, | 
| 405 &valid_expiry_); | 376 &valid_expiry_); | 
| 406 | 377 | 
| 407 fingerprint_ = CalculateFingerprint(cert_handle_); | 378 fingerprint_ = CalculateFingerprint(cert_handle_); | 
| 408 } | 379 } | 
| 409 | 380 | 
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 735 } else if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_NetscapeCertType)) { | 706 } else if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_NetscapeCertType)) { | 
| 736 uint16_t flags = | 707 uint16_t flags = | 
| 737 *reinterpret_cast<const uint16_t*>(ext->value.parsedValue); | 708 *reinterpret_cast<const uint16_t*>(ext->value.parsedValue); | 
| 738 if (flags & CE_NCT_SSL_Client) | 709 if (flags & CE_NCT_SSL_Client) | 
| 739 return true; | 710 return true; | 
| 740 } | 711 } | 
| 741 } | 712 } | 
| 742 return false; | 713 return false; | 
| 743 } | 714 } | 
| 744 | 715 | 
| 716 bool X509Certificate::IsIssuedBy( | |
| 717 const std::vector<CertPrincipal>& valid_issuers) { | |
| 718 // Get the cert's issuer chain. | |
| 719 CFArrayRef trust_chain = NULL; | |
| 
wtc
2010/03/24 23:52:05
Nit: trust_chain => cert_chain
     scoped_trust_c
 | |
| 720 OSStatus result; | |
| 721 result = CopyCertChain(os_cert_handle(), &trust_chain); | |
| 722 if (result != noErr) | |
| 723 return false; | |
| 724 scoped_cftyperef<CFArrayRef> scoped_trust_chain(trust_chain); | |
| 725 | |
| 726 // Check all the certs in the chain for a match. | |
| 727 int n = CFArrayGetCount(trust_chain); | |
| 728 for (int i = 0; i < n; ++i) { | |
| 729 SecCertificateRef intermediate_handle = reinterpret_cast<SecCertificateRef>( | |
| 
wtc
2010/03/24 23:52:05
Nit: "intermediate" is misleading, because this ca
 
Jens Alfke
2010/03/26 17:15:04
It is, but we have to check the issuer of that cer
 
wtc
2010/03/26 21:03:22
In each iteration, you are checking intermediate->
 | |
| 730 const_cast<void*>(CFArrayGetValueAtIndex(trust_chain, i))); | |
| 731 CFRetain(intermediate_handle); | |
| 732 X509Certificate* intermediate = X509Certificate::CreateFromHandle( | |
| 
wtc
2010/03/24 23:52:05
X509Certificate is reference counted, so always st
 | |
| 733 intermediate_handle, | |
| 734 X509Certificate::SOURCE_LONE_CERT_IMPORT, | |
| 735 X509Certificate::OSCertHandles()); | |
| 736 for (unsigned j = 0; j < valid_issuers.size(); j++) | |
| 
wtc
2010/03/24 23:52:05
Nit: use curly braces around the for loop's body,
 | |
| 737 if (intermediate->subject().Matches(valid_issuers[j])) { | |
| 738 return true; | |
| 739 } | |
| 740 } | |
| 741 return false; | |
| 742 } | |
| 743 | |
| 745 // static | 744 // static | 
| 746 OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) { | 745 OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) { | 
| 747 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | 746 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | 
| 748 CSSM_APPLE_TP_SSL_OPTS_VERSION, | 747 CSSM_APPLE_TP_SSL_OPTS_VERSION, | 
| 749 0, | 748 0, | 
| 750 NULL, | 749 NULL, | 
| 751 CSSM_APPLE_TP_SSL_CLIENT | 750 CSSM_APPLE_TP_SSL_CLIENT | 
| 752 }; | 751 }; | 
| 753 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, | 752 return CreatePolicy(&CSSMOID_APPLE_TP_SSL, | 
| 754 &tp_ssl_options, | 753 &tp_ssl_options, | 
| 755 sizeof(tp_ssl_options), | 754 sizeof(tp_ssl_options), | 
| 756 out_policy); | 755 out_policy); | 
| 757 } | 756 } | 
| 758 | 757 | 
| 759 // static | 758 // static | 
| 760 bool X509Certificate::GetSSLClientCertificates ( | 759 bool X509Certificate::GetSSLClientCertificates ( | 
| 761 const std::string& server_domain, | 760 const std::string& server_domain, | 
| 761 const std::vector<Principal>& valid_issuers, | |
| 762 std::vector<scoped_refptr<X509Certificate> >* certs) { | 762 std::vector<scoped_refptr<X509Certificate> >* certs) { | 
| 763 scoped_cftyperef<SecIdentityRef> preferred_identity; | 763 scoped_cftyperef<SecIdentityRef> preferred_identity; | 
| 764 if (!server_domain.empty()) { | 764 if (!server_domain.empty()) { | 
| 765 // See if there's an identity preference for this domain: | 765 // See if there's an identity preference for this domain: | 
| 766 scoped_cftyperef<CFStringRef> domain_str( | 766 scoped_cftyperef<CFStringRef> domain_str( | 
| 767 base::SysUTF8ToCFStringRef("https://" + server_domain)); | 767 base::SysUTF8ToCFStringRef("https://" + server_domain)); | 
| 768 SecIdentityRef identity = NULL; | 768 SecIdentityRef identity = NULL; | 
| 769 if (SecIdentityCopyPreference(domain_str, | 769 if (SecIdentityCopyPreference(domain_str, | 
| 770 0, | 770 0, | 
| 771 NULL, | 771 NULL, | 
| 
wtc
2010/03/24 23:52:05
IMPORTANT: we can finally pass a real validIssuers
 
wtc
2010/03/25 01:00:35
I looked at the source code of SecIdentityCopyPref
 | |
| 772 &identity) == noErr) | 772 &identity) == noErr) | 
| 773 preferred_identity.reset(identity); | 773 preferred_identity.reset(identity); | 
| 774 } | 774 } | 
| 775 | 775 | 
| 776 // Now enumerate the identities in the available keychains. | |
| 776 SecIdentitySearchRef search = nil; | 777 SecIdentitySearchRef search = nil; | 
| 777 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); | 778 OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search); | 
| 778 scoped_cftyperef<SecIdentitySearchRef> scoped_search(search); | 779 scoped_cftyperef<SecIdentitySearchRef> scoped_search(search); | 
| 779 while (!err) { | 780 while (!err) { | 
| 780 SecIdentityRef identity = NULL; | 781 SecIdentityRef identity = NULL; | 
| 781 err = SecIdentitySearchCopyNext(search, &identity); | 782 err = SecIdentitySearchCopyNext(search, &identity); | 
| 782 if (err) | 783 if (err) | 
| 783 break; | 784 break; | 
| 784 scoped_cftyperef<SecIdentityRef> scoped_identity(identity); | 785 scoped_cftyperef<SecIdentityRef> scoped_identity(identity); | 
| 785 | 786 | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 798 // Skip duplicates (a cert may be in multiple keychains). | 799 // Skip duplicates (a cert may be in multiple keychains). | 
| 799 X509Certificate::Fingerprint fingerprint = cert->fingerprint(); | 800 X509Certificate::Fingerprint fingerprint = cert->fingerprint(); | 
| 800 unsigned i; | 801 unsigned i; | 
| 801 for (i = 0; i < certs->size(); ++i) { | 802 for (i = 0; i < certs->size(); ++i) { | 
| 802 if ((*certs)[i]->fingerprint().Equals(fingerprint)) | 803 if ((*certs)[i]->fingerprint().Equals(fingerprint)) | 
| 803 break; | 804 break; | 
| 804 } | 805 } | 
| 805 if (i < certs->size()) | 806 if (i < certs->size()) | 
| 806 continue; | 807 continue; | 
| 807 | 808 | 
| 809 bool is_preferred = preferred_identity && | |
| 810 CFEqual(preferred_identity, identity); | |
| 811 | |
| 812 // Make sure the issuer matches valid_issuers, if given. | |
| 813 // But an explicit cert preference overrides this. | |
| 814 if (!is_preferred && | |
| 815 valid_issuers.size() > 0 && | |
| 816 !cert->IsIssuedBy(valid_issuers)) | |
| 817 continue; | |
| 818 | |
| 808 // The cert passes, so add it to the vector. | 819 // The cert passes, so add it to the vector. | 
| 809 // If it's the preferred identity, add it at the start (so it'll be | 820 // If it's the preferred identity, add it at the start (so it'll be | 
| 810 // selected by default in the UI.) | 821 // selected by default in the UI.) | 
| 811 if (preferred_identity && CFEqual(preferred_identity, identity)) | 822 if (is_preferred) | 
| 812 certs->insert(certs->begin(), cert); | 823 certs->insert(certs->begin(), cert); | 
| 813 else | 824 else | 
| 814 certs->push_back(cert); | 825 certs->push_back(cert); | 
| 815 } | 826 } | 
| 816 | 827 | 
| 817 if (err != errSecItemNotFound) { | 828 if (err != errSecItemNotFound) { | 
| 818 LOG(ERROR) << "SecIdentitySearch error " << err; | 829 LOG(ERROR) << "SecIdentitySearch error " << err; | 
| 819 return false; | 830 return false; | 
| 820 } | 831 } | 
| 821 return true; | 832 return true; | 
| 822 } | 833 } | 
| 823 | 834 | 
| 824 CFArrayRef X509Certificate::CreateClientCertificateChain() const { | 835 CFArrayRef X509Certificate::CreateClientCertificateChain() const { | 
| 825 // Initialize the result array with just the IdentityRef of the receiver: | 836 // Initialize the result array with just the IdentityRef of the receiver: | 
| 826 OSStatus result; | 837 OSStatus result; | 
| 827 SecIdentityRef identity; | 838 SecIdentityRef identity; | 
| 828 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); | 839 result = SecIdentityCreateWithCertificate(NULL, cert_handle_, &identity); | 
| 829 if (result) { | 840 if (result) { | 
| 830 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; | 841 LOG(ERROR) << "SecIdentityCreateWithCertificate error " << result; | 
| 831 return NULL; | 842 return NULL; | 
| 832 } | 843 } | 
| 833 scoped_cftyperef<CFMutableArrayRef> chain( | 844 scoped_cftyperef<CFMutableArrayRef> chain( | 
| 834 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 845 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); | 
| 835 CFArrayAppendValue(chain, identity); | 846 CFArrayAppendValue(chain, identity); | 
| 836 | 847 | 
| 837 { | 848 CFArrayRef trust_chain = NULL; | 
| 
wtc
2010/03/24 23:52:05
Nit: trust_chain => cert_chain
 | |
| 838 // Create an SSL policy ref configured for client cert evaluation. | 849 result = CopyCertChain(cert_handle_, &trust_chain); | 
| 839 SecPolicyRef ssl_policy; | 850 if (result) | 
| 840 result = CreateSSLClientPolicy(&ssl_policy); | 851 goto exit; | 
| 841 if (result) | |
| 842 goto exit; | |
| 843 scoped_cftyperef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
| 844 | 852 | 
| 845 // Use a SecTrust object to find the intermediate certs in the trust chain. | 853 // Append the intermediate certs from SecTrust to the result array: | 
| 846 scoped_cftyperef<CFArrayRef> input_certs( | 854 if (trust_chain) { | 
| 847 CFArrayCreate(NULL, (const void**)&cert_handle_, 1, | 855 int chain_count = CFArrayGetCount(trust_chain); | 
| 848 &kCFTypeArrayCallBacks)); | 856 if (chain_count > 1) { | 
| 849 SecTrustRef trust_ref = NULL; | 857 CFArrayAppendArray(chain, | 
| 850 result = SecTrustCreateWithCertificates(input_certs, | 858 trust_chain, | 
| 851 ssl_policy, | 859 CFRangeMake(1, chain_count - 1)); | 
| 852 &trust_ref); | |
| 853 if (result) | |
| 854 goto exit; | |
| 855 scoped_cftyperef<SecTrustRef> trust(trust_ref); | |
| 856 | |
| 857 SecTrustResultType status; | |
| 858 CFArrayRef trust_chain = NULL; | |
| 859 CSSM_TP_APPLE_EVIDENCE_INFO* status_chain; | |
| 860 result = SecTrustEvaluate(trust, &status); | |
| 861 if (result) | |
| 862 goto exit; | |
| 863 result = SecTrustGetResult(trust, &status, &trust_chain, &status_chain); | |
| 864 if (result) | |
| 865 goto exit; | |
| 866 | |
| 867 // Append the intermediate certs from SecTrust to the result array: | |
| 868 if (trust_chain) { | |
| 869 int chain_count = CFArrayGetCount(trust_chain); | |
| 870 if (chain_count > 1) { | |
| 871 CFArrayAppendArray(chain, | |
| 872 trust_chain, | |
| 873 CFRangeMake(1, chain_count - 1)); | |
| 874 } | |
| 875 CFRelease(trust_chain); | |
| 876 } | 860 } | 
| 861 CFRelease(trust_chain); | |
| 877 } | 862 } | 
| 878 exit: | 863 exit: | 
| 879 if (result) | 864 if (result) | 
| 880 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; | 865 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; | 
| 881 return chain.release(); | 866 return chain.release(); | 
| 882 } | 867 } | 
| 883 | 868 | 
| 884 } // namespace net | 869 } // namespace net | 
| OLD | NEW |