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 |