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" |
31 #include "net/cert/test_root_certs.h" | 32 #include "net/cert/test_root_certs.h" |
32 #include "net/cert/x509_certificate.h" | 33 #include "net/cert/x509_certificate.h" |
33 #include "net/cert/x509_util_mac.h" | 34 #include "net/cert/x509_util_mac.h" |
34 | 35 |
35 // CSSM functions are deprecated as of OSX 10.7, but have no replacement. | 36 // CSSM functions are deprecated as of OSX 10.7, but have no replacement. |
36 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1 | 37 // https://bugs.chromium.org/p/chromium/issues/detail?id=590914#c1 |
37 #pragma clang diagnostic push | 38 #pragma clang diagnostic push |
38 #pragma clang diagnostic ignored "-Wdeprecated-declarations" | 39 #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
39 | 40 |
40 // From 10.7.2 libsecurity_keychain-55035/lib/SecTrustPriv.h, for use with | 41 // 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... |
141 // specific status for (such as basic constraints violation, or | 142 // specific status for (such as basic constraints violation, or |
142 // unknown critical extension) | 143 // unknown critical extension) |
143 OSSTATUS_LOG(WARNING, status) | 144 OSSTATUS_LOG(WARNING, status) |
144 << "Unknown error mapped to CERT_STATUS_INVALID"; | 145 << "Unknown error mapped to CERT_STATUS_INVALID"; |
145 return CERT_STATUS_INVALID; | 146 return CERT_STATUS_INVALID; |
146 } | 147 } |
147 } | 148 } |
148 } | 149 } |
149 | 150 |
150 // Creates a series of SecPolicyRefs to be added to a SecTrustRef used to | 151 // Creates a series of SecPolicyRefs to be added to a SecTrustRef used to |
151 // validate a certificate for an SSL server. |hostname| contains the name of | 152 // validate a certificate for an SSL server. |flags| is a bitwise-OR of |
152 // the SSL server that the certificate should be verified against. |flags| is | 153 // VerifyFlags that can further alter how trust is validated, such as how |
153 // a bitwise-OR of VerifyFlags that can further alter how trust is validated, | 154 // revocation is checked. If successful, returns noErr, and stores the |
154 // such as how revocation is checked. If successful, returns noErr, and | 155 // resultant array of SecPolicyRefs in |policies|. |
155 // stores the resultant array of SecPolicyRefs in |policies|. | 156 OSStatus CreateTrustPolicies(int flags, ScopedCFTypeRef<CFArrayRef>* policies) { |
156 OSStatus CreateTrustPolicies(const std::string& hostname, | |
157 int flags, | |
158 ScopedCFTypeRef<CFArrayRef>* policies) { | |
159 ScopedCFTypeRef<CFMutableArrayRef> local_policies( | 157 ScopedCFTypeRef<CFMutableArrayRef> local_policies( |
160 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); | 158 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); |
161 if (!local_policies) | 159 if (!local_policies) |
162 return memFullErr; | 160 return memFullErr; |
163 | 161 |
164 SecPolicyRef ssl_policy; | 162 SecPolicyRef ssl_policy; |
165 OSStatus status = x509_util::CreateSSLServerPolicy(hostname, &ssl_policy); | 163 OSStatus status = |
| 164 x509_util::CreateSSLServerPolicy(std::string(), &ssl_policy); |
166 if (status) | 165 if (status) |
167 return status; | 166 return status; |
168 CFArrayAppendValue(local_policies, ssl_policy); | 167 CFArrayAppendValue(local_policies, ssl_policy); |
169 CFRelease(ssl_policy); | 168 CFRelease(ssl_policy); |
170 | 169 |
171 // Explicitly add revocation policies, in order to override system | 170 // Explicitly add revocation policies, in order to override system |
172 // revocation checking policies and instead respect the application-level | 171 // revocation checking policies and instead respect the application-level |
173 // revocation preference. | 172 // revocation preference. |
174 status = x509_util::CreateRevocationPolicies( | 173 status = x509_util::CreateRevocationPolicies( |
175 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), | 174 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 // failure, no output parameters are modified. | 369 // failure, no output parameters are modified. |
371 // | 370 // |
372 // Note: An OK return does not mean that |cert_array| is trusted, merely that | 371 // Note: An OK return does not mean that |cert_array| is trusted, merely that |
373 // verification was performed successfully. | 372 // verification was performed successfully. |
374 // | 373 // |
375 // This function should only be called while the Mac Security Services lock is | 374 // This function should only be called while the Mac Security Services lock is |
376 // held. | 375 // held. |
377 int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array, | 376 int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array, |
378 CFArrayRef trust_policies, | 377 CFArrayRef trust_policies, |
379 int flags, | 378 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 |
397 CSSM_APPLE_TP_ACTION_DATA tp_action_data; | 403 CSSM_APPLE_TP_ACTION_DATA tp_action_data; |
398 memset(&tp_action_data, 0, sizeof(tp_action_data)); | 404 memset(&tp_action_data, 0, sizeof(tp_action_data)); |
399 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; | 405 tp_action_data.Version = CSSM_APPLE_TP_ACTION_VERSION; |
400 // Allow CSSM to download any missing intermediate certificates if an | 406 // Allow CSSM to download any missing intermediate certificates if an |
401 // authorityInfoAccess extension or issuerAltName extension is present. | 407 // authorityInfoAccess extension or issuerAltName extension is present. |
402 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET | | 408 tp_action_data.ActionFlags = CSSM_TP_ACTION_FETCH_CERT_FROM_NET | |
403 CSSM_TP_ACTION_TRUST_SETTINGS; | 409 CSSM_TP_ACTION_TRUST_SETTINGS; |
404 | 410 |
405 // Note: For EV certificates, the Apple TP will handle setting these flags | 411 // Note: For EV certificates, the Apple TP will handle setting these flags |
406 // as part of EV evaluation. | 412 // as part of EV evaluation. |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 | 539 |
534 int CertVerifyProcMac::VerifyInternal( | 540 int CertVerifyProcMac::VerifyInternal( |
535 X509Certificate* cert, | 541 X509Certificate* cert, |
536 const std::string& hostname, | 542 const std::string& hostname, |
537 const std::string& ocsp_response, | 543 const std::string& ocsp_response, |
538 int flags, | 544 int flags, |
539 CRLSet* crl_set, | 545 CRLSet* crl_set, |
540 const CertificateList& additional_trust_anchors, | 546 const CertificateList& additional_trust_anchors, |
541 CertVerifyResult* verify_result) { | 547 CertVerifyResult* verify_result) { |
542 ScopedCFTypeRef<CFArrayRef> trust_policies; | 548 ScopedCFTypeRef<CFArrayRef> trust_policies; |
543 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); | 549 OSStatus status = CreateTrustPolicies(flags, &trust_policies); |
544 if (status) | 550 if (status) |
545 return NetErrorFromOSStatus(status); | 551 return NetErrorFromOSStatus(status); |
546 | 552 |
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 | |
555 // Serialize all calls that may use the Keychain, to work around various | 553 // Serialize all calls that may use the Keychain, to work around various |
556 // issues in OS X 10.6+ with multi-threaded access to Security.framework. | 554 // issues in OS X 10.6+ with multi-threaded access to Security.framework. |
557 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); | 555 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); |
558 | 556 |
559 ScopedCFTypeRef<SecTrustRef> trust_ref; | 557 ScopedCFTypeRef<SecTrustRef> trust_ref; |
560 SecTrustResultType trust_result = kSecTrustResultDeny; | 558 SecTrustResultType trust_result = kSecTrustResultDeny; |
561 ScopedCFTypeRef<CFArrayRef> completed_chain; | 559 ScopedCFTypeRef<CFArrayRef> completed_chain; |
562 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; | 560 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info = NULL; |
563 bool candidate_untrusted = true; | 561 bool candidate_untrusted = true; |
564 bool candidate_weak = false; | 562 bool candidate_weak = false; |
| 563 bool completed_chain_revoked = false; |
565 | 564 |
566 // OS X lacks proper path discovery; it will take the input certs and never | 565 // OS X lacks proper path discovery; it will take the input certs and never |
567 // backtrack the graph attempting to discover valid paths. | 566 // backtrack the graph attempting to discover valid paths. |
568 // This can create issues in some situations: | 567 // This can create issues in some situations: |
569 // - When OS X changes the trust store, there may be a chain | 568 // - When OS X changes the trust store, there may be a chain |
570 // A -> B -> C -> D | 569 // A -> B -> C -> D |
571 // where OS X trusts D (on some versions) and trusts C (on some versions). | 570 // where OS X trusts D (on some versions) and trusts C (on some versions). |
572 // If a server supplies a chain A, B, C (cross-signed by D), then this chain | 571 // If a server supplies a chain A, B, C (cross-signed by D), then this chain |
573 // will successfully validate on systems that trust D, but fail for systems | 572 // will successfully validate on systems that trust D, but fail for systems |
574 // that trust C. If the server supplies a chain of A -> B, then it forces | 573 // that trust C. If the server supplies a chain of A -> B, then it forces |
(...skipping 15 matching lines...) Expand all Loading... |
590 // version of C signed by D is signed using a weak algorithm (e.g. SHA-1), | 589 // version of C signed by D is signed using a weak algorithm (e.g. SHA-1), |
591 // while the version of C in the trust store's signature doesn't matter. | 590 // while the version of C in the trust store's signature doesn't matter. |
592 // Since a 'strong' chain exists, it would be desirable to prefer this | 591 // Since a 'strong' chain exists, it would be desirable to prefer this |
593 // chain. | 592 // chain. |
594 // | 593 // |
595 // - A variant of the above example, it may be that the version of B sent by | 594 // - A variant of the above example, it may be that the version of B sent by |
596 // the server is signed using a weak algorithm, but the version of B | 595 // the server is signed using a weak algorithm, but the version of B |
597 // present in the AIA of A is signed using a strong algorithm. Since a | 596 // present in the AIA of A is signed using a strong algorithm. Since a |
598 // 'strong' chain exists, it would be desirable to prefer this chain. | 597 // 'strong' chain exists, it would be desirable to prefer this chain. |
599 // | 598 // |
| 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 // |
600 // Because of this, the code below first attempts to validate the peer's | 603 // Because of this, the code below first attempts to validate the peer's |
601 // identity using the supplied chain. If it is not trusted (e.g. the OS only | 604 // identity using the supplied chain. If it is not trusted (e.g. the OS only |
602 // trusts C, but the version of C signed by D was sent, and D is not trusted), | 605 // trusts C, but the version of C signed by D was sent, and D is not trusted), |
603 // or if it contains a weak chain, it will begin lopping off certificates | 606 // or if it contains a weak chain, it will begin lopping off certificates |
604 // from the end of the chain and attempting to verify. If a stronger, trusted | 607 // from the end of the chain and attempting to verify. If a stronger, trusted |
605 // chain is found, it is used, otherwise, the algorithm continues until only | 608 // chain is found, it is used, otherwise, the algorithm continues until only |
606 // the peer's certificate remains. | 609 // the peer's certificate remains. |
607 // | 610 // |
| 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 // |
608 // This does cause a performance hit for these users, but only in cases where | 615 // This does cause a performance hit for these users, but only in cases where |
609 // OS X is building weaker chains than desired, or when it would otherwise | 616 // OS X is building weaker chains than desired, or when it would otherwise |
610 // fail the connection. | 617 // fail the connection. |
611 while (CFArrayGetCount(cert_array) > 0) { | 618 for (bool try_reordered_keychain : {false, true}) { |
612 ScopedCFTypeRef<SecTrustRef> temp_ref; | 619 ScopedCFTypeRef<CFArrayRef> scoped_alternate_keychain_search_list; |
613 SecTrustResultType temp_trust_result = kSecTrustResultDeny; | 620 if (TestKeychainSearchList::HasInstance()) { |
614 ScopedCFTypeRef<CFArrayRef> temp_chain; | 621 // Unit tests need to be able to hermetically simulate situations where a |
615 CSSM_TP_APPLE_EVIDENCE_INFO* temp_chain_info = NULL; | 622 // user has an undesirable certificate in a per-user keychain. |
| 623 // Adding/Removing a Keychain using SecKeychainCreate/SecKeychainDelete |
| 624 // has global side effects, which would break other tests and processes |
| 625 // running on the same machine, so instead tests may load pre-created |
| 626 // keychains using SecKeychainOpen and then inject them through |
| 627 // TestKeychainSearchList. |
| 628 CFArrayRef keychain_search_list; |
| 629 status = TestKeychainSearchList::GetInstance()->CopySearchList( |
| 630 &keychain_search_list); |
| 631 if (status) |
| 632 return NetErrorFromOSStatus(status); |
| 633 scoped_alternate_keychain_search_list.reset(keychain_search_list); |
| 634 } |
| 635 if (try_reordered_keychain) { |
| 636 // If a TestKeychainSearchList is present, it will have already set |
| 637 // |scoped_alternate_keychain_search_list|, which will be used as the |
| 638 // basis for reordering the keychain. Otherwise, get the current keychain |
| 639 // search list and use that. |
| 640 if (!scoped_alternate_keychain_search_list) { |
| 641 CFArrayRef keychain_search_list; |
| 642 status = SecKeychainCopySearchList(&keychain_search_list); |
| 643 if (status) |
| 644 return NetErrorFromOSStatus(status); |
| 645 scoped_alternate_keychain_search_list.reset(keychain_search_list); |
| 646 } |
| 647 CFMutableArrayRef mutable_keychain_search_list = CFArrayCreateMutableCopy( |
| 648 kCFAllocatorDefault, |
| 649 CFArrayGetCount(scoped_alternate_keychain_search_list.get()) + 1, |
| 650 scoped_alternate_keychain_search_list.get()); |
| 651 if (!mutable_keychain_search_list) |
| 652 return ERR_OUT_OF_MEMORY; |
| 653 scoped_alternate_keychain_search_list.reset(mutable_keychain_search_list); |
616 | 654 |
617 int rv = BuildAndEvaluateSecTrustRef(cert_array, trust_policies, flags, | 655 SecKeychainRef keychain; |
618 &temp_ref, &temp_trust_result, | 656 // Get a reference to the System Roots keychain. The System Roots |
619 &temp_chain, &temp_chain_info); | 657 // keychain is not normally present in the keychain search list, but is |
620 if (rv != OK) | 658 // implicitly checked after the keychains in the search list. By |
621 return rv; | 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); |
622 | 667 |
623 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && | 668 CFArrayInsertValueAtIndex(mutable_keychain_search_list, 0, keychain); |
624 temp_trust_result != kSecTrustResultProceed); | |
625 bool weak_chain = false; | |
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); | |
639 } | 669 } |
640 // Set the result to the current chain if: | |
641 // - This is the first verification attempt. This ensures that if | |
642 // everything is awful (e.g. it may just be an untrusted cert), that | |
643 // what is reported is exactly what was sent by the server | |
644 // - If the current chain is trusted, and the old chain was not trusted, | |
645 // then prefer this chain. This ensures that if there is at least a | |
646 // valid path to a trust anchor, it's preferred over reporting an error. | |
647 // - If the current chain is trusted, and the old chain is trusted, but | |
648 // the old chain contained weak algorithms while the current chain only | |
649 // contains strong algorithms, then prefer the current chain over the | |
650 // old chain. | |
651 // | |
652 // Note: If the leaf certificate itself is weak, then the only | |
653 // consideration is whether or not there is a trusted chain. That's | |
654 // because no amount of path discovery will fix a weak leaf. | |
655 if (!trust_ref || (!untrusted && (candidate_untrusted || | |
656 (candidate_weak && !weak_chain)))) { | |
657 trust_ref = temp_ref; | |
658 trust_result = temp_trust_result; | |
659 completed_chain = temp_chain; | |
660 chain_info = temp_chain_info; | |
661 | 670 |
662 candidate_untrusted = untrusted; | 671 ScopedCFTypeRef<CFMutableArrayRef> cert_array( |
663 candidate_weak = weak_chain; | 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); |
664 } | 758 } |
665 // Short-circuit when a current, trusted chain is found. | 759 // Short-circuit when a current, trusted chain is found. |
666 if (!untrusted && !weak_chain) | 760 if (!candidate_untrusted && !candidate_weak) |
667 break; | 761 break; |
668 CFArrayRemoveValueAtIndex(cert_array, CFArrayGetCount(cert_array) - 1); | |
669 } | 762 } |
670 | 763 |
671 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) | 764 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) |
672 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 765 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
673 | 766 |
674 if (crl_set && !CheckRevocationWithCRLSet(completed_chain, crl_set)) | 767 if (completed_chain_revoked) |
675 verify_result->cert_status |= CERT_STATUS_REVOKED; | 768 verify_result->cert_status |= CERT_STATUS_REVOKED; |
676 | 769 |
677 if (CFArrayGetCount(completed_chain) > 0) { | 770 if (CFArrayGetCount(completed_chain) > 0) { |
678 bool leaf_is_weak_unused = false; | 771 bool leaf_is_weak_unused = false; |
679 GetCertChainInfo(completed_chain, chain_info, verify_result, | 772 GetCertChainInfo(completed_chain, chain_info, verify_result, |
680 &leaf_is_weak_unused); | 773 &leaf_is_weak_unused); |
681 } | 774 } |
682 | 775 |
683 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits | 776 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits |
684 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds | 777 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 } | 928 } |
836 } | 929 } |
837 } | 930 } |
838 | 931 |
839 return OK; | 932 return OK; |
840 } | 933 } |
841 | 934 |
842 } // namespace net | 935 } // namespace net |
843 | 936 |
844 #pragma clang diagnostic pop // "-Wdeprecated-declarations" | 937 #pragma clang diagnostic pop // "-Wdeprecated-declarations" |
OLD | NEW |