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 scoped_refptr<X509Certificate> CreateCertFromCERTList( | |
| 356 const CERTCertList* cert_list) { | |
| 357 X509Certificate::OSCertHandles intermediates; | |
| 358 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); | |
| 359 !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) { | |
| 360 intermediates.push_back(node->cert); | |
| 361 } | |
| 362 if (intermediates.empty()) | |
| 363 return nullptr; | |
| 364 | |
| 365 X509Certificate::OSCertHandle leaf = intermediates.front(); | |
| 366 intermediates.erase(intermediates.begin()); | |
|
eroman
2016/02/25 03:12:02
Could have avoided the erase().
Ryan Sleevi
2016/03/01 22:44:57
I'm not sure your remark here, or what you're sugg
eroman
2016/03/02 00:05:07
In the construction of intermediates vector above,
| |
| 367 #if defined(OS_IOS) | |
| 368 return x509_util_ios::CreateCertFromNSSHandles(leaf, intermediates); | |
| 369 #else | |
| 370 return X509Certificate::CreateFromHandle(leaf, intermediates); | |
| 371 #endif | |
| 372 } | |
| 373 | |
| 374 // Arguments for CheckChainRevocationWithCRLSet that are curried within the | |
| 375 // CERTChainVerifyCallback's isChainValidArg. | |
| 376 struct CheckChainRevocationArgs { | |
| 377 CRLSet* crl_set; | |
| 378 CERTChainVerifyCallback* next_callback; | |
| 379 scoped_refptr<X509Certificate> revoked_chain; | |
| 380 }; | |
| 381 | |
| 382 SECStatus CheckChainRevocationWithCRLSet(void* is_chain_valid_arg, | |
| 383 const CERTCertList* current_chain, | |
| 384 PRBool* chain_ok) { | |
| 385 if (!is_chain_valid_arg) { | |
|
eroman
2016/02/25 03:12:02
Is this actually reachable?
Ryan Sleevi
2016/03/01 22:44:57
It's NSS; the guarantees the API provides are undo
| |
| 386 *chain_ok = PR_FALSE; | |
| 387 return SECFailure; | |
| 388 } | |
| 389 | |
| 390 CheckChainRevocationArgs* args = | |
| 391 static_cast<CheckChainRevocationArgs*>(is_chain_valid_arg); | |
| 392 | |
| 393 CRLSetResult crlset_result = kCRLSetUnknown; | |
| 394 if (args->crl_set) | |
|
eroman
2016/02/25 03:12:01
curlies
| |
| 395 crlset_result = | |
| 396 CheckRevocationWithCRLSet(current_chain, nullptr, args->crl_set); | |
| 397 | |
| 398 if (crlset_result == kCRLSetRevoked) { | |
| 399 args->revoked_chain = CreateCertFromCERTList(current_chain); | |
| 400 *chain_ok = PR_FALSE; | |
| 401 return SECSuccess; | |
| 402 } | |
| 403 args->revoked_chain = nullptr; | |
| 404 | |
| 405 *chain_ok = PR_TRUE; | |
| 406 if (!args->next_callback || !args->next_callback->isChainValid) | |
|
eroman
2016/02/25 03:12:02
Is it expected that isChainValid can be NULL, or i
Ryan Sleevi
2016/03/01 22:44:57
Yes, it is; this matches the internal checks of NS
| |
| 407 return SECSuccess; | |
| 408 | |
| 409 return (*args->next_callback->isChainValid)( | |
| 410 args->next_callback->isChainValidArg, current_chain, chain_ok); | |
| 411 } | |
| 412 | |
| 355 // Forward declarations. | 413 // Forward declarations. |
| 356 SECStatus RetryPKIXVerifyCertWithWorkarounds( | 414 SECStatus RetryPKIXVerifyCertWithWorkarounds( |
| 357 CERTCertificate* cert_handle, int num_policy_oids, | 415 CERTCertificate* cert_handle, int num_policy_oids, |
| 358 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, | 416 bool cert_io_enabled, std::vector<CERTValInParam>* cvin, |
| 359 CERTValOutParam* cvout); | 417 CERTValOutParam* cvout); |
| 360 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); | 418 SECOidTag GetFirstCertPolicy(CERTCertificate* cert_handle); |
| 361 | 419 |
| 362 // Call CERT_PKIXVerifyCert for the cert_handle. | 420 // Call CERT_PKIXVerifyCert for the cert_handle. |
| 363 // Verification results are stored in an array of CERTValOutParam. | 421 // 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 | 422 // 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, | 876 cache_ocsp_response_from_side_channel_(CERT_GetDefaultCertDB(), cert_handle, |
| 819 PR_Now(), &ocsp_response_item, | 877 PR_Now(), &ocsp_response_item, |
| 820 nullptr); | 878 nullptr); |
| 821 } | 879 } |
| 822 | 880 |
| 823 if (!cert->VerifyNameMatch(hostname, | 881 if (!cert->VerifyNameMatch(hostname, |
| 824 &verify_result->common_name_fallback_used)) { | 882 &verify_result->common_name_fallback_used)) { |
| 825 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 883 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 826 } | 884 } |
| 827 | 885 |
| 886 CheckChainRevocationArgs check_chain_revocation_args; | |
| 887 check_chain_revocation_args.crl_set = crl_set; | |
| 888 check_chain_revocation_args.next_callback = chain_verify_callback; | |
| 889 check_chain_revocation_args.revoked_chain = nullptr; | |
|
eroman
2016/02/25 03:12:01
could have omitted this unless you are trying to b
Ryan Sleevi
2016/03/01 22:44:58
crl_set and next_callback are pointer types; they
eroman
2016/03/02 00:05:07
I was referring to revoked_chain, which is a scope
| |
| 890 | |
| 891 CERTChainVerifyCallback crlset_callback; | |
| 892 memset(&crlset_callback, 0, sizeof(crlset_callback)); | |
| 893 crlset_callback.isChainValid = &CheckChainRevocationWithCRLSet; | |
| 894 crlset_callback.isChainValidArg = | |
| 895 static_cast<void*>(&check_chain_revocation_args); | |
| 896 | |
| 828 // Make sure that the cert is valid now. | 897 // Make sure that the cert is valid now. |
| 829 SECCertTimeValidity validity = CERT_CheckCertValidTimes( | 898 SECCertTimeValidity validity = CERT_CheckCertValidTimes( |
| 830 cert_handle, PR_Now(), PR_TRUE); | 899 cert_handle, PR_Now(), PR_TRUE); |
| 831 if (validity != secCertTimeValid) | 900 if (validity != secCertTimeValid) |
| 832 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 901 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| 833 | 902 |
| 834 CERTValOutParam cvout[3]; | 903 CERTValOutParam cvout[3]; |
| 835 int cvout_index = 0; | 904 int cvout_index = 0; |
| 836 cvout[cvout_index].type = cert_po_certList; | 905 cvout[cvout_index].type = cert_po_certList; |
| 837 cvout[cvout_index].value.pointer.chain = NULL; | 906 cvout[cvout_index].value.pointer.chain = NULL; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 855 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); | 924 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED); |
| 856 if (check_revocation) | 925 if (check_revocation) |
| 857 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 926 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 858 | 927 |
| 859 ScopedCERTCertList trust_anchors; | 928 ScopedCERTCertList trust_anchors; |
| 860 if (!additional_trust_anchors.empty()) { | 929 if (!additional_trust_anchors.empty()) { |
| 861 trust_anchors.reset( | 930 trust_anchors.reset( |
| 862 CertificateListToCERTCertList(additional_trust_anchors)); | 931 CertificateListToCERTCertList(additional_trust_anchors)); |
| 863 } | 932 } |
| 864 | 933 |
| 865 SECStatus status = PKIXVerifyCert(cert_handle, | 934 SECStatus status = |
| 866 check_revocation, | 935 PKIXVerifyCert(cert_handle, check_revocation, false, cert_io_enabled, |
| 867 false, | 936 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 | 937 |
| 875 if (status == SECSuccess && | 938 if (status == SECSuccess && |
| 876 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && | 939 (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && |
| 877 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) { | 940 !IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert)) { |
| 878 // TODO(rsleevi): Optimize this by supplying the constructed chain to | 941 // TODO(rsleevi): Optimize this by supplying the constructed chain to |
| 879 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream | 942 // libpkix via cvin. Omitting for now, due to lack of coverage in upstream |
| 880 // NSS tests for that feature. | 943 // NSS tests for that feature. |
| 881 scoped_cvout.Clear(); | 944 scoped_cvout.Clear(); |
| 882 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 945 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 883 status = PKIXVerifyCert(cert_handle, | 946 status = PKIXVerifyCert(cert_handle, true, true, cert_io_enabled, NULL, 0, |
| 884 true, | 947 trust_anchors.get(), &crlset_callback, cvout); |
| 885 true, | |
| 886 cert_io_enabled, | |
| 887 NULL, | |
| 888 0, | |
| 889 trust_anchors.get(), | |
| 890 chain_verify_callback, | |
| 891 cvout); | |
| 892 } | 948 } |
| 893 | 949 |
| 894 if (status == SECSuccess) { | 950 if (status == SECSuccess) { |
| 895 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, | 951 AppendPublicKeyHashes(cvout[cvout_cert_list_index].value.pointer.chain, |
| 896 cvout[cvout_trust_anchor_index].value.pointer.cert, | 952 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 897 &verify_result->public_key_hashes); | 953 &verify_result->public_key_hashes); |
| 898 | 954 |
| 899 verify_result->is_issued_by_known_root = | 955 verify_result->is_issued_by_known_root = |
| 900 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); | 956 IsKnownRoot(cvout[cvout_trust_anchor_index].value.pointer.cert); |
| 901 verify_result->is_issued_by_additional_trust_anchor = | 957 verify_result->is_issued_by_additional_trust_anchor = |
| 902 IsAdditionalTrustAnchor( | 958 IsAdditionalTrustAnchor( |
| 903 trust_anchors.get(), | 959 trust_anchors.get(), |
| 904 cvout[cvout_trust_anchor_index].value.pointer.cert); | 960 cvout[cvout_trust_anchor_index].value.pointer.cert); |
| 905 | 961 |
| 906 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, | 962 GetCertChainInfo(cvout[cvout_cert_list_index].value.pointer.chain, |
| 907 cvout[cvout_trust_anchor_index].value.pointer.cert, | 963 cvout[cvout_trust_anchor_index].value.pointer.cert, |
| 908 verify_result); | 964 verify_result); |
| 909 } | 965 } |
| 910 | 966 |
| 911 CRLSetResult crl_set_result = kCRLSetUnknown; | 967 CRLSetResult crl_set_result = kCRLSetUnknown; |
| 912 if (crl_set) { | 968 if (crl_set) { |
| 913 crl_set_result = CheckRevocationWithCRLSet( | 969 if (status == SECSuccess) { |
| 914 cvout[cvout_cert_list_index].value.pointer.chain, | 970 crl_set_result = CheckRevocationWithCRLSet( |
|
eroman
2016/02/25 03:12:02
Wasn't this already called by PKIXVerifyCert() on
Ryan Sleevi
2016/03/01 22:44:57
As with the Windows code, we're taking a defense i
| |
| 915 cvout[cvout_trust_anchor_index].value.pointer.cert, | 971 cvout[cvout_cert_list_index].value.pointer.chain, |
| 916 crl_set); | 972 cvout[cvout_trust_anchor_index].value.pointer.cert, crl_set); |
| 917 if (crl_set_result == kCRLSetRevoked) { | 973 if (crl_set_result == kCRLSetRevoked) { |
| 974 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | |
| 975 status = SECFailure; | |
| 976 } | |
| 977 } else if (PORT_GetError() == SEC_ERROR_APPLICATION_CALLBACK_ERROR && | |
| 978 check_chain_revocation_args.revoked_chain) { | |
|
eroman
2016/02/25 03:12:02
It doesn't look like the revoked_chain is every co
Ryan Sleevi
2016/03/01 22:44:58
You're right; I was originally going to sub in the
| |
| 979 // If a CRLSet was supplied, and the error was an application callback | |
| 980 // error, then it was directed through the CRLSet code and that | |
| 981 // particular chain was revoked. | |
| 918 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); | 982 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); |
| 919 status = SECFailure; | |
| 920 } | 983 } |
| 921 } | 984 } |
| 922 | 985 |
| 923 if (status != SECSuccess) { | 986 if (status != SECSuccess) { |
| 924 int err = PORT_GetError(); | 987 int err = PORT_GetError(); |
| 925 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname | 988 LOG(ERROR) << "CERT_PKIXVerifyCert for " << hostname |
| 926 << " failed err=" << err; | 989 << " failed err=" << err; |
| 927 // CERT_PKIXVerifyCert rerports the wrong error code for | 990 // CERT_PKIXVerifyCert rerports the wrong error code for |
| 928 // expired certificates (NSS bug 491174) | 991 // expired certificates (NSS bug 491174) |
| 929 if (err == SEC_ERROR_CERT_NOT_VALID && | 992 if (err == SEC_ERROR_CERT_NOT_VALID && |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 942 return MapCertStatusToNetError(verify_result->cert_status); | 1005 return MapCertStatusToNetError(verify_result->cert_status); |
| 943 | 1006 |
| 944 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { | 1007 if ((flags & CertVerifier::VERIFY_EV_CERT) && is_ev_candidate) { |
| 945 check_revocation |= | 1008 check_revocation |= |
| 946 crl_set_result != kCRLSetOk && | 1009 crl_set_result != kCRLSetOk && |
| 947 cert_io_enabled && | 1010 cert_io_enabled && |
| 948 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); | 1011 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED_EV_ONLY); |
| 949 if (check_revocation) | 1012 if (check_revocation) |
| 950 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 1013 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| 951 | 1014 |
| 952 if (VerifyEV(cert_handle, | 1015 if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata, |
| 953 flags, | 1016 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; | 1017 verify_result->cert_status |= CERT_STATUS_IS_EV; |
| 961 } | 1018 } |
| 962 } | 1019 } |
| 963 | 1020 |
| 964 return OK; | 1021 return OK; |
| 965 } | 1022 } |
| 966 | 1023 |
| 967 int CertVerifyProcNSS::VerifyInternal( | 1024 int CertVerifyProcNSS::VerifyInternal( |
| 968 X509Certificate* cert, | 1025 X509Certificate* cert, |
| 969 const std::string& hostname, | 1026 const std::string& hostname, |
| 970 const std::string& ocsp_response, | 1027 const std::string& ocsp_response, |
| 971 int flags, | 1028 int flags, |
| 972 CRLSet* crl_set, | 1029 CRLSet* crl_set, |
| 973 const CertificateList& additional_trust_anchors, | 1030 const CertificateList& additional_trust_anchors, |
| 974 CertVerifyResult* verify_result) { | 1031 CertVerifyResult* verify_result) { |
| 975 return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set, | 1032 return VerifyInternalImpl(cert, hostname, ocsp_response, flags, crl_set, |
| 976 additional_trust_anchors, | 1033 additional_trust_anchors, |
| 977 NULL, // chain_verify_callback | 1034 NULL, // chain_verify_callback |
| 978 verify_result); | 1035 verify_result); |
| 979 } | 1036 } |
| 980 | 1037 |
| 981 } // namespace net | 1038 } // namespace net |
| OLD | NEW |