Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |