Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/cert_verify_proc_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(CERTCertList* cert_list, | 282 CRLSetResult CheckRevocationWithCRLSet(const 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 | |
| 355 // Forward declarations. | 399 // Forward declarations. |
| 356 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 400 SECStatus RetryPKIXVerifyCertWithWorkarounds( |
| 357 CERTCertificate* cert_handle, int num_policy_oids, | 401 CERTCertificate* cert_handle, int num_policy_oids, |
| 358 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, | 402 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, |
| 359 CERTValOutParam* cvout); | 403 CERTValOutParam* cvout); |
| 360 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); | 404 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); |
| 361 | 405 |
| 362 // Call CERT_PKIXVerifyCert for the cert_handle. | 406 // Call CERT_PKIXVerifyCert for the cert_handle. |
| 363 // Verification results are stored in an array of CERTValOutParam. | 407 // Verification results are stored in an array of CERTValOutParam. |
| 364 // If |hard_fail| is true, and no policy_oids are supplied (eg: EV is NOT being | 408 // 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... | |
| 818 cache_ocsp_response_from_side_channel_(CERT_GetDefaultCertDB(), cert_handle, | 862 cache_ocsp_response_from_side_channel_(CERT_GetDefaultCertDB(), cert_handle, |
| 819 PR_Now(), &ocsp_response_item, | 863 PR_Now(), &ocsp_response_item, |
| 820 nullptr); | 864 nullptr); |
| 821 } | 865 } |
| 822 | 866 |
| 823 if (!cert->VerifyNameMatch(hostname, | 867 if (!cert->VerifyNameMatch(hostname, |
| 824 &verify_result->common_name_fallback_used)) { | 868 &verify_result->common_name_fallback_used)) { |
| 825 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 869 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 826 } | 870 } |
| 827 | 871 |
| 872 CheckChainRevocationArgs check_chain_revocation_args; | |
| 873 CERTChainVerifyCallback crlset_callback; | |
| 874 memset(&crlset_callback, 0, sizeof(crlset_callback)); | |
| 875 crlset_callback.isChainValid = &CheckChainRevocationWithCRLSet; | |
| 876 crlset_callback.isChainValidArg = | |
| 877 static_cast<void*>(&check_chain_revocation_args); | |
| 878 | |
| 828 // Make sure that the cert is valid now. | 879 // Make sure that the cert is valid now. |
| 829 SECCertTimeValidity validity = CERT_CheckCertValidTimes( | 880 SECCertTimeValidity validity = CERT_CheckCertValidTimes( |
| 830 cert_handle, PR_Now(), PR_TRUE); | 881 cert_handle, PR_Now(), PR_TRUE); |
| 831 if (validity != secCertTimeValid) | 882 if (validity != secCertTimeValid) |
| 832 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 883 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| 833 | 884 |
| 834 CERTValOutParam cvout[3]; | 885 CERTValOutParam cvout[3]; |
| 835 int cvout_index = 0; | 886 int cvout_index = 0; |
| 836 cvout[cvout_index].type = cert_po_certList; | 887 cvout[cvout_index].type = cert_po_certList; |
| 837 cvout[cvout_index].value.pointer.chain = NULL; | 888 cvout[cvout_index].value.pointer.chain = NULL; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 855 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); | 906 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); |
| 856 if (check_revocation) | 907 if (check_revocation) |
| 857 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 908 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 858 | 909 |
| 859 ScopedCERTCertList trust_anchors; | 910 ScopedCERTCertList trust_anchors; |
| 860 if (!additional_trust_anchors.empty()) { | 911 if (!additional_trust_anchors.empty()) { |
| 861 trust_anchors.reset( | 912 trust_anchors.reset( |
| 862 CertificateListToCERTCertList(additional_trust_anchors)); | 913 CertificateListToCERTCertList(additional_trust_anchors)); |
| 863 } | 914 } |
| 864 | 915 |
| 865 SECStatus status = PKIXVerifyCert(cert_handle, | 916 SECStatus status = |
| 866 check_revocation, | 917 PKIXVerifyCert(cert_handle, check_revocation, false, cert_io_enabled, |
| 867 false, | 918 NULL, 0, trust_anchors.get(), &crlset_callback, cvout); |
| 868 cert_io_enabled, | |
| 869 NULL, | |
| 870 0, | |
| 871 trust_anchors.get(), | |
| 872 chain_verify_callback, | |
| 873 cvout); | |
| 874 | 919 |
| 875 if (status == SECSuccess && | 920 if (status == SECSuccess && |
| 876 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && | 921 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && |
| 877 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) { | 922 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) { |
| 878 // TODO(rsleevi): Optimize this by supplying the constructed chain to | 923 // TODO(rsleevi): Optimize this by supplying the constructed chain to |
| 879 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream | 924 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream |
| 880 // NSS tests for that feature. | 925 // NSS tests for that feature. |
| 881 scoped_cvout.Clear(); | 926 scoped_cvout.Clear(); |
| 882 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 927 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 883 status = PKIXVerifyCert(cert_handle, | 928 status = PKIXVerifyCert(cert_handle, true, true, cert_io_enabled, NULL, 0, |
| 884 true, | 929 trust_anchors.get(), &crlset_callback, cvout); |
|
eroman
2016/03/02 00:05:07
I think it would be better to explicitly reset |ch
| |
| 885 true, | |
| 886 cert_io_enabled, | |
| 887 NULL, | |
| 888 0, | |
| 889 trust_anchors.get(), | |
| 890 chain_verify_callback, | |
| 891 cvout); | |
| 892 } | 930 } |
| 893 | 931 |
| 894 if (status == SECSuccess) { | 932 if (status == SECSuccess) { |
| 895 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, | 933 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, |
| 896 cvout[cvout_trust_anchor_index].value.pointer.cert, | 934 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 897 &verify_result->public_key_hashes); | 935 &verify_result->public_key_hashes); |
| 898 | 936 |
| 899 verify_result->is_issued_by_known_root = | 937 verify_result->is_issued_by_known_root = |
| 900 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); | 938 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); |
| 901 verify_result->is_issued_by_additional_trust_anchor = | 939 verify_result->is_issued_by_additional_trust_anchor = |
| 902 IsAdditionalTrustAnchor( | 940 IsAdditionalTrustAnchor( |
| 903 trust_anchors.get(), | 941 trust_anchors.get(), |
| 904 cvout[cvout_trust_anchor_index].value.pointer.cert); | 942 cvout[cvout_trust_anchor_index].value.pointer.cert); |
| 905 | 943 |
| 906 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, | 944 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, |
| 907 cvout[cvout_trust_anchor_index].value.pointer.cert, | 945 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 908 verify_result); | 946 verify_result); |
| 909 } | 947 } |
| 910 | 948 |
| 911 CRLSetResult crl_set_result = kCRLSetUnknown; | 949 CRLSetResult crl_set_result = kCRLSetUnknown; |
| 912 if (crl_set) { | 950 if (crl_set) { |
| 913 crl_set_result = CheckRevocationWithCRLSet( | 951 if (status == SECSuccess) { |
| 914 cvout[cvout_cert_list_index].value.pointer.chain, | 952 crl_set_result = CheckRevocationWithCRLSet( |
| 915 cvout[cvout_trust_anchor_index].value.pointer.cert, | 953 cvout[cvout_cert_list_index].value.pointer.chain, |
| 916 crl_set); | 954 cvout[cvout_trust_anchor_index].value.pointer.cert, crl_set); |
| 917 if (crl_set_result == kCRLSetRevoked) { | 955 if (crl_set_result == kCRLSetRevoked) { |
| 956 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | |
| 957 status = SECFailure; | |
| 958 } | |
| 959 } else if (PORT_GetError() == SEC_ERROR_APPLICATION_CALLBACK_ERROR && | |
| 960 check_chain_revocation_args.was_revoked) { | |
| 961 // If a CRLSet was supplied, and the error was an application callback | |
| 962 // error, then it was directed through the CRLSet code and that | |
| 963 // particular chain was revoked. | |
| 918 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | 964 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); |
| 919 status = SECFailure; | |
| 920 } | 965 } |
| 921 } | 966 } |
| 922 | 967 |
| 923 if (status != SECSuccess) { | 968 if (status != SECSuccess) { |
| 924 int err = PORT_GetError(); | 969 int err = PORT_GetError(); |
| 925 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname | 970 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname |
| 926 << " failed err=" << err; | 971 << " failed err=" << err; |
| 927 // CERT_PKIXVerifyCert rerports the wrong error code for | 972 // CERT_PKIXVerifyCert rerports the wrong error code for |
| 928 // expired certificates (NSS bug 491174) | 973 // expired certificates (NSS bug 491174) |
| 929 if (err == SEC_ERROR_CERT_NOT_VALID && | 974 if (err == SEC_ERROR_CERT_NOT_VALID && |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 942 return MapCertStatusToNetError(verify_result->cert_status); | 987 return MapCertStatusToNetError(verify_result->cert_status); |
| 943 | 988 |
| 944 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { | 989 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { |
| 945 check_revocation |= | 990 check_revocation |= |
| 946 crl_set_result != kCRLSetOk && | 991 crl_set_result != kCRLSetOk && |
| 947 cert_io_enabled && | 992 cert_io_enabled && |
| 948 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); | 993 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); |
| 949 if (check_revocation) | 994 if (check_revocation) |
| 950 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 995 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 951 | 996 |
| 952 if (VerifyEV(cert_handle, | 997 if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata, |
| 953 flags, | 998 ev_policy_oid, trust_anchors.get(), &crlset_callback)) { |
| 954 crl_set, | |
| 955 check_revocation, | |
| 956 metadata, | |
| 957 ev_policy_oid, | |
| 958 trust_anchors.get(), | |
| 959 chain_verify_callback)) { | |
| 960 verify_result->cert_status |= CERT_STATUS_IS_EV; | 999 verify_result->cert_status |= CERT_STATUS_IS_EV; |
| 961 } | 1000 } |
| 962 } | 1001 } |
| 963 | 1002 |
| 964 return OK; | 1003 return OK; |
| 965 } | 1004 } |
| 966 | 1005 |
| 967 int CertVerifyProcNSS::VerifyInternal( | 1006 int CertVerifyProcNSS::VerifyInternal( |
| 968 X509Certificate* cert, | 1007 X509Certificate* cert, |
| 969 const std::string& hostname, | 1008 const std::string& hostname, |
| 970 const std::string& ocsp_response, | 1009 const std::string& ocsp_response, |
| 971 int flags, | 1010 int flags, |
| 972 CRLSet* crl_set, | 1011 CRLSet* crl_set, |
| 973 const CertificateList& additional_trust_anchors, | 1012 const CertificateList& additional_trust_anchors, |
| 974 CertVerifyResult* verify_result) { | 1013 CertVerifyResult* verify_result) { |
| 975 return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set, | 1014 return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set, |
| 976 additional_trust_anchors, | 1015 additional_trust_anchors, |
| 977 NULL, // chain_verify_callback | 1016 NULL, // chain_verify_callback |
| 978 verify_result); | 1017 verify_result); |
| 979 } | 1018 } |
| 980 | 1019 |
| 981 } // namespace net | 1020 } // namespace net |
| OLD | NEW |