Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Side by Side Diff: net/cert/cert_verify_proc_mac.cc

Issue 1094983002: Account for the OS returning an empty certificate chain. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: test, somewhat tidier code Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/cert/cert_verify_proc.h ('k') | net/cert/cert_verify_proc_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/cert/cert_verify_proc_mac.h" 5 #include "net/cert/cert_verify_proc_mac.h"
6 6
7 #include <CommonCrypto/CommonDigest.h> 7 #include <CommonCrypto/CommonDigest.h>
8 #include <CoreServices/CoreServices.h> 8 #include <CoreServices/CoreServices.h>
9 #include <Security/Security.h> 9 #include <Security/Security.h>
10 10
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY), 169 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY),
170 local_policies); 170 local_policies);
171 if (status) 171 if (status)
172 return status; 172 return status;
173 173
174 policies->reset(local_policies.release()); 174 policies->reset(local_policies.release());
175 return noErr; 175 return noErr;
176 } 176 }
177 177
178 // Stores the constructed certificate chain |cert_chain| and information about 178 // Stores the constructed certificate chain |cert_chain| and information about
179 // the signature algorithms used into |*verify_result|. If the leaf cert in 179 // the signature algorithms used into |*verify_result|. |cert_chain| must not be
180 // |cert_chain| contains a weak (MD2, MD4, MD5, SHA-1) signature, stores that 180 // empty.
181 // in |*leaf_is_weak|.
182 void GetCertChainInfo(CFArrayRef cert_chain, 181 void GetCertChainInfo(CFArrayRef cert_chain,
183 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info, 182 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info,
184 CertVerifyResult* verify_result, 183 CertVerifyResult* verify_result) {
185 bool* leaf_is_weak) { 184 DCHECK_LT(0, CFArrayGetCount(cert_chain));
186 *leaf_is_weak = false; 185
187 verify_result->verified_cert = nullptr;
188 verify_result->has_md2 = false; 186 verify_result->has_md2 = false;
189 verify_result->has_md4 = false; 187 verify_result->has_md4 = false;
190 verify_result->has_md5 = false; 188 verify_result->has_md5 = false;
191 verify_result->has_sha1 = false; 189 verify_result->has_sha1 = false;
192 190
193 SecCertificateRef verified_cert = NULL; 191 SecCertificateRef verified_cert = NULL;
194 std::vector<SecCertificateRef> verified_chain; 192 std::vector<SecCertificateRef> verified_chain;
195 for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) { 193 for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) {
196 SecCertificateRef chain_cert = reinterpret_cast<SecCertificateRef>( 194 SecCertificateRef chain_cert = reinterpret_cast<SecCertificateRef>(
197 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); 195 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i)));
(...skipping 27 matching lines...) Expand all
225 // OS X certificate library, but based on history, it is best to play it 223 // OS X certificate library, but based on history, it is best to play it
226 // safe. 224 // safe.
227 const CSSM_X509_ALGORITHM_IDENTIFIER* sig_algorithm = 225 const CSSM_X509_ALGORITHM_IDENTIFIER* sig_algorithm =
228 signature_field.GetAs<CSSM_X509_ALGORITHM_IDENTIFIER>(); 226 signature_field.GetAs<CSSM_X509_ALGORITHM_IDENTIFIER>();
229 if (!sig_algorithm) 227 if (!sig_algorithm)
230 continue; 228 continue;
231 229
232 const CSSM_OID* alg_oid = &sig_algorithm->algorithm; 230 const CSSM_OID* alg_oid = &sig_algorithm->algorithm;
233 if (CSSMOIDEqual(alg_oid, &CSSMOID_MD2WithRSA)) { 231 if (CSSMOIDEqual(alg_oid, &CSSMOID_MD2WithRSA)) {
234 verify_result->has_md2 = true; 232 verify_result->has_md2 = true;
235 if (i == 0)
236 *leaf_is_weak = true;
237 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD4WithRSA)) { 233 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD4WithRSA)) {
238 verify_result->has_md4 = true; 234 verify_result->has_md4 = true;
239 if (i == 0)
240 *leaf_is_weak = true;
241 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD5WithRSA)) { 235 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD5WithRSA)) {
242 verify_result->has_md5 = true; 236 verify_result->has_md5 = true;
243 if (i == 0)
244 *leaf_is_weak = true;
245 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA) || 237 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA) ||
246 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA_OIW) || 238 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA_OIW) ||
247 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA) || 239 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA) ||
248 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_CMS) || 240 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_CMS) ||
249 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_JDK) || 241 CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_JDK) ||
250 CSSMOIDEqual(alg_oid, &CSSMOID_ECDSA_WithSHA1)) { 242 CSSMOIDEqual(alg_oid, &CSSMOID_ECDSA_WithSHA1)) {
251 verify_result->has_sha1 = true; 243 verify_result->has_sha1 = true;
252 if (i == 0)
253 *leaf_is_weak = true;
254 } 244 }
255 } 245 }
256 if (!verified_cert) 246 if (!verified_cert) {
247 NOTREACHED();
257 return; 248 return;
249 }
258 250
259 verify_result->verified_cert = 251 verify_result->verified_cert =
260 X509Certificate::CreateFromHandle(verified_cert, verified_chain); 252 X509Certificate::CreateFromHandle(verified_cert, verified_chain);
261 } 253 }
262 254
263 void AppendPublicKeyHashes(CFArrayRef chain, 255 void AppendPublicKeyHashes(CFArrayRef chain,
264 HashValueVector* hashes) { 256 HashValueVector* hashes) {
265 const CFIndex n = CFArrayGetCount(chain); 257 const CFIndex n = CFArrayGetCount(chain);
266 for (CFIndex i = 0; i < n; i++) { 258 for (CFIndex i = 0; i < n; i++) {
267 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>( 259 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 SecTrustResultType temp_trust_result = kSecTrustResultDeny; 546 SecTrustResultType temp_trust_result = kSecTrustResultDeny;
555 ScopedCFTypeRef<CFArrayRef> temp_chain; 547 ScopedCFTypeRef<CFArrayRef> temp_chain;
556 CSSM_TP_APPLE_EVIDENCE_INFO* temp_chain_info = NULL; 548 CSSM_TP_APPLE_EVIDENCE_INFO* temp_chain_info = NULL;
557 549
558 int rv = BuildAndEvaluateSecTrustRef(cert_array, trust_policies, flags, 550 int rv = BuildAndEvaluateSecTrustRef(cert_array, trust_policies, flags,
559 &temp_ref, &temp_trust_result, 551 &temp_ref, &temp_trust_result,
560 &temp_chain, &temp_chain_info); 552 &temp_chain, &temp_chain_info);
561 if (rv != OK) 553 if (rv != OK)
562 return rv; 554 return rv;
563 555
564 CertVerifyResult temp_verify_result;
565 bool leaf_is_weak = false;
566 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result,
567 &leaf_is_weak);
568
569 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && 556 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified &&
570 temp_trust_result != kSecTrustResultProceed); 557 temp_trust_result != kSecTrustResultProceed);
571 bool weak_chain = 558 bool weak_chain = false;
572 !leaf_is_weak && 559 if (CFArrayGetCount(cert_array) > 0) {
573 (temp_verify_result.has_md2 || temp_verify_result.has_md4 || 560 CertVerifyResult temp_verify_result;
574 temp_verify_result.has_md5 || temp_verify_result.has_sha1); 561 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result);
562 weak_chain = temp_verify_result.has_md2 || temp_verify_result.has_md4 ||
563 temp_verify_result.has_md5 || temp_verify_result.has_sha1;
564 } else {
565 // If the chain is trusted or has recoverable errors, it cannot be empty.
566 DCHECK(untrusted);
567 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result);
568 }
575 // Set the result to the current chain if: 569 // Set the result to the current chain if:
576 // - This is the first verification attempt. This ensures that if 570 // - This is the first verification attempt. This ensures that if
577 // everything is awful (e.g. it may just be an untrusted cert), that 571 // everything is awful (e.g. it may just be an untrusted cert), that
578 // what is reported is exactly what was sent by the server 572 // what is reported is exactly what was sent by the server
579 // - If the current chain is trusted, and the old chain was not trusted, 573 // - If the current chain is trusted, and the old chain was not trusted,
580 // then prefer this chain. This ensures that if there is at least a 574 // then prefer this chain. This ensures that if there is at least a
581 // valid path to a trust anchor, it's preferred over reporting an error. 575 // valid path to a trust anchor, it's preferred over reporting an error.
582 // - If the current chain is trusted, and the old chain is trusted, but 576 // - If the current chain is trusted, and the old chain is trusted, but
583 // the old chain contained weak algorithms while the current chain only 577 // the old chain contained weak algorithms while the current chain only
584 // contains strong algorithms, then prefer the current chain over the 578 // contains strong algorithms, then prefer the current chain over the
585 // old chain. 579 // old chain.
586 //
587 // Note: If the leaf certificate itself is weak, then the only
588 // consideration is whether or not there is a trusted chain. That's
589 // because no amount of path discovery will fix a weak leaf.
Ryan Sleevi 2015/04/23 00:30:50 This is a bug that we _aren't_ exiting this loop a
590 if (!trust_ref || (!untrusted && (candidate_untrusted || 580 if (!trust_ref || (!untrusted && (candidate_untrusted ||
591 (candidate_weak && !weak_chain)))) { 581 (candidate_weak && !weak_chain)))) {
592 trust_ref = temp_ref; 582 trust_ref = temp_ref;
593 trust_result = temp_trust_result; 583 trust_result = temp_trust_result;
594 completed_chain = temp_chain; 584 completed_chain = temp_chain;
595 chain_info = temp_chain_info; 585 chain_info = temp_chain_info;
596 586
597 candidate_untrusted = untrusted; 587 candidate_untrusted = untrusted;
598 candidate_weak = weak_chain; 588 candidate_weak = weak_chain;
599 } 589 }
600 // Short-circuit when a current, trusted chain is found. 590 // Short-circuit when a current, trusted chain is found.
601 if (!untrusted && !weak_chain) 591 if (!untrusted && !weak_chain)
Ryan Sleevi 2015/04/23 00:30:50 This is the bug. It should have been if (!untrust
602 break; 592 break;
603 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1); 593 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1);
604 } 594 }
605 595
606 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) 596 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED)
607 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; 597 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
608 598
609 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set)) 599 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set))
610 verify_result->cert_status |= CERT_STATUS_REVOKED; 600 verify_result->cert_status |= CERT_STATUS_REVOKED;
611 601
612 bool leaf_is_weak_unused = false; 602 if (CFArrayGetCount(completed_chain) > 0)
613 GetCertChainInfo(completed_chain, chain_info, verify_result, 603 GetCertChainInfo(completed_chain, chain_info, verify_result);
614 &leaf_is_weak_unused);
615 604
616 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits 605 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits
617 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds 606 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds
618 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping 607 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping
619 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only 608 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only
620 // error was due to an unsupported key size. 609 // error was due to an unsupported key size.
621 bool policy_failed = false; 610 bool policy_failed = false;
622 bool weak_key_or_signature_algorithm = false; 611 bool weak_key_or_signature_algorithm = false;
623 612
624 // Evaluate the results 613 // Evaluate the results
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
765 } 754 }
766 } 755 }
767 } 756 }
768 } 757 }
769 } 758 }
770 759
771 return OK; 760 return OK;
772 } 761 }
773 762
774 } // namespace net 763 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/cert_verify_proc.h ('k') | net/cert/cert_verify_proc_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698