| 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 |