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 10 matching lines...) Expand all Loading... |
21 #include "base/synchronization/lock.h" | 21 #include "base/synchronization/lock.h" |
22 #include "crypto/mac_security_services_lock.h" | 22 #include "crypto/mac_security_services_lock.h" |
23 #include "crypto/sha2.h" | 23 #include "crypto/sha2.h" |
24 #include "net/base/hash_value.h" | 24 #include "net/base/hash_value.h" |
25 #include "net/base/net_errors.h" | 25 #include "net/base/net_errors.h" |
26 #include "net/cert/asn1_util.h" | 26 #include "net/cert/asn1_util.h" |
27 #include "net/cert/cert_status_flags.h" | 27 #include "net/cert/cert_status_flags.h" |
28 #include "net/cert/cert_verifier.h" | 28 #include "net/cert/cert_verifier.h" |
29 #include "net/cert/cert_verify_result.h" | 29 #include "net/cert/cert_verify_result.h" |
30 #include "net/cert/crl_set.h" | 30 #include "net/cert/crl_set.h" |
31 #include "net/cert/test_keychain_search_list_mac.h" | |
32 #include "net/cert/test_root_certs.h" | 31 #include "net/cert/test_root_certs.h" |
33 #include "net/cert/x509_certificate.h" | 32 #include "net/cert/x509_certificate.h" |
34 #include "net/cert/x509_util_mac.h" | 33 #include "net/cert/x509_util_mac.h" |
35 | 34 |
36 // CSSM functions are deprecated as of OSX 10.7, but have no replacement. | 35 // CSSM functions are deprecated as of OSX 10.7, but have no replacement. |
37 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1 | 36 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1 |
38 #pragma clang diagnostic push | 37 #pragma clang diagnostic push |
39 #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 38 #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
40 | 39 |
41 // From 10.7.2 libsecurity_keychain-55035/lib/SecTrustPriv.h, for use with | 40 // From 10.7.2 libsecurity_keychain-55035/lib/SecTrustPriv.h, for use with |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 // specific status for (such as basic constraints violation, or | 141 // specific status for (such as basic constraints violation, or |
143 // unknown critical extension) | 142 // unknown critical extension) |
144 OSSTATUS_LOG(WARNING, status) | 143 OSSTATUS_LOG(WARNING, status) |
145 << "Unknown error mapped to CERT_STATUS_INVALID"; | 144 << "Unknown error mapped to CERT_STATUS_INVALID"; |
146 return CERT_STATUS_INVALID; | 145 return CERT_STATUS_INVALID; |
147 } | 146 } |
148 } | 147 } |
149 } | 148 } |
150 | 149 |
151 // Creates a series of SecPolicyRefs to be added to a SecTrustRef used to | 150 // Creates a series of SecPolicyRefs to be added to a SecTrustRef used to |
152 // validate a certificate for an SSL server. |flags| is a bitwise-OR of | 151 // validate a certificate for an SSL server. |hostname| contains the name of |
153 // VerifyFlags that can further alter how trust is validated, such as how | 152 // the SSL server that the certificate should be verified against. |flags| is |
154 // revocation is checked. If successful, returns noErr, and stores the | 153 // a bitwise-OR of VerifyFlags that can further alter how trust is validated, |
155 // resultant array of SecPolicyRefs in |policies|. | 154 // such as how revocation is checked. If successful, returns noErr, and |
156 OSStatus CreateTrustPolicies(int flags, ScopedCFTypeRef<CFArrayRef>* policies) { | 155 // stores the resultant array of SecPolicyRefs in |policies|. |
| 156 OSStatus CreateTrustPolicies(const std::string& hostname, |
| 157 int flags, |
| 158 ScopedCFTypeRef<CFArrayRef>* policies) { |
157 ScopedCFTypeRef<CFMutableArrayRef> local_policies( | 159 ScopedCFTypeRef<CFMutableArrayRef> local_policies( |
158 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); | 160 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); |
159 if (!local_policies) | 161 if (!local_policies) |
160 return memFullErr; | 162 return memFullErr; |
161 | 163 |
162 SecPolicyRef ssl_policy; | 164 SecPolicyRef ssl_policy; |
163 OSStatus status = | 165 OSStatus status = x509_util::CreateSSLServerPolicy(hostname, &ssl_policy); |
164 x509_util::CreateSSLServerPolicy(std::string(), &ssl_policy); | |
165 if (status) | 166 if (status) |
166 return status; | 167 return status; |
167 CFArrayAppendValue(local_policies, ssl_policy); | 168 CFArrayAppendValue(local_policies, ssl_policy); |
168 CFRelease(ssl_policy); | 169 CFRelease(ssl_policy); |
169 | 170 |
170 // Explicitly add revocation policies, in order to override system | 171 // Explicitly add revocation policies, in order to override system |
171 // revocation checking policies and instead respect the application-level | 172 // revocation checking policies and instead respect the application-level |
172 // revocation preference. | 173 // revocation preference. |
173 status = x509_util::CreateRevocationPolicies( | 174 status = x509_util::CreateRevocationPolicies( |
174 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), | 175 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 // failure, no output parameters are modified. | 370 // failure, no output parameters are modified. |
370 // | 371 // |
371 // Note: An OK return does not mean that |cert_array| is trusted, merely that | 372 // Note: An OK return does not mean that |cert_array| is trusted, merely that |
372 // verification was performed successfully. | 373 // verification was performed successfully. |
373 // | 374 // |
374 // This function should only be called while the Mac Security Services lock is | 375 // This function should only be called while the Mac Security Services lock is |
375 // held. | 376 // held. |
376 int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array, | 377 int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array, |
377 CFArrayRef trust_policies, | 378 CFArrayRef trust_policies, |
378 int flags, | 379 int flags, |
379 CFArrayRef keychain_search_list, | |
380 ScopedCFTypeRef<SecTrustRef>* trust_ref, | 380 ScopedCFTypeRef<SecTrustRef>* trust_ref, |
381 SecTrustResultType* trust_result, | 381 SecTrustResultType* trust_result, |
382 ScopedCFTypeRef<CFArrayRef>* verified_chain, | 382 ScopedCFTypeRef<CFArrayRef>* verified_chain, |
383 CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) { | 383 CSSM_TP_APPLE_EVIDENCE_INFO** chain_info) { |
384 SecTrustRef tmp_trust = NULL; | 384 SecTrustRef tmp_trust = NULL; |
385 OSStatus status = SecTrustCreateWithCertificates(cert_array, trust_policies, | 385 OSStatus status = SecTrustCreateWithCertificates(cert_array, trust_policies, |
386 &tmp_trust); | 386 &tmp_trust); |
387 if (status) | 387 if (status) |
388 return NetErrorFromOSStatus(status); | 388 return NetErrorFromOSStatus(status); |
389 ScopedCFTypeRef<SecTrustRef> scoped_tmp_trust(tmp_trust); | 389 ScopedCFTypeRef<SecTrustRef> scoped_tmp_trust(tmp_trust); |
390 | 390 |
391 if (TestRootCerts::HasInstance()) { | 391 if (TestRootCerts::HasInstance()) { |
392 status = TestRootCerts::GetInstance()->FixupSecTrustRef(tmp_trust); | 392 status = TestRootCerts::GetInstance()->FixupSecTrustRef(tmp_trust); |
393 if (status) | 393 if (status) |
394 return NetErrorFromOSStatus(status); | 394 return NetErrorFromOSStatus(status); |
395 } | 395 } |
396 | 396 |
397 if (keychain_search_list) { | |
398 status = SecTrustSetKeychains(tmp_trust, keychain_search_list); | |
399 if (status) | |
400 return NetErrorFromOSStatus(status); | |
401 } | |
402 | |
403 CSSM_APPLE_TP_ACTION_DATA tp_action_data; | 397 CSSM_APPLE_TP_ACTION_DATA tp_action_data; |
404 memset(&tp_action_data, 0, sizeof(tp_action_data)); | 398 memset(&tp_action_data, 0, sizeof(tp_action_data)); |
405 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; | 399 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; |
406 // Allow CSSM to download any missing intermediate certificates if an | 400 // Allow CSSM to download any missing intermediate certificates if an |
407 // authorityInfoAccess extension or issuerAltName extension is present. | 401 // authorityInfoAccess extension or issuerAltName extension is present. |
408 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET | | 402 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET | |
409 CSSM_TP_ACTION_TRUST_SETTINGS; | 403 CSSM_TP_ACTION_TRUST_SETTINGS; |
410 | 404 |
411 // Note: For EV certificates, the Apple TP will handle setting these flags | 405 // Note: For EV certificates, the Apple TP will handle setting these flags |
412 // as part of EV evaluation. | 406 // as part of EV evaluation. |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 | 533 |
540 int CertVerifyProcMac::VerifyInternal( | 534 int CertVerifyProcMac::VerifyInternal( |
541 X509Certificate* cert, | 535 X509Certificate* cert, |
542 const std::string& hostname, | 536 const std::string& hostname, |
543 const std::string& ocsp_response, | 537 const std::string& ocsp_response, |
544 int flags, | 538 int flags, |
545 CRLSet* crl_set, | 539 CRLSet* crl_set, |
546 const CertificateList& additional_trust_anchors, | 540 const CertificateList& additional_trust_anchors, |
547 CertVerifyResult* verify_result) { | 541 CertVerifyResult* verify_result) { |
548 ScopedCFTypeRef<CFArrayRef> trust_policies; | 542 ScopedCFTypeRef<CFArrayRef> trust_policies; |
549 OSStatus status = CreateTrustPolicies(flags, &trust_policies); | 543 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); |
550 if (status) | 544 if (status) |
551 return NetErrorFromOSStatus(status); | 545 return NetErrorFromOSStatus(status); |
552 | 546 |
| 547 // Create and configure a SecTrustRef, which takes our certificate(s) |
| 548 // and our SSL SecPolicyRef. SecTrustCreateWithCertificates() takes an |
| 549 // array of certificates, the first of which is the certificate we're |
| 550 // verifying, and the subsequent (optional) certificates are used for |
| 551 // chain building. |
| 552 ScopedCFTypeRef<CFMutableArrayRef> cert_array( |
| 553 cert->CreateOSCertChainForCert()); |
| 554 |
553 // Serialize all calls that may use the Keychain, to work around various | 555 // Serialize all calls that may use the Keychain, to work around various |
554 // issues in OS X 10.6+ with multi-threaded access to Security.framework. | 556 // issues in OS X 10.6+ with multi-threaded access to Security.framework. |
555 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | 557 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
556 | 558 |
557 ScopedCFTypeRef<SecTrustRef> trust_ref; | 559 ScopedCFTypeRef<SecTrustRef> trust_ref; |
558 SecTrustResultType trust_result = kSecTrustResultDeny; | 560 SecTrustResultType trust_result = kSecTrustResultDeny; |
559 ScopedCFTypeRef<CFArrayRef> completed_chain; | 561 ScopedCFTypeRef<CFArrayRef> completed_chain; |
560 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; | 562 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; |
561 bool candidate_untrusted = true; | 563 bool candidate_untrusted = true; |
562 bool candidate_weak = false; | 564 bool candidate_weak = false; |
563 bool completed_chain_revoked = false; | |
564 | 565 |
565 // OS X lacks proper path discovery; it will take the input certs and never | 566 // OS X lacks proper path discovery; it will take the input certs and never |
566 // backtrack the graph attempting to discover valid paths. | 567 // backtrack the graph attempting to discover valid paths. |
567 // This can create issues in some situations: | 568 // This can create issues in some situations: |
568 // - When OS X changes the trust store, there may be a chain | 569 // - When OS X changes the trust store, there may be a chain |
569 // A -> B -> C -> D | 570 // A -> B -> C -> D |
570 // where OS X trusts D (on some versions) and trusts C (on some versions). | 571 // where OS X trusts D (on some versions) and trusts C (on some versions). |
571 // If a server supplies a chain A, B, C (cross-signed by D), then this chain | 572 // If a server supplies a chain A, B, C (cross-signed by D), then this chain |
572 // will successfully validate on systems that trust D, but fail for systems | 573 // will successfully validate on systems that trust D, but fail for systems |
573 // that trust C. If the server supplies a chain of A -> B, then it forces | 574 // that trust C. If the server supplies a chain of A -> B, then it forces |
(...skipping 15 matching lines...) Expand all Loading... |
589 // version of C signed by D is signed using a weak algorithm (e.g. SHA-1), | 590 // version of C signed by D is signed using a weak algorithm (e.g. SHA-1), |
590 // while the version of C in the trust store's signature doesn't matter. | 591 // while the version of C in the trust store's signature doesn't matter. |
591 // Since a 'strong' chain exists, it would be desirable to prefer this | 592 // Since a 'strong' chain exists, it would be desirable to prefer this |
592 // chain. | 593 // chain. |
593 // | 594 // |
594 // - A variant of the above example, it may be that the version of B sent by | 595 // - A variant of the above example, it may be that the version of B sent by |
595 // the server is signed using a weak algorithm, but the version of B | 596 // the server is signed using a weak algorithm, but the version of B |
596 // present in the AIA of A is signed using a strong algorithm. Since a | 597 // present in the AIA of A is signed using a strong algorithm. Since a |
597 // 'strong' chain exists, it would be desirable to prefer this chain. | 598 // 'strong' chain exists, it would be desirable to prefer this chain. |
598 // | 599 // |
599 // - A user keychain may contain a less desirable intermediate or root. | |
600 // OS X gives the user keychains higher priority than the system keychain, | |
601 // so it may build a weak chain. | |
602 // | |
603 // Because of this, the code below first attempts to validate the peer's | 600 // Because of this, the code below first attempts to validate the peer's |
604 // identity using the supplied chain. If it is not trusted (e.g. the OS only | 601 // identity using the supplied chain. If it is not trusted (e.g. the OS only |
605 // trusts C, but the version of C signed by D was sent, and D is not trusted), | 602 // trusts C, but the version of C signed by D was sent, and D is not trusted), |
606 // or if it contains a weak chain, it will begin lopping off certificates | 603 // or if it contains a weak chain, it will begin lopping off certificates |
607 // from the end of the chain and attempting to verify. If a stronger, trusted | 604 // from the end of the chain and attempting to verify. If a stronger, trusted |
608 // chain is found, it is used, otherwise, the algorithm continues until only | 605 // chain is found, it is used, otherwise, the algorithm continues until only |
609 // the peer's certificate remains. | 606 // the peer's certificate remains. |
610 // | 607 // |
611 // If the loop does not find a trusted chain, the loop will be repeated with | |
612 // the keychain search order altered to give priority to the System Roots | |
613 // keychain. | |
614 // | |
615 // This does cause a performance hit for these users, but only in cases where | 608 // This does cause a performance hit for these users, but only in cases where |
616 // OS X is building weaker chains than desired, or when it would otherwise | 609 // OS X is building weaker chains than desired, or when it would otherwise |
617 // fail the connection. | 610 // fail the connection. |
618 for (bool try_reordered_keychain : {false, true}) { | 611 while (CFArrayGetCount(cert_array) > 0) { |
619 ScopedCFTypeRef<CFArrayRef> scoped_alternate_keychain_search_list; | 612 ScopedCFTypeRef<SecTrustRef> temp_ref; |
620 if (TestKeychainSearchList::HasInstance()) { | 613 SecTrustResultType temp_trust_result = kSecTrustResultDeny; |
621 // Unit tests need to be able to hermetically simulate situations where a | 614 ScopedCFTypeRef<CFArrayRef> temp_chain; |
622 // user has an undesirable certificate in a per-user keychain. | 615 CSSM_TP_APPLE_EVIDENCE_INFO* temp_chain_info = NULL; |
623 // Adding/Removing a Keychain using SecKeychainCreate/SecKeychainDelete | 616 |
624 // has global side effects, which would break other tests and processes | 617 int rv = BuildAndEvaluateSecTrustRef(cert_array, trust_policies, flags, |
625 // running on the same machine, so instead tests may load pre-created | 618 &temp_ref, &temp_trust_result, |
626 // keychains using SecKeychainOpen and then inject them through | 619 &temp_chain, &temp_chain_info); |
627 // TestKeychainSearchList. | 620 if (rv != OK) |
628 CFArrayRef keychain_search_list; | 621 return rv; |
629 status = TestKeychainSearchList::GetInstance()->CopySearchList( | 622 |
630 &keychain_search_list); | 623 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && |
631 if (status) | 624 temp_trust_result != kSecTrustResultProceed); |
632 return NetErrorFromOSStatus(status); | 625 bool weak_chain = false; |
633 scoped_alternate_keychain_search_list.reset(keychain_search_list); | 626 if (CFArrayGetCount(temp_chain) == 0) { |
| 627 // If the chain is empty, it cannot be trusted or have recoverable |
| 628 // errors. |
| 629 DCHECK(untrusted); |
| 630 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); |
| 631 } else { |
| 632 CertVerifyResult temp_verify_result; |
| 633 bool leaf_is_weak = false; |
| 634 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result, |
| 635 &leaf_is_weak); |
| 636 weak_chain = !leaf_is_weak && |
| 637 (temp_verify_result.has_md2 || temp_verify_result.has_md4 || |
| 638 temp_verify_result.has_md5 || temp_verify_result.has_sha1); |
634 } | 639 } |
635 if (try_reordered_keychain) { | 640 // Set the result to the current chain if: |
636 // If a TestKeychainSearchList is present, it will have already set | 641 // - This is the first verification attempt. This ensures that if |
637 // |scoped_alternate_keychain_search_list|, which will be used as the | 642 // everything is awful (e.g. it may just be an untrusted cert), that |
638 // basis for reordering the keychain. Otherwise, get the current keychain | 643 // what is reported is exactly what was sent by the server |
639 // search list and use that. | 644 // - If the current chain is trusted, and the old chain was not trusted, |
640 if (!scoped_alternate_keychain_search_list) { | 645 // then prefer this chain. This ensures that if there is at least a |
641 CFArrayRef keychain_search_list; | 646 // valid path to a trust anchor, it's preferred over reporting an error. |
642 status = SecKeychainCopySearchList(&keychain_search_list); | 647 // - If the current chain is trusted, and the old chain is trusted, but |
643 if (status) | 648 // the old chain contained weak algorithms while the current chain only |
644 return NetErrorFromOSStatus(status); | 649 // contains strong algorithms, then prefer the current chain over the |
645 scoped_alternate_keychain_search_list.reset(keychain_search_list); | 650 // old chain. |
646 } | 651 // |
647 CFMutableArrayRef mutable_keychain_search_list = CFArrayCreateMutableCopy( | 652 // Note: If the leaf certificate itself is weak, then the only |
648 kCFAllocatorDefault, | 653 // consideration is whether or not there is a trusted chain. That's |
649 CFArrayGetCount(scoped_alternate_keychain_search_list.get()) + 1, | 654 // because no amount of path discovery will fix a weak leaf. |
650 scoped_alternate_keychain_search_list.get()); | 655 if (!trust_ref || (!untrusted && (candidate_untrusted || |
651 if (!mutable_keychain_search_list) | 656 (candidate_weak && !weak_chain)))) { |
652 return ERR_OUT_OF_MEMORY; | 657 trust_ref = temp_ref; |
653 scoped_alternate_keychain_search_list.reset(mutable_keychain_search_list); | 658 trust_result = temp_trust_result; |
| 659 completed_chain = temp_chain; |
| 660 chain_info = temp_chain_info; |
654 | 661 |
655 SecKeychainRef keychain; | 662 candidate_untrusted = untrusted; |
656 // Get a reference to the System Roots keychain. The System Roots | 663 candidate_weak = weak_chain; |
657 // keychain is not normally present in the keychain search list, but is | |
658 // implicitly checked after the keychains in the search list. By | |
659 // including it directly, force it to be checked first. This is a gross | |
660 // hack, but the path is known to be valid on OS X 10.9-10.11. | |
661 status = SecKeychainOpen( | |
662 "/System/Library/Keychains/SystemRootCertificates.keychain", | |
663 &keychain); | |
664 if (status) | |
665 return NetErrorFromOSStatus(status); | |
666 ScopedCFTypeRef<SecKeychainRef> scoped_keychain(keychain); | |
667 | |
668 CFArrayInsertValueAtIndex(mutable_keychain_search_list, 0, keychain); | |
669 } | |
670 | |
671 ScopedCFTypeRef<CFMutableArrayRef> cert_array( | |
672 cert->CreateOSCertChainForCert()); | |
673 | |
674 // Beginning with the certificate chain as supplied by the server, attempt | |
675 // to verify the chain. If a failure is encountered, trim a certificate | |
676 // from the end (so long as one remains) and retry, in the hope of forcing | |
677 // OS X to find a better path. | |
678 while (CFArrayGetCount(cert_array) > 0) { | |
679 ScopedCFTypeRef<SecTrustRef> temp_ref; | |
680 SecTrustResultType temp_trust_result = kSecTrustResultDeny; | |
681 ScopedCFTypeRef<CFArrayRef> temp_chain; | |
682 CSSM_TP_APPLE_EVIDENCE_INFO* temp_chain_info = NULL; | |
683 | |
684 int rv = BuildAndEvaluateSecTrustRef( | |
685 cert_array, trust_policies, flags, | |
686 scoped_alternate_keychain_search_list.get(), &temp_ref, | |
687 &temp_trust_result, &temp_chain, &temp_chain_info); | |
688 if (rv != OK) | |
689 return rv; | |
690 | |
691 // Check to see if the path |temp_chain| has been revoked. This is less | |
692 // than ideal to perform after path building, rather than during, because | |
693 // there may be multiple paths to trust anchors, and only some of them | |
694 // are revoked. Ideally, CRLSets would be part of path building, which | |
695 // they are when using NSS (Linux) or CryptoAPI (Windows). | |
696 // | |
697 // The CRLSet checking is performed inside the loop in the hope that if a | |
698 // path is revoked, it's an older path, and the only reason it was built | |
699 // is because the server forced it (by supplying an older or less | |
700 // desirable intermediate) or because the user had installed a | |
701 // certificate in their Keychain forcing this path. However, this means | |
702 // its still possible for a CRLSet block of an intermediate to prevent | |
703 // access, even when there is a 'good' chain. To fully remedy this, a | |
704 // solution might be to have CRLSets contain enough knowledge about what | |
705 // the 'desired' path might be, but for the time being, the | |
706 // implementation is kept as 'simple' as it can be. | |
707 bool revoked = | |
708 (crl_set && !CheckRevocationWithCRLSet(temp_chain, crl_set)); | |
709 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && | |
710 temp_trust_result != kSecTrustResultProceed) || | |
711 revoked; | |
712 bool weak_chain = false; | |
713 if (CFArrayGetCount(temp_chain) == 0) { | |
714 // If the chain is empty, it cannot be trusted or have recoverable | |
715 // errors. | |
716 DCHECK(untrusted); | |
717 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); | |
718 } else { | |
719 CertVerifyResult temp_verify_result; | |
720 bool leaf_is_weak = false; | |
721 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result, | |
722 &leaf_is_weak); | |
723 weak_chain = | |
724 !leaf_is_weak && | |
725 (temp_verify_result.has_md2 || temp_verify_result.has_md4 || | |
726 temp_verify_result.has_md5 || temp_verify_result.has_sha1); | |
727 } | |
728 // Set the result to the current chain if: | |
729 // - This is the first verification attempt. This ensures that if | |
730 // everything is awful (e.g. it may just be an untrusted cert), that | |
731 // what is reported is exactly what was sent by the server | |
732 // - If the current chain is trusted, and the old chain was not trusted, | |
733 // then prefer this chain. This ensures that if there is at least a | |
734 // valid path to a trust anchor, it's preferred over reporting an error. | |
735 // - If the current chain is trusted, and the old chain is trusted, but | |
736 // the old chain contained weak algorithms while the current chain only | |
737 // contains strong algorithms, then prefer the current chain over the | |
738 // old chain. | |
739 // | |
740 // Note: If the leaf certificate itself is weak, then the only | |
741 // consideration is whether or not there is a trusted chain. That's | |
742 // because no amount of path discovery will fix a weak leaf. | |
743 if (!trust_ref || (!untrusted && (candidate_untrusted || | |
744 (candidate_weak && !weak_chain)))) { | |
745 trust_ref = temp_ref; | |
746 trust_result = temp_trust_result; | |
747 completed_chain = temp_chain; | |
748 completed_chain_revoked = revoked; | |
749 chain_info = temp_chain_info; | |
750 | |
751 candidate_untrusted = untrusted; | |
752 candidate_weak = weak_chain; | |
753 } | |
754 // Short-circuit when a current, trusted chain is found. | |
755 if (!untrusted && !weak_chain) | |
756 break; | |
757 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1); | |
758 } | 664 } |
759 // Short-circuit when a current, trusted chain is found. | 665 // Short-circuit when a current, trusted chain is found. |
760 if (!candidate_untrusted && !candidate_weak) | 666 if (!untrusted && !weak_chain) |
761 break; | 667 break; |
| 668 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1); |
762 } | 669 } |
763 | 670 |
764 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) | 671 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) |
765 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 672 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
766 | 673 |
767 if (completed_chain_revoked) | 674 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set)) |
768 verify_result->cert_status |= CERT_STATUS_REVOKED; | 675 verify_result->cert_status |= CERT_STATUS_REVOKED; |
769 | 676 |
770 if (CFArrayGetCount(completed_chain) > 0) { | 677 if (CFArrayGetCount(completed_chain) > 0) { |
771 bool leaf_is_weak_unused = false; | 678 bool leaf_is_weak_unused = false; |
772 GetCertChainInfo(completed_chain, chain_info, verify_result, | 679 GetCertChainInfo(completed_chain, chain_info, verify_result, |
773 &leaf_is_weak_unused); | 680 &leaf_is_weak_unused); |
774 } | 681 } |
775 | 682 |
776 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits | 683 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits |
777 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds | 684 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
928 } | 835 } |
929 } | 836 } |
930 } | 837 } |
931 | 838 |
932 return OK; | 839 return OK; |
933 } | 840 } |
934 | 841 |
935 } // namespace net | 842 } // namespace net |
936 | 843 |
937 #pragma clang diagnostic pop // "-Wdeprecated-declarations" | 844 #pragma clang diagnostic pop // "-Wdeprecated-declarations" |
OLD | NEW |