Chromium Code Reviews| Index: net/cert/cert_verify_proc_nss.cc |
| diff --git a/net/cert/cert_verify_proc_nss.cc b/net/cert/cert_verify_proc_nss.cc |
| index ca8e8116f0ef521f61539386abbc59dd57da2f21..3556a00b5385ce472c3a4e748203f14cd4741697 100644 |
| --- a/net/cert/cert_verify_proc_nss.cc |
| +++ b/net/cert/cert_verify_proc_nss.cc |
| @@ -279,7 +279,7 @@ enum CRLSetResult { |
| // that some EV sites would otherwise take the hit of an OCSP lookup for |
| // no reason. |
| // kCRLSetOk: otherwise. |
| -CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list, |
| +CRLSetResult CheckRevocationWithCRLSet(const CERTCertList* cert_list, |
| CERTCertificate* root, |
| CRLSet* crl_set) { |
| std::vector<CERTCertificate*> certs; |
| @@ -352,6 +352,50 @@ CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list, |
| return kCRLSetOk; |
| } |
| +// Arguments for CheckChainRevocationWithCRLSet that are curried within the |
| +// CERTChainVerifyCallback's isChainValidArg. |
| +struct CheckChainRevocationArgs { |
| + // The CRLSet to evaluate against. |
| + CRLSet* crl_set = nullptr; |
| + |
| + // The next callback to invoke, if the CRLSet does not report any errors. |
| + CERTChainVerifyCallback* next_callback = nullptr; |
| + |
| + // Indicates that the application callback failure was due to a CRLSet |
| + // revocation, rather than due to |next_callback| rejecting it. This is |
| + // used to map the error back to the proper caller-visible error code. |
| + bool was_revoked = false; |
| +}; |
| + |
| +SECStatus CheckChainRevocationWithCRLSet(void* is_chain_valid_arg, |
| + const CERTCertList* current_chain, |
| + PRBool* chain_ok) { |
| + CHECK(is_chain_valid_arg); |
| + |
| + CheckChainRevocationArgs* args = |
| + static_cast<CheckChainRevocationArgs*>(is_chain_valid_arg); |
| + |
| + CRLSetResult crlset_result = kCRLSetUnknown; |
| + if (args->crl_set) { |
| + crlset_result = |
| + CheckRevocationWithCRLSet(current_chain, nullptr, args->crl_set); |
| + } |
| + |
| + if (crlset_result == kCRLSetRevoked) { |
| + args->was_revoked = true; |
| + *chain_ok = PR_FALSE; |
| + return SECSuccess; |
| + } |
| + args->was_revoked = false; |
| + |
| + *chain_ok = PR_TRUE; |
| + if (!args->next_callback || !args->next_callback->isChainValid) |
| + return SECSuccess; |
| + |
| + return (*args->next_callback->isChainValid)( |
| + args->next_callback->isChainValidArg, current_chain, chain_ok); |
| +} |
| + |
| // Forward declarations. |
| SECStatus RetryPKIXVerifyCertWithWorkarounds( |
| CERTCertificate* cert_handle, int num_policy_oids, |
| @@ -825,6 +869,13 @@ int CertVerifyProcNSS::VerifyInternalImpl( |
| verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| } |
| + CheckChainRevocationArgs check_chain_revocation_args; |
| + CERTChainVerifyCallback crlset_callback; |
| + memset(&crlset_callback, 0, sizeof(crlset_callback)); |
| + crlset_callback.isChainValid = &CheckChainRevocationWithCRLSet; |
| + crlset_callback.isChainValidArg = |
| + static_cast<void*>(&check_chain_revocation_args); |
| + |
| // Make sure that the cert is valid now. |
| SECCertTimeValidity validity = CERT_CheckCertValidTimes( |
| cert_handle, PR_Now(), PR_TRUE); |
| @@ -862,15 +913,9 @@ int CertVerifyProcNSS::VerifyInternalImpl( |
| CertificateListToCERTCertList(additional_trust_anchors)); |
| } |
| - SECStatus status = PKIXVerifyCert(cert_handle, |
| - check_revocation, |
| - false, |
| - cert_io_enabled, |
| - NULL, |
| - 0, |
| - trust_anchors.get(), |
| - chain_verify_callback, |
| - cvout); |
| + SECStatus status = |
| + PKIXVerifyCert(cert_handle, check_revocation, false, cert_io_enabled, |
| + NULL, 0, trust_anchors.get(), &crlset_callback, cvout); |
| if (status == SECSuccess && |
| (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) && |
| @@ -880,15 +925,8 @@ int CertVerifyProcNSS::VerifyInternalImpl( |
| // NSS tests for that feature. |
| scoped_cvout.Clear(); |
| verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| - status = PKIXVerifyCert(cert_handle, |
| - true, |
| - true, |
| - cert_io_enabled, |
| - NULL, |
| - 0, |
| - trust_anchors.get(), |
| - chain_verify_callback, |
| - cvout); |
| + status = PKIXVerifyCert(cert_handle, true, true, cert_io_enabled, NULL, 0, |
| + trust_anchors.get(), &crlset_callback, cvout); |
|
eroman
2016/03/02 00:05:07
I think it would be better to explicitly reset |ch
|
| } |
| if (status == SECSuccess) { |
| @@ -910,13 +948,20 @@ int CertVerifyProcNSS::VerifyInternalImpl( |
| CRLSetResult crl_set_result = kCRLSetUnknown; |
| if (crl_set) { |
| - crl_set_result = CheckRevocationWithCRLSet( |
| - cvout[cvout_cert_list_index].value.pointer.chain, |
| - cvout[cvout_trust_anchor_index].value.pointer.cert, |
| - crl_set); |
| - if (crl_set_result == kCRLSetRevoked) { |
| + if (status == SECSuccess) { |
| + crl_set_result = CheckRevocationWithCRLSet( |
| + cvout[cvout_cert_list_index].value.pointer.chain, |
| + cvout[cvout_trust_anchor_index].value.pointer.cert, crl_set); |
| + if (crl_set_result == kCRLSetRevoked) { |
| + PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); |
| + status = SECFailure; |
| + } |
| + } else if (PORT_GetError() == SEC_ERROR_APPLICATION_CALLBACK_ERROR && |
| + check_chain_revocation_args.was_revoked) { |
| + // If a CRLSet was supplied, and the error was an application callback |
| + // error, then it was directed through the CRLSet code and that |
| + // particular chain was revoked. |
| PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); |
| - status = SECFailure; |
| } |
| } |
| @@ -949,14 +994,8 @@ int CertVerifyProcNSS::VerifyInternalImpl( |
| if (check_revocation) |
| verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
| - if (VerifyEV(cert_handle, |
| - flags, |
| - crl_set, |
| - check_revocation, |
| - metadata, |
| - ev_policy_oid, |
| - trust_anchors.get(), |
| - chain_verify_callback)) { |
| + if (VerifyEV(cert_handle, flags, crl_set, check_revocation, metadata, |
| + ev_policy_oid, trust_anchors.get(), &crlset_callback)) { |
| verify_result->cert_status |= CERT_STATUS_IS_EV; |
| } |
| } |