| 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_nss.h" | 5 #include "net/cert/cert_verify_proc_nss.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include <cert.h> | 10 #include <cert.h> |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 // kCRLSetRevoked: if any element of the chain is known to have been revoked. | 272 // kCRLSetRevoked: if any element of the chain is known to have been revoked. |
| 273 // kCRLSetUnknown: if there is no fresh information about the leaf | 273 // kCRLSetUnknown: if there is no fresh information about the leaf |
| 274 // certificate in the chain or if the CRLSet has expired. | 274 // certificate in the chain or if the CRLSet has expired. |
| 275 // | 275 // |
| 276 // Only the leaf certificate is considered for coverage because some | 276 // Only the leaf certificate is considered for coverage because some |
| 277 // intermediates have CRLs with no revocations (after filtering) and | 277 // intermediates have CRLs with no revocations (after filtering) and |
| 278 // those CRLs are pruned from the CRLSet at generation time. This means | 278 // those CRLs are pruned from the CRLSet at generation time. This means |
| 279 // that some EV sites would otherwise take the hit of an OCSP lookup for | 279 // that some EV sites would otherwise take the hit of an OCSP lookup for |
| 280 // no reason. | 280 // no reason. |
| 281 // kCRLSetOk: otherwise. | 281 // kCRLSetOk: otherwise. |
| 282 CRLSetResult CheckRevocationWithCRLSet(const CERTCertList* cert_list, | 282 CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list, |
| 283 CERTCertificate* root, | 283 CERTCertificate* root, |
| 284 CRLSet* crl_set) { | 284 CRLSet* crl_set) { |
| 285 std::vector<CERTCertificate*> certs; | 285 std::vector<CERTCertificate*> certs; |
| 286 | 286 |
| 287 if (cert_list) { | 287 if (cert_list) { |
| 288 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); | 288 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); |
| 289 !CERT_LIST_END(node, cert_list); | 289 !CERT_LIST_END(node, cert_list); |
| 290 node = CERT_LIST_NEXT(node)) { | 290 node = CERT_LIST_NEXT(node)) { |
| 291 certs.push_back(node->cert); | 291 certs.push_back(node->cert); |
| 292 } | 292 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 error = true; | 345 error = true; |
| 346 continue; | 346 continue; |
| 347 } | 347 } |
| 348 } | 348 } |
| 349 | 349 |
| 350 if (error || !last_covered || crl_set->IsExpired()) | 350 if (error || !last_covered || crl_set->IsExpired()) |
| 351 return kCRLSetUnknown; | 351 return kCRLSetUnknown; |
| 352 return kCRLSetOk; | 352 return kCRLSetOk; |
| 353 } | 353 } |
| 354 | 354 |
| 355 // Arguments for CheckChainRevocationWithCRLSet that are curried within the | |
| 356 // CERTChainVerifyCallback's isChainValidArg. | |
| 357 struct CheckChainRevocationArgs { | |
| 358 // The CRLSet to evaluate against. | |
| 359 CRLSet* crl_set = nullptr; | |
| 360 | |
| 361 // The next callback to invoke, if the CRLSet does not report any errors. | |
| 362 CERTChainVerifyCallback* next_callback = nullptr; | |
| 363 | |
| 364 // Indicates that the application callback failure was due to a CRLSet | |
| 365 // revocation, rather than due to |next_callback| rejecting it. This is | |
| 366 // used to map the error back to the proper caller-visible error code. | |
| 367 bool was_revoked = false; | |
| 368 }; | |
| 369 | |
| 370 SECStatus CheckChainRevocationWithCRLSet(void* is_chain_valid_arg, | |
| 371 const CERTCertList* current_chain, | |
| 372 PRBool* chain_ok) { | |
| 373 CHECK(is_chain_valid_arg); | |
| 374 | |
| 375 CheckChainRevocationArgs* args = | |
| 376 static_cast<CheckChainRevocationArgs*>(is_chain_valid_arg); | |
| 377 | |
| 378 CRLSetResult crlset_result = kCRLSetUnknown; | |
| 379 if (args->crl_set) { | |
| 380 crlset_result = | |
| 381 CheckRevocationWithCRLSet(current_chain, nullptr, args->crl_set); | |
| 382 } | |
| 383 | |
| 384 if (crlset_result == kCRLSetRevoked) { | |
| 385 args->was_revoked = true; | |
| 386 *chain_ok = PR_FALSE; | |
| 387 return SECSuccess; | |
| 388 } | |
| 389 args->was_revoked = false; | |
| 390 | |
| 391 *chain_ok = PR_TRUE; | |
| 392 if (!args->next_callback || !args->next_callback->isChainValid) | |
| 393 return SECSuccess; | |
| 394 | |
| 395 return (*args->next_callback->isChainValid)( | |
| 396 args->next_callback->isChainValidArg, current_chain, chain_ok); | |
| 397 } | |
| 398 | |
| 399 // Forward declarations. | 355 // Forward declarations. |
| 400 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 356 SECStatus RetryPKIXVerifyCertWithWorkarounds( |
| 401 CERTCertificate* cert_handle, int num_policy_oids, | 357 CERTCertificate* cert_handle, int num_policy_oids, |
| 402 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, | 358 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, |
| 403 CERTValOutParam* cvout); | 359 CERTValOutParam* cvout); |
| 404 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); | 360 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); |
| 405 | 361 |
| 406 // Call CERT_PKIXVerifyCert for the cert_handle. | 362 // Call CERT_PKIXVerifyCert for the cert_handle. |
| 407 // Verification results are stored in an array of CERTValOutParam. | 363 // Verification results are stored in an array of CERTValOutParam. |
| 408 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being | 364 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 cache_ocsp_response_from_side_channel_(CERT_GetDefaultCertDB(), cert_handle, | 818 cache_ocsp_response_from_side_channel_(CERT_GetDefaultCertDB(), cert_handle, |
| 863 PR_Now(), &ocsp_response_item, | 819 PR_Now(), &ocsp_response_item, |
| 864 nullptr); | 820 nullptr); |
| 865 } | 821 } |
| 866 | 822 |
| 867 if (!cert->VerifyNameMatch(hostname, | 823 if (!cert->VerifyNameMatch(hostname, |
| 868 &verify_result->common_name_fallback_used)) { | 824 &verify_result->common_name_fallback_used)) { |
| 869 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 825 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 870 } | 826 } |
| 871 | 827 |
| 872 // Setup a callback to call into CheckChainRevocationWithCRLSet with the | |
| 873 // current CRLSet. If the CRLSet revokes a given chain, |was_revoked| | |
| 874 // will be set to true. | |
| 875 // The same callback and args are used for every invocation of | |
| 876 // PKIXVerifyCert, as CheckChainRevocationWithCRLSet handles resetting | |
| 877 // |was_revoked| as necessary. | |
| 878 CheckChainRevocationArgs check_chain_revocation_args; | |
| 879 check_chain_revocation_args.crl_set = crl_set; | |
| 880 check_chain_revocation_args.next_callback = chain_verify_callback; | |
| 881 | |
| 882 CERTChainVerifyCallback crlset_callback; | |
| 883 memset(&crlset_callback, 0, sizeof(crlset_callback)); | |
| 884 crlset_callback.isChainValid = &CheckChainRevocationWithCRLSet; | |
| 885 crlset_callback.isChainValidArg = | |
| 886 static_cast<void*>(&check_chain_revocation_args); | |
| 887 | |
| 888 // Make sure that the cert is valid now. | 828 // Make sure that the cert is valid now. |
| 889 SECCertTimeValidity validity = CERT_CheckCertValidTimes( | 829 SECCertTimeValidity validity = CERT_CheckCertValidTimes( |
| 890 cert_handle, PR_Now(), PR_TRUE); | 830 cert_handle, PR_Now(), PR_TRUE); |
| 891 if (validity != secCertTimeValid) | 831 if (validity != secCertTimeValid) |
| 892 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 832 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| 893 | 833 |
| 894 CERTValOutParam cvout[3]; | 834 CERTValOutParam cvout[3]; |
| 895 int cvout_index = 0; | 835 int cvout_index = 0; |
| 896 cvout[cvout_index].type = cert_po_certList; | 836 cvout[cvout_index].type = cert_po_certList; |
| 897 cvout[cvout_index].value.pointer.chain = NULL; | 837 cvout[cvout_index].value.pointer.chain = NULL; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 915 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); | 855 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); |
| 916 if (check_revocation) | 856 if (check_revocation) |
| 917 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 857 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 918 | 858 |
| 919 ScopedCERTCertList trust_anchors; | 859 ScopedCERTCertList trust_anchors; |
| 920 if (!additional_trust_anchors.empty()) { | 860 if (!additional_trust_anchors.empty()) { |
| 921 trust_anchors.reset( | 861 trust_anchors.reset( |
| 922 CertificateListToCERTCertList(additional_trust_anchors)); | 862 CertificateListToCERTCertList(additional_trust_anchors)); |
| 923 } | 863 } |
| 924 | 864 |
| 925 SECStatus status = | 865 SECStatus status = PKIXVerifyCert(cert_handle, |
| 926 PKIXVerifyCert(cert_handle, check_revocation, false, cert_io_enabled, | 866 check_revocation, |
| 927 NULL, 0, trust_anchors.get(), &crlset_callback, cvout); | 867 false, |
| 868 cert_io_enabled, |
| 869 NULL, |
| 870 0, |
| 871 trust_anchors.get(), |
| 872 chain_verify_callback, |
| 873 cvout); |
| 928 | 874 |
| 929 if (status == SECSuccess && | 875 if (status == SECSuccess && |
| 930 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && | 876 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && |
| 931 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) { | 877 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) { |
| 932 // TODO(rsleevi): Optimize this by supplying the constructed chain to | 878 // TODO(rsleevi): Optimize this by supplying the constructed chain to |
| 933 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream | 879 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream |
| 934 // NSS tests for that feature. | 880 // NSS tests for that feature. |
| 935 scoped_cvout.Clear(); | 881 scoped_cvout.Clear(); |
| 936 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 882 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 937 status = PKIXVerifyCert(cert_handle, true, true, cert_io_enabled, NULL, 0, | 883 status = PKIXVerifyCert(cert_handle, |
| 938 trust_anchors.get(), &crlset_callback, cvout); | 884 true, |
| 885 true, |
| 886 cert_io_enabled, |
| 887 NULL, |
| 888 0, |
| 889 trust_anchors.get(), |
| 890 chain_verify_callback, |
| 891 cvout); |
| 939 } | 892 } |
| 940 | 893 |
| 941 if (status == SECSuccess) { | 894 if (status == SECSuccess) { |
| 942 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, | 895 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, |
| 943 cvout[cvout_trust_anchor_index].value.pointer.cert, | 896 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 944 &verify_result->public_key_hashes); | 897 &verify_result->public_key_hashes); |
| 945 | 898 |
| 946 verify_result->is_issued_by_known_root = | 899 verify_result->is_issued_by_known_root = |
| 947 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); | 900 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); |
| 948 verify_result->is_issued_by_additional_trust_anchor = | 901 verify_result->is_issued_by_additional_trust_anchor = |
| 949 IsAdditionalTrustAnchor( | 902 IsAdditionalTrustAnchor( |
| 950 trust_anchors.get(), | 903 trust_anchors.get(), |
| 951 cvout[cvout_trust_anchor_index].value.pointer.cert); | 904 cvout[cvout_trust_anchor_index].value.pointer.cert); |
| 952 | 905 |
| 953 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, | 906 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, |
| 954 cvout[cvout_trust_anchor_index].value.pointer.cert, | 907 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 955 verify_result); | 908 verify_result); |
| 956 } | 909 } |
| 957 | 910 |
| 958 CRLSetResult crl_set_result = kCRLSetUnknown; | 911 CRLSetResult crl_set_result = kCRLSetUnknown; |
| 959 if (crl_set) { | 912 if (crl_set) { |
| 960 if (status == SECSuccess) { | 913 crl_set_result = CheckRevocationWithCRLSet( |
| 961 // Reverify the returned chain; NSS should have already called | 914 cvout[cvout_cert_list_index].value.pointer.chain, |
| 962 // CheckChainRevocationWithCRLSet prior to returning, but given the | 915 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 963 // edge cases (self-signed certs that are trusted; cached chains; | 916 crl_set); |
| 964 // unreadable code), this is more about defense in depth than | 917 if (crl_set_result == kCRLSetRevoked) { |
| 965 // functional necessity. | |
| 966 crl_set_result = CheckRevocationWithCRLSet( | |
| 967 cvout[cvout_cert_list_index].value.pointer.chain, | |
| 968 cvout[cvout_trust_anchor_index].value.pointer.cert, crl_set); | |
| 969 if (crl_set_result == kCRLSetRevoked) { | |
| 970 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | |
| 971 status = SECFailure; | |
| 972 } | |
| 973 } else if (PORT_GetError() == SEC_ERROR_APPLICATION_CALLBACK_ERROR && | |
| 974 check_chain_revocation_args.was_revoked) { | |
| 975 // If a CRLSet was supplied, and the error was an application callback | |
| 976 // error, then it was directed through the CRLSet code and that | |
| 977 // particular chain was revoked. | |
| 978 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | 918 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); |
| 919 status = SECFailure; |
| 979 } | 920 } |
| 980 } | 921 } |
| 981 | 922 |
| 982 if (status != SECSuccess) { | 923 if (status != SECSuccess) { |
| 983 int err = PORT_GetError(); | 924 int err = PORT_GetError(); |
| 984 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname | 925 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname |
| 985 << " failed err=" << err; | 926 << " failed err=" << err; |
| 986 // CERT_PKIXVerifyCert rerports the wrong error code for | 927 // CERT_PKIXVerifyCert rerports the wrong error code for |
| 987 // expired certificates (NSS bug 491174) | 928 // expired certificates (NSS bug 491174) |
| 988 if (err == SEC_ERROR_CERT_NOT_VALID && | 929 if (err == SEC_ERROR_CERT_NOT_VALID && |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1001 return MapCertStatusToNetError(verify_result->cert_status); | 942 return MapCertStatusToNetError(verify_result->cert_status); |
| 1002 | 943 |
| 1003 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { | 944 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { |
| 1004 check_revocation |= | 945 check_revocation |= |
| 1005 crl_set_result != kCRLSetOk && | 946 crl_set_result != kCRLSetOk && |
| 1006 cert_io_enabled && | 947 cert_io_enabled && |
| 1007 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); | 948 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); |
| 1008 if (check_revocation) | 949 if (check_revocation) |
| 1009 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 950 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 1010 | 951 |
| 1011 if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata, | 952 if (VerifyEV(cert_handle, |
| 1012 ev_policy_oid, trust_anchors.get(), &crlset_callback)) { | 953 flags, |
| 954 crl_set, |
| 955 check_revocation, |
| 956 metadata, |
| 957 ev_policy_oid, |
| 958 trust_anchors.get(), |
| 959 chain_verify_callback)) { |
| 1013 verify_result->cert_status |= CERT_STATUS_IS_EV; | 960 verify_result->cert_status |= CERT_STATUS_IS_EV; |
| 1014 } | 961 } |
| 1015 } | 962 } |
| 1016 | 963 |
| 1017 return OK; | 964 return OK; |
| 1018 } | 965 } |
| 1019 | 966 |
| 1020 int CertVerifyProcNSS::VerifyInternal( | 967 int CertVerifyProcNSS::VerifyInternal( |
| 1021 X509Certificate* cert, | 968 X509Certificate* cert, |
| 1022 const std::string& hostname, | 969 const std::string& hostname, |
| 1023 const std::string& ocsp_response, | 970 const std::string& ocsp_response, |
| 1024 int flags, | 971 int flags, |
| 1025 CRLSet* crl_set, | 972 CRLSet* crl_set, |
| 1026 const CertificateList& additional_trust_anchors, | 973 const CertificateList& additional_trust_anchors, |
| 1027 CertVerifyResult* verify_result) { | 974 CertVerifyResult* verify_result) { |
| 1028 return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set, | 975 return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set, |
| 1029 additional_trust_anchors, | 976 additional_trust_anchors, |
| 1030 NULL, // chain_verify_callback | 977 NULL, // chain_verify_callback |
| 1031 verify_result); | 978 verify_result); |
| 1032 } | 979 } |
| 1033 | 980 |
| 1034 } // namespace net | 981 } // namespace net |
| OLD | NEW |