| 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 <Security/Security.h> |
| 9 #include <time.h> | 9 #include <time.h> |
| 10 | 10 |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/pickle.h" | 12 #include "base/pickle.h" |
| 13 #include "base/scoped_cftyperef.h" | 13 #include "base/scoped_cftyperef.h" |
| 14 #include "base/sys_string_conversions.h" | 14 #include "base/sys_string_conversions.h" |
| 15 #include "net/base/cert_status_flags.h" | |
| 16 #include "net/base/cert_verify_result.h" | |
| 17 #include "net/base/net_errors.h" | |
| 18 | 15 |
| 19 using base::Time; | 16 using base::Time; |
| 20 | 17 |
| 21 namespace net { | 18 namespace net { |
| 22 | 19 |
| 23 class MacTrustedCertificates { | |
| 24 public: | |
| 25 // Sets the trusted root certificate used by tests. Call with |cert| set | |
| 26 // to NULL to clear the test certificate. | |
| 27 void SetTestCertificate(X509Certificate* cert) { | |
| 28 AutoLock lock(lock_); | |
| 29 test_certificate_ = cert; | |
| 30 } | |
| 31 | |
| 32 // Returns an array containing the trusted certificates for use with | |
| 33 // SecTrustSetAnchorCertificates(). Returns NULL if the system-supplied | |
| 34 // list of trust anchors is acceptable (that is, there is not test | |
| 35 // certificate available). Ownership follows the Create Rule (caller | |
| 36 // is responsible for calling CFRelease on the non-NULL result). | |
| 37 CFArrayRef CopyTrustedCertificateArray() { | |
| 38 AutoLock lock(lock_); | |
| 39 | |
| 40 if (!test_certificate_) | |
| 41 return NULL; | |
| 42 | |
| 43 // Failure to copy the anchor certificates or add the test certificate | |
| 44 // is non-fatal; SecTrustEvaluate() will use the system anchors instead. | |
| 45 CFArrayRef anchor_array; | |
| 46 OSStatus status = SecTrustCopyAnchorCertificates(&anchor_array); | |
| 47 if (status) | |
| 48 return NULL; | |
| 49 scoped_cftyperef<CFArrayRef> scoped_anchor_array(anchor_array); | |
| 50 CFMutableArrayRef merged_array = CFArrayCreateMutableCopy( | |
| 51 kCFAllocatorDefault, 0, anchor_array); | |
| 52 if (!merged_array) | |
| 53 return NULL; | |
| 54 CFArrayAppendValue(merged_array, test_certificate_->os_cert_handle()); | |
| 55 | |
| 56 return merged_array; | |
| 57 } | |
| 58 private: | |
| 59 friend struct DefaultSingletonTraits<MacTrustedCertificates>; | |
| 60 | |
| 61 // Obtain an instance of MacTrustedCertificates via the singleton | |
| 62 // interface. | |
| 63 MacTrustedCertificates() : test_certificate_(NULL) { } | |
| 64 | |
| 65 // An X509Certificate object that may be appended to the list of | |
| 66 // system trusted anchors. | |
| 67 scoped_refptr<X509Certificate> test_certificate_; | |
| 68 | |
| 69 // The trusted cache may be accessed from multiple threads. | |
| 70 mutable Lock lock_; | |
| 71 | |
| 72 DISALLOW_COPY_AND_ASSIGN(MacTrustedCertificates); | |
| 73 }; | |
| 74 | |
| 75 void SetMacTestCertificate(X509Certificate* cert) { | |
| 76 Singleton<MacTrustedCertificates>::get()->SetTestCertificate(cert); | |
| 77 } | |
| 78 | |
| 79 namespace { | 20 namespace { |
| 80 | |
| 81 typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef, | |
| 82 CFDictionaryRef*); | |
| 83 | |
| 84 int NetErrorFromOSStatus(OSStatus status) { | |
| 85 switch (status) { | |
| 86 case noErr: | |
| 87 return OK; | |
| 88 case errSecNotAvailable: | |
| 89 case errSecNoCertificateModule: | |
| 90 case errSecNoPolicyModule: | |
| 91 return ERR_NOT_IMPLEMENTED; | |
| 92 case errSecAuthFailed: | |
| 93 return ERR_ACCESS_DENIED; | |
| 94 default: | |
| 95 LOG(ERROR) << "Unknown error " << status << " mapped to net::ERR_FAILED"; | |
| 96 return ERR_FAILED; | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 int CertStatusFromOSStatus(OSStatus status) { | |
| 101 switch (status) { | |
| 102 case noErr: | |
| 103 return 0; | |
| 104 | |
| 105 case CSSMERR_TP_INVALID_ANCHOR_CERT: | |
| 106 case CSSMERR_TP_NOT_TRUSTED: | |
| 107 case CSSMERR_TP_INVALID_CERT_AUTHORITY: | |
| 108 return CERT_STATUS_AUTHORITY_INVALID; | |
| 109 | |
| 110 case CSSMERR_TP_CERT_EXPIRED: | |
| 111 case CSSMERR_TP_CERT_NOT_VALID_YET: | |
| 112 // "Expired" and "not yet valid" collapse into a single status. | |
| 113 return CERT_STATUS_DATE_INVALID; | |
| 114 | |
| 115 case CSSMERR_TP_CERT_REVOKED: | |
| 116 case CSSMERR_TP_CERT_SUSPENDED: | |
| 117 return CERT_STATUS_REVOKED; | |
| 118 | |
| 119 case CSSMERR_APPLETP_HOSTNAME_MISMATCH: | |
| 120 return CERT_STATUS_COMMON_NAME_INVALID; | |
| 121 | |
| 122 case CSSMERR_APPLETP_CRL_NOT_FOUND: | |
| 123 case CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK: | |
| 124 case CSSMERR_APPLETP_OCSP_UNAVAILABLE: | |
| 125 return CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 126 | |
| 127 case CSSMERR_APPLETP_CRL_NOT_TRUSTED: | |
| 128 case CSSMERR_APPLETP_CRL_SERVER_DOWN: | |
| 129 case CSSMERR_APPLETP_CRL_NOT_VALID_YET: | |
| 130 case CSSMERR_APPLETP_NETWORK_FAILURE: | |
| 131 case CSSMERR_APPLETP_OCSP_BAD_RESPONSE: | |
| 132 case CSSMERR_APPLETP_OCSP_NO_SIGNER: | |
| 133 case CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED: | |
| 134 case CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED: | |
| 135 case CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ: | |
| 136 case CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR: | |
| 137 case CSSMERR_APPLETP_OCSP_RESP_TRY_LATER: | |
| 138 // We asked for a revocation check, but didn't get it. | |
| 139 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
| 140 | |
| 141 default: | |
| 142 // Failure was due to something Chromium doesn't define a | |
| 143 // specific status for (such as basic constraints violation, or | |
| 144 // unknown critical extension) | |
| 145 return CERT_STATUS_INVALID; | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 bool OverrideHostnameMismatch(const std::string& hostname, | |
| 150 std::vector<std::string>* dns_names) { | |
| 151 // SecTrustEvaluate() does not check dotted IP addresses. If | |
| 152 // hostname is provided as, say, 127.0.0.1, then the error | |
| 153 // CSSMERR_APPLETP_HOSTNAME_MISMATCH will always be returned, | |
| 154 // even if the certificate contains 127.0.0.1 as one of its names. | |
| 155 // We, however, want to allow that behavior. SecTrustEvaluate() | |
| 156 // only checks for digits and dots when considering whether a | |
| 157 // hostname is an IP address, so IPv6 and hex addresses go through | |
| 158 // its normal comparison. | |
| 159 bool is_dotted_ip = true; | |
| 160 bool override_hostname_mismatch = false; | |
| 161 for (std::string::const_iterator c = hostname.begin(); | |
| 162 c != hostname.end() && is_dotted_ip; ++c) | |
| 163 is_dotted_ip = (*c >= '0' && *c <= '9') || *c == '.'; | |
| 164 if (is_dotted_ip) { | |
| 165 for (std::vector<std::string>::const_iterator name = dns_names->begin(); | |
| 166 name != dns_names->end() && !override_hostname_mismatch; ++name) | |
| 167 override_hostname_mismatch = (*name == hostname); | |
| 168 } | |
| 169 return override_hostname_mismatch; | |
| 170 } | |
| 171 | |
| 172 struct CSSMFields { | 21 struct CSSMFields { |
| 173 CSSMFields() : cl_handle(NULL), num_of_fields(0), fields(NULL) {} | 22 CSSMFields() : cl_handle(NULL), num_of_fields(0), fields(NULL) {} |
| 174 ~CSSMFields() { | 23 ~CSSMFields() { |
| 175 if (cl_handle) | 24 if (cl_handle) |
| 176 CSSM_CL_FreeFields(cl_handle, num_of_fields, &fields); | 25 CSSM_CL_FreeFields(cl_handle, num_of_fields, &fields); |
| 177 } | 26 } |
| 178 | 27 |
| 179 CSSM_CL_HANDLE cl_handle; | 28 CSSM_CL_HANDLE cl_handle; |
| 180 uint32 num_of_fields; | 29 uint32 num_of_fields; |
| 181 CSSM_FIELD_PTR fields; | 30 CSSM_FIELD_PTR fields; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 exploded.minute = time.tm_min; | 137 exploded.minute = time.tm_min; |
| 289 exploded.second = time.tm_sec; | 138 exploded.second = time.tm_sec; |
| 290 exploded.millisecond = 0; | 139 exploded.millisecond = 0; |
| 291 | 140 |
| 292 *result = Time::FromUTCExploded(exploded); | 141 *result = Time::FromUTCExploded(exploded); |
| 293 break; | 142 break; |
| 294 } | 143 } |
| 295 } | 144 } |
| 296 } | 145 } |
| 297 | 146 |
| 147 // Serializes the |cert_handle| into |pickle|, such that it may be unserialized |
| 148 // by ReadCertHandleFromPickle(). Returns FALSE on failure. |
| 149 bool WriteCertHandleToPickle(X509Certificate::OSCertHandle cert_handle, |
| 150 Pickle* pickle) { |
| 151 CSSM_DATA cert_data; |
| 152 OSStatus status = SecCertificateGetData(cert_handle, &cert_data); |
| 153 if (status) { |
| 154 return false; |
| 155 } |
| 156 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), |
| 157 cert_data.Length); |
| 158 } |
| 159 |
| 160 // Reads a previously serialized OSCertHandle from the specified |pickle|. If |
| 161 // an error is encountered, returns NULL. |
| 162 SecCertificateRef ReadCertHandleFromPickle(const Pickle& pickle, |
| 163 void** pickle_iter) { |
| 164 const char* data; |
| 165 int length; |
| 166 if (!pickle.ReadData(pickle_iter, &data, &length)) |
| 167 return NULL; |
| 168 |
| 169 return X509Certificate::CreateOSCertHandleFromBytes(data, length); |
| 170 } |
| 171 |
| 298 // Creates a SecPolicyRef for the given OID, with optional value. | 172 // Creates a SecPolicyRef for the given OID, with optional value. |
| 299 OSStatus CreatePolicy(const CSSM_OID* policy_OID, | 173 OSStatus CreatePolicy(const CSSM_OID* policy_OID, |
| 300 void* option_data, | 174 void* option_data, |
| 301 size_t option_length, | 175 size_t option_length, |
| 302 SecPolicyRef* policy) { | 176 SecPolicyRef* policy) { |
| 303 SecPolicySearchRef search; | 177 SecPolicySearchRef search; |
| 304 OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_OID, NULL, | 178 OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_OID, NULL, |
| 305 &search); | 179 &search); |
| 306 if (err) | 180 if (err) |
| 307 return err; | 181 return err; |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 return NULL; | 353 return NULL; |
| 480 | 354 |
| 481 CFArrayAppendValue(cert_list, cert_handle_); | 355 CFArrayAppendValue(cert_list, cert_handle_); |
| 482 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { | 356 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) { |
| 483 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); | 357 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]); |
| 484 } | 358 } |
| 485 | 359 |
| 486 return cert_list; | 360 return cert_list; |
| 487 } | 361 } |
| 488 | 362 |
| 489 int X509Certificate::Verify(const std::string& hostname, int flags, | |
| 490 CertVerifyResult* verify_result) const { | |
| 491 verify_result->Reset(); | |
| 492 | |
| 493 // Create an SSL SecPolicyRef, and configure it to perform hostname | |
| 494 // validation. The hostname check does 99% of what we want, with the | |
| 495 // exception of dotted IPv4 addreses, which we handle ourselves below. | |
| 496 CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = { | |
| 497 CSSM_APPLE_TP_SSL_OPTS_VERSION, | |
| 498 hostname.size(), | |
| 499 hostname.data(), | |
| 500 0 | |
| 501 }; | |
| 502 SecPolicyRef ssl_policy; | |
| 503 OSStatus status = CreatePolicy(&CSSMOID_APPLE_TP_SSL, | |
| 504 &tp_ssl_options, | |
| 505 sizeof(tp_ssl_options), | |
| 506 &ssl_policy); | |
| 507 if (status) | |
| 508 return NetErrorFromOSStatus(status); | |
| 509 scoped_cftyperef<SecPolicyRef> scoped_ssl_policy(ssl_policy); | |
| 510 | |
| 511 // Create and configure a SecTrustRef, which takes our certificate(s) | |
| 512 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an | |
| 513 // array of certificates, the first of which is the certificate we're | |
| 514 // verifying, and the subsequent (optional) certificates are used for | |
| 515 // chain building. | |
| 516 scoped_cftyperef<CFArrayRef> cert_list(CreateOSCertListHandle()); | |
| 517 | |
| 518 // From here on, only one thread can be active at a time. We have had a number | |
| 519 // of sporadic crashes in the SecTrustEvaluate call below, way down inside | |
| 520 // Apple's cert code, which we suspect are caused by a thread-safety issue. | |
| 521 // So as a speculative fix allow only one thread to use SecTrust on this cert. | |
| 522 AutoLock lock(verification_lock_); | |
| 523 | |
| 524 SecTrustRef trust_ref = NULL; | |
| 525 status = SecTrustCreateWithCertificates(cert_list, ssl_policy, &trust_ref); | |
| 526 if (status) | |
| 527 return NetErrorFromOSStatus(status); | |
| 528 scoped_cftyperef<SecTrustRef> scoped_trust_ref(trust_ref); | |
| 529 | |
| 530 // Set the trusted anchor certificates for the SecTrustRef by merging the | |
| 531 // system trust anchors and the test root certificate. | |
| 532 CFArrayRef anchor_array = | |
| 533 Singleton<MacTrustedCertificates>::get()->CopyTrustedCertificateArray(); | |
| 534 scoped_cftyperef<CFArrayRef> scoped_anchor_array(anchor_array); | |
| 535 if (anchor_array) { | |
| 536 status = SecTrustSetAnchorCertificates(trust_ref, anchor_array); | |
| 537 if (status) | |
| 538 return NetErrorFromOSStatus(status); | |
| 539 } | |
| 540 | |
| 541 if (flags & VERIFY_REV_CHECKING_ENABLED) { | |
| 542 // When called with VERIFY_REV_CHECKING_ENABLED, we ask SecTrustEvaluate() | |
| 543 // to apply OCSP and CRL checking, but we're still subject to the global | |
| 544 // settings, which are configured in the Keychain Access application (in | |
| 545 // the Certificates tab of the Preferences dialog). If the user has | |
| 546 // revocation disabled (which is the default), then we will get | |
| 547 // kSecTrustResultRecoverableTrustFailure back from SecTrustEvaluate() | |
| 548 // with one of a number of sub error codes indicating that revocation | |
| 549 // checking did not occur. In that case, we'll set our own result to include | |
| 550 // CERT_STATUS_UNABLE_TO_CHECK_REVOCATION. | |
| 551 // | |
| 552 // NOTE: This does not apply to EV certificates, which always get | |
| 553 // revocation checks regardless of the global settings. | |
| 554 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | |
| 555 CSSM_APPLE_TP_ACTION_DATA tp_action_data = { CSSM_APPLE_TP_ACTION_VERSION }; | |
| 556 tp_action_data.ActionFlags = CSSM_TP_ACTION_REQUIRE_REV_PER_CERT; | |
| 557 CFDataRef action_data_ref = | |
| 558 CFDataCreate(NULL, reinterpret_cast<UInt8*>(&tp_action_data), | |
| 559 sizeof(tp_action_data)); | |
| 560 if (!action_data_ref) | |
| 561 return ERR_OUT_OF_MEMORY; | |
| 562 scoped_cftyperef<CFDataRef> scoped_action_data_ref(action_data_ref); | |
| 563 status = SecTrustSetParameters(trust_ref, CSSM_TP_ACTION_DEFAULT, | |
| 564 action_data_ref); | |
| 565 if (status) | |
| 566 return NetErrorFromOSStatus(status); | |
| 567 } | |
| 568 | |
| 569 // Verify the certificate. A non-zero result from SecTrustGetResult() | |
| 570 // indicates that some fatal error occurred and the chain couldn't be | |
| 571 // processed, not that the chain contains no errors. We need to examine the | |
| 572 // output of SecTrustGetResult() to determine that. | |
| 573 SecTrustResultType trust_result; | |
| 574 status = SecTrustEvaluate(trust_ref, &trust_result); | |
| 575 if (status) | |
| 576 return NetErrorFromOSStatus(status); | |
| 577 CFArrayRef completed_chain = NULL; | |
| 578 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info; | |
| 579 status = SecTrustGetResult(trust_ref, &trust_result, &completed_chain, | |
| 580 &chain_info); | |
| 581 if (status) | |
| 582 return NetErrorFromOSStatus(status); | |
| 583 scoped_cftyperef<CFArrayRef> scoped_completed_chain(completed_chain); | |
| 584 | |
| 585 // Evaluate the results | |
| 586 OSStatus cssm_result; | |
| 587 bool got_certificate_error = false; | |
| 588 switch (trust_result) { | |
| 589 case kSecTrustResultUnspecified: | |
| 590 case kSecTrustResultProceed: | |
| 591 // Certificate chain is valid and trusted ("unspecified" indicates that | |
| 592 // the user has not explicitly set a trust setting) | |
| 593 break; | |
| 594 | |
| 595 case kSecTrustResultDeny: | |
| 596 case kSecTrustResultConfirm: | |
| 597 // Certificate chain is explicitly untrusted. For kSecTrustResultConfirm, | |
| 598 // we're following what Secure Transport does and treating it as | |
| 599 // "deny". | |
| 600 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | |
| 601 break; | |
| 602 | |
| 603 case kSecTrustResultRecoverableTrustFailure: | |
| 604 // Certificate chain has a failure that can be overridden by the user. | |
| 605 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); | |
| 606 if (status) | |
| 607 return NetErrorFromOSStatus(status); | |
| 608 switch (cssm_result) { | |
| 609 case CSSMERR_TP_NOT_TRUSTED: | |
| 610 case CSSMERR_TP_INVALID_ANCHOR_CERT: | |
| 611 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | |
| 612 break; | |
| 613 case CSSMERR_TP_CERT_EXPIRED: | |
| 614 case CSSMERR_TP_CERT_NOT_VALID_YET: | |
| 615 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | |
| 616 break; | |
| 617 case CSSMERR_TP_CERT_REVOKED: | |
| 618 case CSSMERR_TP_CERT_SUSPENDED: | |
| 619 verify_result->cert_status |= CERT_STATUS_REVOKED; | |
| 620 break; | |
| 621 default: | |
| 622 // Look for specific per-certificate errors below. | |
| 623 break; | |
| 624 } | |
| 625 // Walk the chain of error codes in the CSSM_TP_APPLE_EVIDENCE_INFO | |
| 626 // structure which can catch multiple errors from each certificate. | |
| 627 for (CFIndex index = 0, chain_count = CFArrayGetCount(completed_chain); | |
| 628 index < chain_count; ++index) { | |
| 629 if (chain_info[index].StatusBits & CSSM_CERT_STATUS_EXPIRED || | |
| 630 chain_info[index].StatusBits & CSSM_CERT_STATUS_NOT_VALID_YET) | |
| 631 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | |
| 632 for (uint32 status_code_index = 0; | |
| 633 status_code_index < chain_info[index].NumStatusCodes; | |
| 634 ++status_code_index) { | |
| 635 got_certificate_error = true; | |
| 636 int cert_status = CertStatusFromOSStatus( | |
| 637 chain_info[index].StatusCodes[status_code_index]); | |
| 638 if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) { | |
| 639 std::vector<std::string> names; | |
| 640 GetDNSNames(&names); | |
| 641 if (OverrideHostnameMismatch(hostname, &names)) { | |
| 642 cert_status = 0; | |
| 643 } | |
| 644 } | |
| 645 verify_result->cert_status |= cert_status; | |
| 646 } | |
| 647 } | |
| 648 // Be paranoid and ensure that we recorded at least one certificate | |
| 649 // status on receiving kSecTrustResultRecoverableTrustFailure. The | |
| 650 // call to SecTrustGetCssmResultCode() should pick up when the chain | |
| 651 // is not trusted and the loop through CSSM_TP_APPLE_EVIDENCE_INFO | |
| 652 // should pick up everything else, but let's be safe. | |
| 653 if (!verify_result->cert_status && !got_certificate_error) { | |
| 654 verify_result->cert_status |= CERT_STATUS_INVALID; | |
| 655 NOTREACHED(); | |
| 656 } | |
| 657 break; | |
| 658 | |
| 659 default: | |
| 660 status = SecTrustGetCssmResultCode(trust_ref, &cssm_result); | |
| 661 if (status) | |
| 662 return NetErrorFromOSStatus(status); | |
| 663 verify_result->cert_status |= CertStatusFromOSStatus(cssm_result); | |
| 664 if (!verify_result->cert_status) { | |
| 665 verify_result->cert_status |= CERT_STATUS_INVALID; | |
| 666 } | |
| 667 break; | |
| 668 } | |
| 669 | |
| 670 // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be | |
| 671 // compatible with Windows, which in turn implements this behavior to be | |
| 672 // compatible with WinHTTP, which doesn't report this error (bug 3004). | |
| 673 verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 674 | |
| 675 if (IsCertStatusError(verify_result->cert_status)) | |
| 676 return MapCertStatusToNetError(verify_result->cert_status); | |
| 677 | |
| 678 if (flags & VERIFY_EV_CERT) { | |
| 679 // Determine the certificate's EV status using SecTrustCopyExtendedResult(), | |
| 680 // which we need to look up because the function wasn't added until | |
| 681 // Mac OS X 10.5.7. | |
| 682 CFBundleRef bundle = | |
| 683 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")); | |
| 684 if (bundle) { | |
| 685 SecTrustCopyExtendedResultFuncPtr copy_extended_result = | |
| 686 reinterpret_cast<SecTrustCopyExtendedResultFuncPtr>( | |
| 687 CFBundleGetFunctionPointerForName(bundle, | |
| 688 CFSTR("SecTrustCopyExtendedResult"))); | |
| 689 if (copy_extended_result) { | |
| 690 CFDictionaryRef ev_dict = NULL; | |
| 691 status = copy_extended_result(trust_ref, &ev_dict); | |
| 692 if (!status && ev_dict) { | |
| 693 // The returned dictionary contains the EV organization name from the | |
| 694 // server certificate, which we don't need at this point (and we | |
| 695 // have other ways to access, anyway). All we care is that | |
| 696 // SecTrustCopyExtendedResult() returned noErr and a non-NULL | |
| 697 // dictionary. | |
| 698 CFRelease(ev_dict); | |
| 699 verify_result->cert_status |= CERT_STATUS_IS_EV; | |
| 700 } | |
| 701 } | |
| 702 } | |
| 703 } | |
| 704 | |
| 705 return OK; | |
| 706 } | |
| 707 | |
| 708 bool X509Certificate::VerifyEV() const { | |
| 709 // We don't call this private method, but we do need to implement it because | |
| 710 // it's defined in x509_certificate.h. We perform EV checking in the | |
| 711 // Verify() above. | |
| 712 NOTREACHED(); | |
| 713 return false; | |
| 714 } | |
| 715 | |
| 716 // static | 363 // static |
| 717 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, | 364 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, |
| 718 X509Certificate::OSCertHandle b) { | 365 X509Certificate::OSCertHandle b) { |
| 719 DCHECK(a && b); | 366 DCHECK(a && b); |
| 720 if (a == b) | 367 if (a == b) |
| 721 return true; | 368 return true; |
| 722 if (CFEqual(a, b)) | 369 if (CFEqual(a, b)) |
| 723 return true; | 370 return true; |
| 724 CSSM_DATA a_data, b_data; | 371 CSSM_DATA a_data, b_data; |
| 725 return SecCertificateGetData(a, &a_data) == noErr && | 372 return SecCertificateGetData(a, &a_data) == noErr && |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1015 } | 662 } |
| 1016 CFRelease(cert_chain); | 663 CFRelease(cert_chain); |
| 1017 } | 664 } |
| 1018 exit: | 665 exit: |
| 1019 if (result) | 666 if (result) |
| 1020 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; | 667 LOG(ERROR) << "CreateIdentityCertificateChain error " << result; |
| 1021 return chain.release(); | 668 return chain.release(); |
| 1022 } | 669 } |
| 1023 | 670 |
| 1024 } // namespace net | 671 } // namespace net |
| OLD | NEW |