Chromium Code Reviews| 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/logging.h" | 11 #include "base/logging.h" |
| 11 #include "base/pickle.h" | 12 #include "base/pickle.h" |
| 12 #include "net/base/cert_status_flags.h" | 13 #include "net/base/cert_status_flags.h" |
| 13 #include "net/base/ev_root_ca_metadata.h" | 14 #include "net/base/cert_verify_result.h" |
| 14 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 15 | 16 |
| 16 using base::Time; | 17 using base::Time; |
| 17 | 18 |
| 18 namespace net { | 19 namespace net { |
| 19 | 20 |
| 21 class MacTrustedCertificates { | |
|
wtc
2009/08/27 00:14:18
See if you can put this class inside #ifdef UNIT_T
| |
| 22 public: | |
| 23 // Sets the trusted root certificate used by tests. Call with |cert| set | |
| 24 // to NULL to clear the test certificate. | |
| 25 void SetTestCertificate(X509Certificate* cert) { | |
| 26 AutoLock lock(lock_); | |
| 27 test_certificate_ = cert; | |
| 28 } | |
| 29 | |
| 30 // Returns an array containing the trusted certificates for use with | |
| 31 // SecTrustSetAnchorCertificates(). Returns NULL if the system-supplied | |
| 32 // list of trust anchors is acceptable (that is, there is not test | |
| 33 // certificate available). Ownership follows the Create Rule (caller | |
| 34 // is responsible for calling CFRelease on the non-NULL result). | |
| 35 CFArrayRef CopyTrustedCertificateArray() { | |
| 36 AutoLock lock(lock_); | |
| 37 | |
| 38 if (!test_certificate_) | |
| 39 return NULL; | |
| 40 | |
| 41 // Failure to copy the anchor certificates or add the test certificate | |
| 42 // is non-fatal; SecTrustEvaluate() will use the system anchors instead. | |
| 43 CFArrayRef anchor_array; | |
| 44 OSStatus status = SecTrustCopyAnchorCertificates(&anchor_array); | |
| 45 if (status) | |
| 46 return NULL; | |
| 47 scoped_cftyperef<CFArrayRef> scoped_anchor_array(anchor_array); | |
| 48 CFMutableArrayRef merged_array = CFArrayCreateMutableCopy( | |
| 49 kCFAllocatorDefault, 0, anchor_array); | |
| 50 if (!merged_array) | |
| 51 return NULL; | |
| 52 CFArrayAppendValue(merged_array, test_certificate_->os_cert_handle()); | |
| 53 | |
| 54 return merged_array; | |
| 55 } | |
| 56 private: | |
| 57 friend struct DefaultSingletonTraits<MacTrustedCertificates>; | |
| 58 | |
| 59 // Obtain an instance of MacTrustedCertificates via the singleton | |
| 60 // interface. | |
| 61 MacTrustedCertificates() : test_certificate_(NULL) { } | |
| 62 | |
| 63 // An X509Certificate object that may be appended to the list of | |
| 64 // system trusted anchors. | |
| 65 scoped_refptr<X509Certificate> test_certificate_; | |
| 66 | |
| 67 // The trusted cache may be accessed from multiple threads. | |
| 68 mutable Lock lock_; | |
| 69 | |
| 70 DISALLOW_COPY_AND_ASSIGN(MacTrustedCertificates); | |
| 71 }; | |
| 72 | |
| 73 void SetMacTestCertificate(X509Certificate* cert) { | |
|
wtc
2009/08/27 00:14:18
We should declare this function in x509_certificat
| |
| 74 Singleton<MacTrustedCertificates>::get()->SetTestCertificate(cert); | |
| 75 } | |
| 76 | |
| 20 namespace { | 77 namespace { |
| 21 | 78 |
| 79 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, | |
| 80 CFDictionaryRef*); | |
| 81 | |
| 22 inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) { | 82 inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) { |
| 23 return oid1->Length == oid2->Length && | 83 return oid1->Length == oid2->Length && |
| 24 (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0); | 84 (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0); |
| 25 } | 85 } |
| 26 | 86 |
| 87 int NetErrorFromOSStatus(OSStatus status) { | |
| 88 switch (status) { | |
| 89 case noErr: | |
| 90 return OK; | |
| 91 case errSecNotAvailable: | |
| 92 case errSecNoCertificateModule: | |
| 93 case errSecNoPolicyModule: | |
| 94 return ERR_NOT_IMPLEMENTED; | |
| 95 case errSecAuthFailed: | |
| 96 return ERR_ACCESS_DENIED; | |
| 97 default: | |
| 98 LOG(ERROR) << "Unknown error " << status << " mapped to net::ERR_FAILED"; | |
| 99 return ERR_FAILED; | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 int CertStatusFromOSStatus(OSStatus status) { | |
| 104 switch (status) { | |
| 105 case noErr: | |
| 106 return 0; | |
| 107 | |
| 108 case CSSMERR_TP_INVALID_ANCHOR_CERT: | |
| 109 case CSSMERR_TP_NOT_TRUSTED: | |
| 110 case CSSMERR_TP_INVALID_CERT_AUTHORITY: | |
| 111 return CERT_STATUS_AUTHORITY_INVALID; | |
| 112 | |
| 113 case CSSMERR_TP_CERT_EXPIRED: | |
| 114 case CSSMERR_TP_CERT_NOT_VALID_YET: | |
| 115 // "Expired" and "not yet valid" collapse into a single status. | |
| 116 return CERT_STATUS_DATE_INVALID; | |
| 117 | |
| 118 case CSSMERR_TP_CERT_REVOKED: | |
| 119 case CSSMERR_TP_CERT_SUSPENDED: | |
| 120 return CERT_STATUS_REVOKED; | |
| 121 | |
| 122 case CSSMERR_APPLETP_HOSTNAME_MISMATCH: | |
| 123 return CERT_STATUS_COMMON_NAME_INVALID; | |
| 124 | |
| 125 case CSSMERR_APPLETP_CRL_NOT_FOUND: | |
| 126 case CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK: | |
| 127 return CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 128 | |
| 129 case CSSMERR_APPLETP_CRL_NOT_TRUSTED: | |
| 130 case CSSMERR_APPLETP_CRL_SERVER_DOWN: | |
| 131 case CSSMERR_APPLETP_CRL_NOT_VALID_YET: | |
| 132 case CSSMERR_APPLETP_NETWORK_FAILURE: | |
| 133 case CSSMERR_APPLETP_OCSP_UNAVAILABLE: | |
| 134 case CSSMERR_APPLETP_OCSP_BAD_RESPONSE: | |
| 135 case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED: | |
| 136 case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED: | |
| 137 case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ: | |
| 138 case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR: | |
| 139 case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER: | |
| 140 // We asked for a revocation check, but didn't get it. | |
| 141 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
| 142 | |
| 143 default: | |
| 144 // Failure was due to something Chromium doesn't define a | |
| 145 // specific status for (such as basic constraints violation, or | |
| 146 // unknown critical extension) | |
| 147 return CERT_STATUS_INVALID; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 bool OverrideHostnameMismatch(const std::string& hostname, | |
| 152 std::vector<std::string>* dns_names) { | |
| 153 // SecTrustEvaluate() does not check dotted IP addresses. If | |
| 154 // hostname is provided as, say, 127.0.0.1, then the error | |
| 155 // CSSMERR_APPLETP_HOSTNAME_MISMATCH will always be returned, | |
| 156 // even if the certificate contains 127.0.0.1 as one of its names. | |
|
wtc
2009/08/27 02:12:06
Change "one of its names" to "the commonName in th
| |
| 157 // We, however, want to allow that behavior. SecTrustEvaluate() | |
|
wtc
2009/08/27 02:12:06
Add something like "to be compatible with Windows
| |
| 158 // only checks for digits and dots when considering whether a | |
| 159 // hostname is an IP address, so IPv6 and hex addresses go through | |
| 160 // its normal comparison. | |
| 161 bool is_dotted_ip = true; | |
| 162 bool override_hostname_mismatch = false; | |
| 163 for (std::string::const_iterator c = hostname.begin(); | |
| 164 c != hostname.end() && is_dotted_ip; ++c) | |
| 165 is_dotted_ip = (*c >= '0' && *c <= '9') || *c == '.'; | |
| 166 if (is_dotted_ip) { | |
| 167 for (std::vector<std::string>::const_iterator name = dns_names->begin(); | |
| 168 name != dns_names->end() && !override_hostname_mismatch; ++name) | |
| 169 override_hostname_mismatch = (*name == hostname); | |
| 170 } | |
| 171 return override_hostname_mismatch; | |
| 172 } | |
| 173 | |
| 27 void ParsePrincipal(const CSSM_X509_NAME* name, | 174 void ParsePrincipal(const CSSM_X509_NAME* name, |
| 28 X509Certificate::Principal* principal) { | 175 X509Certificate::Principal* principal) { |
| 29 std::vector<std::string> common_names, locality_names, state_names, | 176 std::vector<std::string> common_names, locality_names, state_names, |
| 30 country_names; | 177 country_names; |
| 31 | 178 |
| 32 // TODO(jcampan): add business_category and serial_number. | 179 // TODO(jcampan): add business_category and serial_number. |
| 33 const CSSM_OID* kOIDs[] = { &CSSMOID_CommonName, | 180 const CSSM_OID* kOIDs[] = { &CSSMOID_CommonName, |
| 34 &CSSMOID_LocalityName, | 181 &CSSMOID_LocalityName, |
| 35 &CSSMOID_StateProvinceName, | 182 &CSSMOID_StateProvinceName, |
| 36 &CSSMOID_CountryName, | 183 &CSSMOID_CountryName, |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { | 402 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { |
| 256 dns_names->clear(); | 403 dns_names->clear(); |
| 257 | 404 |
| 258 GetCertGeneralNamesForOID(cert_handle_, CSSMOID_SubjectAltName, GNT_DNSName, | 405 GetCertGeneralNamesForOID(cert_handle_, CSSMOID_SubjectAltName, GNT_DNSName, |
| 259 dns_names); | 406 dns_names); |
| 260 | 407 |
| 261 if (dns_names->empty()) | 408 if (dns_names->empty()) |
| 262 dns_names->push_back(subject_.common_name); | 409 dns_names->push_back(subject_.common_name); |
| 263 } | 410 } |
| 264 | 411 |
| 265 int X509Certificate::Verify(const std::string& hostname, | 412 int X509Certificate::Verify(const std::string& hostname, int flags, |
| 266 int flags, CertVerifyResult* verify_result) const { | 413 CertVerifyResult* verify_result) const { |
| 267 NOTIMPLEMENTED(); | 414 verify_result->Reset(); |
| 268 return ERR_NOT_IMPLEMENTED; | 415 |
| 269 } | 416 // Create an SSL SecPolicyRef, and configure it to perform hostname |
| 270 | 417 // validation. The hostname check does 99% of what we want, with the |
| 271 // Returns true if the certificate is an extended-validation certificate. | 418 // exception of dotted IPv4 addreses, which we handle ourselves below. |
| 272 // | 419 SecPolicySearchRef ssl_policy_search_ref = NULL; |
| 273 // The certificate has already been verified by the HTTP library. cert_status | 420 OSStatus status = SecPolicySearchCreate(CSSM_CERT_X_509v3, |
| 274 // represents the result of that verification. This function performs | 421 &CSSMOID_APPLE_TP_SSL, |
| 275 // additional checks of the certificatePolicies extensions of the certificates | 422 NULL, |
| 276 // in the certificate chain according to Section 7 (pp. 11-12) of the EV | 423 &ssl_policy_search_ref); |
| 277 // Certificate Guidelines Version 1.0 at | 424 if (status) |
| 278 // http://cabforum.org/EV_Certificate_Guidelines.pdf. | 425 return NetErrorFromOSStatus(status); |
| 426 scoped_cftyperef<SecPolicySearchRef> | |
| 427 scoped_ssl_policy_search_ref(ssl_policy_search_ref); | |
| 428 SecPolicyRef ssl_policy = NULL; | |
| 429 status = SecPolicySearchCopyNext(ssl_policy_search_ref, &ssl_policy); | |
| 430 if (status) | |
| 431 return NetErrorFromOSStatus(status); | |
| 432 scoped_cftyperef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
| 433 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { CSSM_APPLE_TP_SSL_OPTS_VERSION }; | |
| 434 tp_ssl_options.ServerName = hostname.data(); | |
| 435 tp_ssl_options.ServerNameLen = hostname.size(); | |
| 436 CSSM_DATA tp_ssl_options_data_value; | |
| 437 tp_ssl_options_data_value.Data = reinterpret_cast<uint8*>(&tp_ssl_options); | |
| 438 tp_ssl_options_data_value.Length = sizeof(tp_ssl_options); | |
| 439 status = SecPolicySetValue(ssl_policy, &tp_ssl_options_data_value); | |
| 440 if (status) | |
| 441 return NetErrorFromOSStatus(status); | |
| 442 | |
| 443 // Create and configure a SecTrustRef, which takes our certificate(s) | |
| 444 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an | |
| 445 // array of certificates, the first of which is the certificate we're | |
| 446 // verifying, and the subsequent (optional) certificates are used for | |
| 447 // chain building. | |
| 448 CFMutableArrayRef cert_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, | |
| 449 &kCFTypeArrayCallBacks); | |
| 450 if (!cert_array) | |
| 451 return ERR_OUT_OF_MEMORY; | |
| 452 scoped_cftyperef<CFArrayRef> scoped_cert_array(cert_array); | |
| 453 CFArrayAppendValue(cert_array, cert_handle_); | |
| 454 if (intermediate_ca_certs_) { | |
| 455 CFIndex intermediate_count = CFArrayGetCount(intermediate_ca_certs_); | |
| 456 for (CFIndex i = 0; i < intermediate_count; ++i) { | |
| 457 SecCertificateRef intermediate_cert = static_cast<SecCertificateRef>( | |
| 458 const_cast<void*>(CFArrayGetValueAtIndex(intermediate_ca_certs_, i))); | |
| 459 CFArrayAppendValue(cert_array, intermediate_cert); | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 SecTrustRef trust_ref = NULL; | |
| 464 status = SecTrustCreateWithCertificates(cert_array, ssl_policy, &trust_ref); | |
| 465 if (status) | |
| 466 return NetErrorFromOSStatus(status); | |
| 467 scoped_cftyperef<SecTrustRef> scoped_trust_ref(trust_ref); | |
| 468 | |
| 469 // Set the trusted anchor certificates for the SecTrustRef by merging the | |
|
wtc
2009/08/27 00:14:18
See if you can put this block of code (lines 469 -
| |
| 470 // system trust anchors and the test root certificate. | |
| 471 CFArrayRef anchor_array = | |
| 472 Singleton<MacTrustedCertificates>::get()->CopyTrustedCertificateArray(); | |
| 473 scoped_cftyperef<CFArrayRef> scoped_anchor_array(anchor_array); | |
| 474 if (anchor_array) { | |
| 475 status = SecTrustSetAnchorCertificates(trust_ref, anchor_array); | |
| 476 if (status) | |
| 477 return NetErrorFromOSStatus(status); | |
| 478 } | |
| 479 | |
| 480 if (flags & VERIFY_REV_CHECKING_ENABLED) { | |
| 481 // When called with VERIFY_REV_CHECKING_ENABLED, we ask SecTrustEvaluate() | |
| 482 // to apply OCSP and CRL checking, but we're still subject to the global | |
| 483 // settings, which are configured in the Keychain Access application (in | |
| 484 // the Certificates tab of the Preferences dialog). If the user has | |
| 485 // revocation disabled (which is the default), then we will get | |
| 486 // kSecTrustResultRecoverableTrustFailure back from SecTrustEvaluate() | |
| 487 // with one of a number of sub error codes indicating that revocation | |
| 488 // checking did not occur. In that case, we'll set our own result to include | |
| 489 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION (note that this does not apply | |
| 490 // to EV certificates, which always get revocation checks regardless of the | |
| 491 // global settings). | |
| 492 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | |
| 493 CSSM_APPLE_TP_ACTION_DATA tp_action_data = { CSSM_APPLE_TP_ACTION_VERSION }; | |
| 494 tp_action_data.ActionFlags = CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; | |
| 495 CFDataRef action_data_ref = | |
| 496 CFDataCreate(NULL, reinterpret_cast<UInt8*>(&tp_action_data), | |
| 497 sizeof(tp_action_data)); | |
| 498 if (!action_data_ref) | |
| 499 return ERR_OUT_OF_MEMORY; | |
| 500 scoped_cftyperef<CFDataRef> scoped_action_data_ref(action_data_ref); | |
| 501 status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT, | |
| 502 action_data_ref); | |
| 503 if (status) | |
| 504 return NetErrorFromOSStatus(status); | |
| 505 } else { | |
| 506 // EV requires revocation checking. | |
| 507 flags &= ~VERIFY_EV_CERT; | |
| 508 } | |
| 509 | |
| 510 // Verify the certificate. A non-zero result from SecTrustGetResult() | |
| 511 // indicates that some fatal error occurred and the chain couldn't be | |
| 512 // processed, not that the chain contains no errors. We need to examine the | |
| 513 // output of SecTrustGetResult() to determine that. | |
| 514 SecTrustResultType trust_result; | |
| 515 status = SecTrustEvaluate(trust_ref, &trust_result); | |
| 516 if (status) | |
| 517 return NetErrorFromOSStatus(status); | |
| 518 CFArrayRef completed_chain = NULL; | |
| 519 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info; | |
| 520 status = SecTrustGetResult(trust_ref, &trust_result, &completed_chain, | |
| 521 &chain_info); | |
| 522 if (status) | |
| 523 return NetErrorFromOSStatus(status); | |
| 524 scoped_cftyperef<CFArrayRef> scoped_completed_chain(completed_chain); | |
| 525 | |
| 526 // Evaluate the results | |
| 527 OSStatus cssm_result; | |
| 528 bool got_certificate_error = false; | |
| 529 switch (trust_result) { | |
| 530 case kSecTrustResultUnspecified: | |
| 531 case kSecTrustResultProceed: | |
| 532 // Certificate chain is valid and trusted ("unspecified" indicates that | |
| 533 // the user has not explicitly set a trust setting) | |
| 534 break; | |
| 535 | |
| 536 case kSecTrustResultDeny: | |
| 537 case kSecTrustResultConfirm: | |
| 538 // Certificate chain is explicitly untrusted. For kSecTrustResultConfirm, | |
| 539 // we're following what Secure Transport does and treating it as | |
| 540 // "deny". | |
| 541 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | |
| 542 break; | |
| 543 | |
| 544 case kSecTrustResultRecoverableTrustFailure: | |
| 545 // Certificate chain has a failure that can be overridden by the user. | |
| 546 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); | |
| 547 if (status) | |
| 548 return NetErrorFromOSStatus(status); | |
| 549 switch (cssm_result) { | |
| 550 case CSSMERR_TP_NOT_TRUSTED: | |
| 551 case CSSMERR_TP_INVALID_ANCHOR_CERT: | |
| 552 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | |
| 553 break; | |
| 554 case CSSMERR_TP_CERT_EXPIRED: | |
| 555 case CSSMERR_TP_CERT_NOT_VALID_YET: | |
| 556 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | |
| 557 break; | |
| 558 case CSSMERR_TP_CERT_REVOKED: | |
| 559 case CSSMERR_TP_CERT_SUSPENDED: | |
| 560 verify_result->cert_status |= CERT_STATUS_REVOKED; | |
| 561 break; | |
| 562 default: | |
| 563 // Look for specific per-certificate errors below. | |
| 564 break; | |
| 565 } | |
| 566 // Walk the chain of error codes in the CSSM_TP_APPLE_EVIDENCE_INFO | |
| 567 // structure which can catch multiple errors from each certificate. | |
| 568 for (CFIndex index = 0, chain_count = CFArrayGetCount(completed_chain); | |
| 569 index < chain_count; ++index) { | |
| 570 if (chain_info[index].StatusBits & CSSM_CERT_STATUS_EXPIRED || | |
| 571 chain_info[index].StatusBits & CSSM_CERT_STATUS_NOT_VALID_YET) | |
| 572 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | |
| 573 for (uint32 status_code_index = 0; | |
| 574 status_code_index < chain_info[index].NumStatusCodes; | |
| 575 ++status_code_index) { | |
| 576 got_certificate_error = true; | |
| 577 int cert_status = CertStatusFromOSStatus(cssm_result); | |
| 578 if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) { | |
| 579 std::vector<std::string> names; | |
| 580 GetDNSNames(&names); | |
|
wtc
2009/08/27 02:12:06
We should use only the common name in the subject
| |
| 581 if (OverrideHostnameMismatch(hostname, &names)) { | |
| 582 cert_status = 0; | |
| 583 } | |
| 584 } | |
| 585 verify_result->cert_status |= cert_status; | |
| 586 } | |
| 587 } | |
| 588 // Be paranoid and ensure that we recorded at least one certificate | |
| 589 // status on receiving kSecTrustResultRecoverableTrustFailure. The | |
| 590 // call to SecTrustGetCssmResultCode() should pick up when the chain | |
| 591 // is not trusted and the loop through CSSM_TP_APPLE_EVIDENCE_INFO | |
| 592 // should pick up everything else, but let's be safe. | |
| 593 if (!verify_result->cert_status && !got_certificate_error) { | |
| 594 verify_result->cert_status |= CERT_STATUS_INVALID; | |
| 595 NOTREACHED(); | |
| 596 } | |
| 597 break; | |
| 598 | |
| 599 default: | |
| 600 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); | |
| 601 if (status) | |
| 602 return NetErrorFromOSStatus(status); | |
| 603 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); | |
| 604 if (!verify_result->cert_status) { | |
| 605 verify_result->cert_status |= CERT_STATUS_INVALID; | |
| 606 } | |
| 607 break; | |
| 608 } | |
| 609 | |
| 610 if (IsCertStatusError(verify_result->cert_status)) | |
| 611 return MapCertStatusToNetError(verify_result->cert_status); | |
| 612 | |
| 613 if (flags & VERIFY_EV_CERT) { | |
| 614 // Determine the certificate's EV status using SecTrustCopyExtendedResult(), | |
| 615 // which we need to look up because the function wasn't added until | |
| 616 // Mac OS X 10.5.7. | |
| 617 CFBundleRef bundle = | |
| 618 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); | |
| 619 if (bundle) { | |
| 620 SecTrustCopyExtendedResultFuncPtr copy_extended_result = | |
| 621 reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>( | |
| 622 CFBundleGetFunctionPointerForName(bundle, | |
| 623 CFSTR("SecTrustCopyExtendedResult"))); | |
| 624 if (copy_extended_result) { | |
| 625 CFDictionaryRef ev_dict = NULL; | |
| 626 status = copy_extended_result(trust_ref, &ev_dict); | |
| 627 if (!status && ev_dict) { | |
| 628 // The returned dictionary contains the EV organization name from the | |
| 629 // server certificate, which we don't need at this point (and we | |
| 630 // have other ways to access, anyway). All we care is that | |
| 631 // SecTrustCopyExtendedResult() returned noErr and a non-NULL | |
| 632 // dictionary. | |
| 633 CFRelease(ev_dict); | |
| 634 verify_result->cert_status |= CERT_STATUS_IS_EV; | |
| 635 } | |
| 636 } | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 return OK; | |
| 641 } | |
| 642 | |
| 279 bool X509Certificate::VerifyEV() const { | 643 bool X509Certificate::VerifyEV() const { |
| 280 // TODO(avi): implement this | 644 // We don't call this private method, but we do need to implement it because |
| 281 NOTIMPLEMENTED(); | 645 // it's defined in x509_certificate.h. We perform EV checking in the |
| 646 // Verify() above. | |
| 647 NOTREACHED(); | |
| 282 return false; | 648 return false; |
| 283 } | 649 } |
| 284 | 650 |
| 651 void X509Certificate::AddIntermediateCertificate(SecCertificateRef cert) { | |
| 652 if (cert) { | |
| 653 if (!intermediate_ca_certs_) { | |
| 654 intermediate_ca_certs_ = CFArrayCreateMutable(kCFAllocatorDefault, 0, | |
| 655 &kCFTypeArrayCallBacks); | |
| 656 } | |
| 657 if (intermediate_ca_certs_) { | |
| 658 CFArrayAppendValue(intermediate_ca_certs_, cert); | |
| 659 } | |
| 660 } | |
| 661 } | |
| 662 | |
| 285 // static | 663 // static |
| 286 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | 664 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( |
| 287 const char* data, int length) { | 665 const char* data, int length) { |
| 288 CSSM_DATA cert_data; | 666 CSSM_DATA cert_data; |
| 289 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); | 667 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); |
| 290 cert_data.Length = length; | 668 cert_data.Length = length; |
| 291 | 669 |
| 292 OSCertHandle cert_handle = NULL; | 670 OSCertHandle cert_handle = NULL; |
| 293 OSStatus status = SecCertificateCreateFromData(&cert_data, | 671 OSStatus status = SecCertificateCreateFromData(&cert_data, |
| 294 CSSM_CERT_X_509v3, | 672 CSSM_CERT_X_509v3, |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 318 | 696 |
| 319 DCHECK(NULL != cert_data.Data); | 697 DCHECK(NULL != cert_data.Data); |
| 320 DCHECK(0 != cert_data.Length); | 698 DCHECK(0 != cert_data.Length); |
| 321 | 699 |
| 322 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); | 700 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); |
| 323 | 701 |
| 324 return sha1; | 702 return sha1; |
| 325 } | 703 } |
| 326 | 704 |
| 327 } // namespace net | 705 } // namespace net |
| OLD | NEW |