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