LCOV - code coverage report
Current view: top level - security/certverifier - CertVerifier.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 23 409 5.6 %
Date: 2017-07-14 16:53:18 Functions: 2 12 16.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "CertVerifier.h"
       8             : 
       9             : #include <stdint.h>
      10             : 
      11             : #include "CTDiversityPolicy.h"
      12             : #include "CTKnownLogs.h"
      13             : #include "CTLogVerifier.h"
      14             : #include "ExtendedValidation.h"
      15             : #include "MultiLogCTVerifier.h"
      16             : #include "NSSCertDBTrustDomain.h"
      17             : #include "NSSErrorsService.h"
      18             : #include "cert.h"
      19             : #include "mozilla/Assertions.h"
      20             : #include "mozilla/Casting.h"
      21             : #include "mozilla/IntegerPrintfMacros.h"
      22             : #include "nsNSSComponent.h"
      23             : #include "nsPromiseFlatString.h"
      24             : #include "nsServiceManagerUtils.h"
      25             : #include "pk11pub.h"
      26             : #include "pkix/pkix.h"
      27             : #include "pkix/pkixnss.h"
      28             : #include "secmod.h"
      29             : 
      30             : using namespace mozilla::ct;
      31             : using namespace mozilla::pkix;
      32             : using namespace mozilla::psm;
      33             : 
      34             : mozilla::LazyLogModule gCertVerifierLog("certverifier");
      35             : 
      36             : // Returns the certificate validity period in calendar months (rounded down).
      37             : // "extern" to allow unit tests in CTPolicyEnforcerTest.cpp.
      38             : extern mozilla::pkix::Result
      39           0 : GetCertLifetimeInFullMonths(PRTime certNotBefore,
      40             :                             PRTime certNotAfter,
      41             :                             size_t& months)
      42             : {
      43           0 :   if (certNotBefore >= certNotAfter) {
      44           0 :     MOZ_ASSERT_UNREACHABLE("Expected notBefore < notAfter");
      45             :     return mozilla::pkix::Result::FATAL_ERROR_INVALID_ARGS;
      46             :   }
      47             : 
      48             :   PRExplodedTime explodedNotBefore;
      49             :   PRExplodedTime explodedNotAfter;
      50             : 
      51           0 :   PR_ExplodeTime(certNotBefore, PR_LocalTimeParameters, &explodedNotBefore);
      52           0 :   PR_ExplodeTime(certNotAfter, PR_LocalTimeParameters, &explodedNotAfter);
      53             : 
      54             :   PRInt32 signedMonths =
      55           0 :     (explodedNotAfter.tm_year - explodedNotBefore.tm_year) * 12 +
      56           0 :     (explodedNotAfter.tm_month - explodedNotBefore.tm_month);
      57           0 :   if (explodedNotAfter.tm_mday < explodedNotBefore.tm_mday) {
      58           0 :     --signedMonths;
      59             :   }
      60             : 
      61             :   // Can't use `mozilla::AssertedCast<size_t>(signedMonths)` below
      62             :   // since it currently generates a warning on Win x64 debug.
      63           0 :   if (signedMonths < 0) {
      64           0 :     MOZ_ASSERT_UNREACHABLE("Expected explodedNotBefore < explodedNotAfter");
      65             :     return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
      66             :   }
      67           0 :   months = static_cast<size_t>(signedMonths);
      68             : 
      69           0 :   return Success;
      70             : }
      71             : 
      72             : namespace mozilla { namespace psm {
      73             : 
      74             : const CertVerifier::Flags CertVerifier::FLAG_LOCAL_ONLY = 1;
      75             : const CertVerifier::Flags CertVerifier::FLAG_MUST_BE_EV = 2;
      76             : const CertVerifier::Flags CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST = 4;
      77             : 
      78             : void
      79           0 : CertificateTransparencyInfo::Reset()
      80             : {
      81           0 :   enabled = false;
      82           0 :   verifyResult.Reset();
      83           0 :   policyCompliance = CTPolicyCompliance::Unknown;
      84           0 : }
      85             : 
      86           1 : CertVerifier::CertVerifier(OcspDownloadConfig odc,
      87             :                            OcspStrictConfig osc,
      88             :                            OcspGetConfig ogc,
      89             :                            mozilla::TimeDuration ocspTimeoutSoft,
      90             :                            mozilla::TimeDuration ocspTimeoutHard,
      91             :                            uint32_t certShortLifetimeInDays,
      92             :                            PinningMode pinningMode,
      93             :                            SHA1Mode sha1Mode,
      94             :                            BRNameMatchingPolicy::Mode nameMatchingMode,
      95             :                            NetscapeStepUpPolicy netscapeStepUpPolicy,
      96           1 :                            CertificateTransparencyMode ctMode)
      97             :   : mOCSPDownloadConfig(odc)
      98           1 :   , mOCSPStrict(osc == ocspStrict)
      99           1 :   , mOCSPGETEnabled(ogc == ocspGetEnabled)
     100             :   , mOCSPTimeoutSoft(ocspTimeoutSoft)
     101             :   , mOCSPTimeoutHard(ocspTimeoutHard)
     102             :   , mCertShortLifetimeInDays(certShortLifetimeInDays)
     103             :   , mPinningMode(pinningMode)
     104             :   , mSHA1Mode(sha1Mode)
     105             :   , mNameMatchingMode(nameMatchingMode)
     106             :   , mNetscapeStepUpPolicy(netscapeStepUpPolicy)
     107           3 :   , mCTMode(ctMode)
     108             : {
     109           1 :   LoadKnownCTLogs();
     110           1 : }
     111             : 
     112           0 : CertVerifier::~CertVerifier()
     113             : {
     114           0 : }
     115             : 
     116             : Result
     117           0 : IsCertChainRootBuiltInRoot(const UniqueCERTCertList& chain, bool& result)
     118             : {
     119           0 :   if (!chain || CERT_LIST_EMPTY(chain)) {
     120           0 :     return Result::FATAL_ERROR_LIBRARY_FAILURE;
     121             :   }
     122           0 :   CERTCertListNode* rootNode = CERT_LIST_TAIL(chain);
     123           0 :   if (!rootNode) {
     124           0 :     return Result::FATAL_ERROR_LIBRARY_FAILURE;
     125             :   }
     126           0 :   CERTCertificate* root = rootNode->cert;
     127           0 :   if (!root) {
     128           0 :     return Result::FATAL_ERROR_LIBRARY_FAILURE;
     129             :   }
     130           0 :   return IsCertBuiltInRoot(root, result);
     131             : }
     132             : 
     133             : // The term "builtin root" traditionally refers to a root CA certificate that
     134             : // has been added to the NSS trust store, because it has been approved
     135             : // for inclusion according to the Mozilla CA policy, and might be accepted
     136             : // by Mozilla applications as an issuer for certificates seen on the public web.
     137             : Result
     138           0 : IsCertBuiltInRoot(CERTCertificate* cert, bool& result)
     139             : {
     140           0 :   result = false;
     141             : #ifdef DEBUG
     142           0 :   nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
     143           0 :   if (!component) {
     144           0 :     return Result::FATAL_ERROR_LIBRARY_FAILURE;
     145             :   }
     146           0 :   nsresult rv = component->IsCertTestBuiltInRoot(cert, result);
     147           0 :   if (NS_FAILED(rv)) {
     148           0 :     return Result::FATAL_ERROR_LIBRARY_FAILURE;
     149             :   }
     150           0 :   if (result) {
     151           0 :     return Success;
     152             :   }
     153             : #endif // DEBUG
     154           0 :   AutoSECMODListReadLock lock;
     155           0 :   for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
     156           0 :        list = list->next) {
     157           0 :     for (int i = 0; i < list->module->slotCount; i++) {
     158           0 :       PK11SlotInfo* slot = list->module->slots[i];
     159             :       // We're searching for the "builtin root module", which is a module that
     160             :       // contains an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST.
     161             :       // We use PK11_HasRootCerts() to identify a module with that property.
     162             :       // In the past, we exclusively used the PKCS#11 module named nssckbi,
     163             :       // which is provided by the NSS library.
     164             :       // Nowadays, some distributions use a replacement module, which contains
     165             :       // the builtin roots, but which also contains additional CA certificates,
     166             :       // such as CAs trusted in a local deployment.
     167             :       // We want to be able to distinguish between these two categories,
     168             :       // because a CA, which may issue certificates for the public web,
     169             :       // is expected to comply with additional requirements.
     170             :       // If the certificate has attribute CKA_NSS_MOZILLA_CA_POLICY set to true,
     171             :       // then we treat it as a "builtin root".
     172           0 :       if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) {
     173           0 :         CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, cert, nullptr);
     174           0 :         if (handle != CK_INVALID_HANDLE &&
     175           0 :             PK11_HasAttributeSet(slot, handle, CKA_NSS_MOZILLA_CA_POLICY,
     176             :                                  false)) {
     177             :           // Attribute was found, and is set to true
     178           0 :           result = true;
     179           0 :           break;
     180             :         }
     181             :       }
     182             :     }
     183             :   }
     184           0 :   return Success;
     185             : }
     186             : 
     187             : static Result
     188           0 : BuildCertChainForOneKeyUsage(NSSCertDBTrustDomain& trustDomain, Input certDER,
     189             :                              Time time, KeyUsage ku1, KeyUsage ku2,
     190             :                              KeyUsage ku3, KeyPurposeId eku,
     191             :                              const CertPolicyId& requiredPolicy,
     192             :                              const Input* stapledOCSPResponse,
     193             :                              /*optional out*/ CertVerifier::OCSPStaplingStatus*
     194             :                                                 ocspStaplingStatus)
     195             : {
     196           0 :   trustDomain.ResetAccumulatedState();
     197           0 :   Result rv = BuildCertChain(trustDomain, certDER, time,
     198             :                              EndEntityOrCA::MustBeEndEntity, ku1,
     199           0 :                              eku, requiredPolicy, stapledOCSPResponse);
     200           0 :   if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
     201           0 :     trustDomain.ResetAccumulatedState();
     202           0 :     rv = BuildCertChain(trustDomain, certDER, time,
     203             :                         EndEntityOrCA::MustBeEndEntity, ku2,
     204           0 :                         eku, requiredPolicy, stapledOCSPResponse);
     205           0 :     if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
     206           0 :       trustDomain.ResetAccumulatedState();
     207           0 :       rv = BuildCertChain(trustDomain, certDER, time,
     208             :                           EndEntityOrCA::MustBeEndEntity, ku3,
     209           0 :                           eku, requiredPolicy, stapledOCSPResponse);
     210           0 :       if (rv != Success) {
     211           0 :         rv = Result::ERROR_INADEQUATE_KEY_USAGE;
     212             :       }
     213             :     }
     214             :   }
     215           0 :   if (ocspStaplingStatus) {
     216           0 :     *ocspStaplingStatus = trustDomain.GetOCSPStaplingStatus();
     217             :   }
     218           0 :   return rv;
     219             : }
     220             : 
     221             : void
     222           1 : CertVerifier::LoadKnownCTLogs()
     223             : {
     224           1 :   mCTVerifier = MakeUnique<MultiLogCTVerifier>();
     225          16 :   for (const CTLogInfo& log : kCTLogList) {
     226          15 :     Input publicKey;
     227          15 :     Result rv = publicKey.Init(
     228          30 :       BitwiseCast<const uint8_t*, const char*>(log.key), log.keyLength);
     229          15 :     if (rv != Success) {
     230           0 :       MOZ_ASSERT_UNREACHABLE("Failed reading a log key for a known CT Log");
     231           0 :       continue;
     232             :     }
     233             : 
     234          30 :     CTLogVerifier logVerifier;
     235             :     const CTLogOperatorInfo& logOperator =
     236          15 :       kCTLogOperatorList[log.operatorIndex];
     237          15 :     rv = logVerifier.Init(publicKey, logOperator.id, log.status,
     238          30 :                           log.disqualificationTime);
     239          15 :     if (rv != Success) {
     240           0 :       MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
     241             :       continue;
     242             :     }
     243             : 
     244          15 :     rv = mCTVerifier->AddLog(Move(logVerifier));
     245          15 :     if (rv != Success) {
     246           0 :       MOZ_ASSERT_UNREACHABLE("Failed activating a known CT Log");
     247             :       continue;
     248             :     }
     249             :   }
     250             :   // TBD: Initialize mCTDiversityPolicy with the CA dependency map
     251             :   // of the known CT logs operators.
     252           1 :   mCTDiversityPolicy = MakeUnique<CTDiversityPolicy>();
     253           1 : }
     254             : 
     255             : Result
     256           0 : CertVerifier::VerifyCertificateTransparencyPolicy(
     257             :   NSSCertDBTrustDomain& trustDomain, const UniqueCERTCertList& builtChain,
     258             :   Input sctsFromTLS, Time time,
     259             :   /*optional out*/ CertificateTransparencyInfo* ctInfo)
     260             : {
     261           0 :   if (ctInfo) {
     262           0 :     ctInfo->Reset();
     263             :   }
     264           0 :   if (mCTMode == CertificateTransparencyMode::Disabled) {
     265           0 :     return Success;
     266             :   }
     267           0 :   if (ctInfo) {
     268           0 :     ctInfo->enabled = true;
     269             :   }
     270             : 
     271           0 :   if (!builtChain || CERT_LIST_EMPTY(builtChain)) {
     272           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     273             :   }
     274             : 
     275           0 :   Input embeddedSCTs = trustDomain.GetSCTListFromCertificate();
     276           0 :   if (embeddedSCTs.GetLength() > 0) {
     277           0 :     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     278             :             ("Got embedded SCT data of length %zu\n",
     279             :               static_cast<size_t>(embeddedSCTs.GetLength())));
     280             :   }
     281           0 :   Input sctsFromOCSP = trustDomain.GetSCTListFromOCSPStapling();
     282           0 :   if (sctsFromOCSP.GetLength() > 0) {
     283           0 :     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     284             :             ("Got OCSP SCT data of length %zu\n",
     285             :               static_cast<size_t>(sctsFromOCSP.GetLength())));
     286             :   }
     287           0 :   if (sctsFromTLS.GetLength() > 0) {
     288           0 :     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     289             :             ("Got TLS SCT data of length %zu\n",
     290             :               static_cast<size_t>(sctsFromTLS.GetLength())));
     291             :   }
     292             : 
     293           0 :   CERTCertListNode* endEntityNode = CERT_LIST_HEAD(builtChain);
     294           0 :   if (!endEntityNode || CERT_LIST_END(endEntityNode, builtChain)) {
     295           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     296             :   }
     297           0 :   CERTCertListNode* issuerNode = CERT_LIST_NEXT(endEntityNode);
     298           0 :   if (!issuerNode || CERT_LIST_END(issuerNode, builtChain)) {
     299             :     // Issuer certificate is required for SCT verification.
     300           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     301             :   }
     302             : 
     303           0 :   CERTCertificate* endEntity = endEntityNode->cert;
     304           0 :   CERTCertificate* issuer = issuerNode->cert;
     305           0 :   if (!endEntity || !issuer) {
     306           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     307             :   }
     308             : 
     309           0 :   if (endEntity->subjectName) {
     310           0 :     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     311             :             ("Verifying CT Policy compliance of subject %s\n",
     312             :              endEntity->subjectName));
     313             :   }
     314             : 
     315           0 :   Input endEntityDER;
     316           0 :   Result rv = endEntityDER.Init(endEntity->derCert.data,
     317           0 :                                 endEntity->derCert.len);
     318           0 :   if (rv != Success) {
     319           0 :     return rv;
     320             :   }
     321             : 
     322           0 :   Input issuerPublicKeyDER;
     323           0 :   rv = issuerPublicKeyDER.Init(issuer->derPublicKey.data,
     324           0 :                                issuer->derPublicKey.len);
     325           0 :   if (rv != Success) {
     326           0 :     return rv;
     327             :   }
     328             : 
     329           0 :   CTVerifyResult result;
     330           0 :   rv = mCTVerifier->Verify(endEntityDER, issuerPublicKeyDER,
     331             :                            embeddedSCTs, sctsFromOCSP, sctsFromTLS, time,
     332           0 :                            result);
     333           0 :   if (rv != Success) {
     334           0 :     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     335             :             ("SCT verification failed with fatal error %" PRId32 "\n",
     336             :              static_cast<uint32_t>(rv)));
     337           0 :     return rv;
     338             :   }
     339             : 
     340           0 :   if (MOZ_LOG_TEST(gCertVerifierLog, LogLevel::Debug)) {
     341           0 :     size_t validCount = 0;
     342           0 :     size_t unknownLogCount = 0;
     343           0 :     size_t disqualifiedLogCount = 0;
     344           0 :     size_t invalidSignatureCount = 0;
     345           0 :     size_t invalidTimestampCount = 0;
     346           0 :     for (const VerifiedSCT& verifiedSct : result.verifiedScts) {
     347           0 :       switch (verifiedSct.status) {
     348             :         case VerifiedSCT::Status::Valid:
     349           0 :           validCount++;
     350           0 :           break;
     351             :         case VerifiedSCT::Status::ValidFromDisqualifiedLog:
     352           0 :           disqualifiedLogCount++;
     353           0 :           break;
     354             :         case VerifiedSCT::Status::UnknownLog:
     355           0 :           unknownLogCount++;
     356           0 :           break;
     357             :         case VerifiedSCT::Status::InvalidSignature:
     358           0 :           invalidSignatureCount++;
     359           0 :           break;
     360             :         case VerifiedSCT::Status::InvalidTimestamp:
     361           0 :           invalidTimestampCount++;
     362           0 :           break;
     363             :         case VerifiedSCT::Status::None:
     364             :         default:
     365           0 :           MOZ_ASSERT_UNREACHABLE("Unexpected SCT verification status");
     366             :       }
     367             :     }
     368           0 :     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     369             :             ("SCT verification result: "
     370             :              "valid=%zu unknownLog=%zu disqualifiedLog=%zu "
     371             :              "invalidSignature=%zu invalidTimestamp=%zu "
     372             :              "decodingErrors=%zu\n",
     373             :              validCount, unknownLogCount, disqualifiedLogCount,
     374             :              invalidSignatureCount, invalidTimestampCount,
     375             :              result.decodingErrors));
     376             :   }
     377             : 
     378             :   PRTime notBefore;
     379             :   PRTime notAfter;
     380           0 :   if (CERT_GetCertTimes(endEntity, &notBefore, &notAfter) != SECSuccess) {
     381           0 :     return Result::FATAL_ERROR_LIBRARY_FAILURE;
     382             :   }
     383             :   size_t lifetimeInMonths;
     384           0 :   rv = GetCertLifetimeInFullMonths(notBefore, notAfter, lifetimeInMonths);
     385           0 :   if (rv != Success) {
     386           0 :     return rv;
     387             :   }
     388             : 
     389           0 :   CTLogOperatorList allOperators;
     390             :   rv = GetCTLogOperatorsFromVerifiedSCTList(result.verifiedScts,
     391           0 :                                             allOperators);
     392           0 :   if (rv != Success) {
     393           0 :     return rv;
     394             :   }
     395             : 
     396           0 :   CTLogOperatorList dependentOperators;
     397           0 :   rv = mCTDiversityPolicy->GetDependentOperators(builtChain, allOperators,
     398           0 :                                                  dependentOperators);
     399           0 :   if (rv != Success) {
     400           0 :     return rv;
     401             :   }
     402             : 
     403             :   CTPolicyEnforcer ctPolicyEnforcer;
     404             :   CTPolicyCompliance ctPolicyCompliance;
     405           0 :   rv = ctPolicyEnforcer.CheckCompliance(result.verifiedScts, lifetimeInMonths,
     406           0 :                                         dependentOperators, ctPolicyCompliance);
     407           0 :   if (rv != Success) {
     408           0 :     MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     409             :             ("CT policy check failed with fatal error %" PRIu32 "\n",
     410             :              static_cast<uint32_t>(rv)));
     411           0 :     return rv;
     412             :   }
     413             : 
     414           0 :   if (ctInfo) {
     415           0 :     ctInfo->verifyResult = Move(result);
     416           0 :     ctInfo->policyCompliance = ctPolicyCompliance;
     417             :   }
     418           0 :   return Success;
     419             : }
     420             : 
     421             : bool
     422           0 : CertVerifier::SHA1ModeMoreRestrictiveThanGivenMode(SHA1Mode mode)
     423             : {
     424           0 :   switch (mSHA1Mode) {
     425             :     case SHA1Mode::Forbidden:
     426           0 :       return mode != SHA1Mode::Forbidden;
     427             :     case SHA1Mode::ImportedRoot:
     428           0 :       return mode != SHA1Mode::Forbidden && mode != SHA1Mode::ImportedRoot;
     429             :     case SHA1Mode::ImportedRootOrBefore2016:
     430           0 :       return mode == SHA1Mode::Allowed;
     431             :     case SHA1Mode::Allowed:
     432           0 :       return false;
     433             :     // MSVC warns unless we explicitly handle this now-unused option.
     434             :     case SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
     435             :     default:
     436           0 :       MOZ_ASSERT(false, "unexpected SHA1Mode type");
     437             :       return true;
     438             :   }
     439             : }
     440             : 
     441             : static const unsigned int MIN_RSA_BITS = 2048;
     442             : static const unsigned int MIN_RSA_BITS_WEAK = 1024;
     443             : 
     444             : Result
     445           0 : CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
     446             :                          Time time, void* pinArg, const char* hostname,
     447             :                  /*out*/ UniqueCERTCertList& builtChain,
     448             :             /*optional*/ UniqueCERTCertList* peerCertChain,
     449             :             /*optional*/ const Flags flags,
     450             :             /*optional*/ const SECItem* stapledOCSPResponseSECItem,
     451             :             /*optional*/ const SECItem* sctsFromTLSSECItem,
     452             :             /*optional*/ const OriginAttributes& originAttributes,
     453             :         /*optional out*/ SECOidTag* evOidPolicy,
     454             :         /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
     455             :         /*optional out*/ KeySizeStatus* keySizeStatus,
     456             :         /*optional out*/ SHA1ModeResult* sha1ModeResult,
     457             :         /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
     458             :         /*optional out*/ CertificateTransparencyInfo* ctInfo)
     459             : {
     460           0 :   MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Top of VerifyCert\n"));
     461             : 
     462           0 :   MOZ_ASSERT(cert);
     463           0 :   MOZ_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
     464           0 :   MOZ_ASSERT(usage == certificateUsageSSLServer || !keySizeStatus);
     465           0 :   MOZ_ASSERT(usage == certificateUsageSSLServer || !sha1ModeResult);
     466             : 
     467           0 :   if (evOidPolicy) {
     468           0 :     *evOidPolicy = SEC_OID_UNKNOWN;
     469             :   }
     470           0 :   if (ocspStaplingStatus) {
     471           0 :     if (usage != certificateUsageSSLServer) {
     472           0 :       return Result::FATAL_ERROR_INVALID_ARGS;
     473             :     }
     474           0 :     *ocspStaplingStatus = OCSP_STAPLING_NEVER_CHECKED;
     475             :   }
     476             : 
     477           0 :   if (keySizeStatus) {
     478           0 :     if (usage != certificateUsageSSLServer) {
     479           0 :       return Result::FATAL_ERROR_INVALID_ARGS;
     480             :     }
     481           0 :     *keySizeStatus = KeySizeStatus::NeverChecked;
     482             :   }
     483             : 
     484           0 :   if (sha1ModeResult) {
     485           0 :     if (usage != certificateUsageSSLServer) {
     486           0 :       return Result::FATAL_ERROR_INVALID_ARGS;
     487             :     }
     488           0 :     *sha1ModeResult = SHA1ModeResult::NeverChecked;
     489             :   }
     490             : 
     491           0 :   if (!cert ||
     492           0 :       (usage != certificateUsageSSLServer && (flags & FLAG_MUST_BE_EV))) {
     493           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
     494             :   }
     495             : 
     496           0 :   Input certDER;
     497           0 :   Result rv = certDER.Init(cert->derCert.data, cert->derCert.len);
     498           0 :   if (rv != Success) {
     499           0 :     return rv;
     500             :   }
     501             : 
     502             :   // We configure the OCSP fetching modes separately for EV and non-EV
     503             :   // verifications.
     504             :   NSSCertDBTrustDomain::OCSPFetching defaultOCSPFetching
     505           0 :     = (mOCSPDownloadConfig == ocspOff) ||
     506           0 :       (mOCSPDownloadConfig == ocspEVOnly) ||
     507           0 :       (flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::NeverFetchOCSP
     508           0 :     : !mOCSPStrict              ? NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
     509           0 :                                 : NSSCertDBTrustDomain::FetchOCSPForDVHardFail;
     510             : 
     511           0 :   OcspGetConfig ocspGETConfig = mOCSPGETEnabled ? ocspGetEnabled
     512           0 :                                                 : ocspGetDisabled;
     513             : 
     514           0 :   Input stapledOCSPResponseInput;
     515           0 :   const Input* stapledOCSPResponse = nullptr;
     516           0 :   if (stapledOCSPResponseSECItem) {
     517           0 :     rv = stapledOCSPResponseInput.Init(stapledOCSPResponseSECItem->data,
     518           0 :                                        stapledOCSPResponseSECItem->len);
     519           0 :     if (rv != Success) {
     520             :       // The stapled OCSP response was too big.
     521           0 :       return Result::ERROR_OCSP_MALFORMED_RESPONSE;
     522             :     }
     523           0 :     stapledOCSPResponse = &stapledOCSPResponseInput;
     524             :   }
     525             : 
     526           0 :   Input sctsFromTLSInput;
     527           0 :   if (sctsFromTLSSECItem) {
     528           0 :     rv = sctsFromTLSInput.Init(sctsFromTLSSECItem->data,
     529           0 :                                sctsFromTLSSECItem->len);
     530             :     // Silently discard the error of the extension being too big,
     531             :     // do not fail the verification.
     532           0 :     MOZ_ASSERT(rv == Success);
     533             :   }
     534             : 
     535           0 :   switch (usage) {
     536             :     case certificateUsageSSLClient: {
     537             :       // XXX: We don't really have a trust bit for SSL client authentication so
     538             :       // just use trustEmail as it is the closest alternative.
     539             :       NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
     540             :                                        mOCSPCache, pinArg, ocspGETConfig,
     541             :                                        mOCSPTimeoutSoft, mOCSPTimeoutHard,
     542           0 :                                        mCertShortLifetimeInDays,
     543             :                                        pinningDisabled, MIN_RSA_BITS_WEAK,
     544             :                                        ValidityCheckingMode::CheckingOff,
     545             :                                        SHA1Mode::Allowed,
     546             :                                        NetscapeStepUpPolicy::NeverMatch,
     547             :                                        originAttributes,
     548             :                                        builtChain, peerCertChain, nullptr,
     549           0 :                                        nullptr);
     550             :       rv = BuildCertChain(trustDomain, certDER, time,
     551             :                           EndEntityOrCA::MustBeEndEntity,
     552             :                           KeyUsage::digitalSignature,
     553             :                           KeyPurposeId::id_kp_clientAuth,
     554           0 :                           CertPolicyId::anyPolicy, stapledOCSPResponse);
     555           0 :       break;
     556             :     }
     557             : 
     558             :     case certificateUsageSSLServer: {
     559             :       // TODO: When verifying a certificate in an SSL handshake, we should
     560             :       // restrict the acceptable key usage based on the key exchange method
     561             :       // chosen by the server.
     562             : 
     563             :       // These configurations are in order of most restrictive to least
     564             :       // restrictive. This enables us to gather telemetry on the expected
     565             :       // results of setting the default policy to a particular configuration.
     566             :       SHA1Mode sha1ModeConfigurations[] = {
     567             :         SHA1Mode::Forbidden,
     568             :         SHA1Mode::ImportedRoot,
     569             :         SHA1Mode::ImportedRootOrBefore2016,
     570             :         SHA1Mode::Allowed,
     571           0 :       };
     572             : 
     573             :       SHA1ModeResult sha1ModeResults[] = {
     574             :         SHA1ModeResult::SucceededWithoutSHA1,
     575             :         SHA1ModeResult::SucceededWithImportedRoot,
     576             :         SHA1ModeResult::SucceededWithImportedRootOrSHA1Before2016,
     577             :         SHA1ModeResult::SucceededWithSHA1,
     578           0 :       };
     579             : 
     580           0 :       size_t sha1ModeConfigurationsCount = MOZ_ARRAY_LENGTH(sha1ModeConfigurations);
     581             : 
     582             :       static_assert(MOZ_ARRAY_LENGTH(sha1ModeConfigurations) ==
     583             :                     MOZ_ARRAY_LENGTH(sha1ModeResults),
     584             :                     "digestAlgorithm array lengths differ");
     585             : 
     586           0 :       rv = Result::ERROR_UNKNOWN_ERROR;
     587             : 
     588             :       // Try to validate for EV first.
     589             :       NSSCertDBTrustDomain::OCSPFetching evOCSPFetching
     590           0 :         = (mOCSPDownloadConfig == ocspOff) ||
     591           0 :           (flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
     592           0 :                                     : NSSCertDBTrustDomain::FetchOCSPForEV;
     593             : 
     594             :       CertPolicyId evPolicy;
     595             :       SECOidTag evPolicyOidTag;
     596           0 :       bool foundEVPolicy = GetFirstEVPolicy(*cert, evPolicy, evPolicyOidTag);
     597           0 :       for (size_t i = 0;
     598           0 :            i < sha1ModeConfigurationsCount && rv != Success && foundEVPolicy;
     599             :            i++) {
     600             :         // Don't attempt verification if the SHA1 mode set by preferences
     601             :         // (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
     602             :         // (To put it another way, only attempt verification if the SHA1 mode
     603             :         // option we're on is as restrictive or more restrictive than
     604             :         // mSHA1Mode.) This allows us to gather telemetry information while
     605             :         // still enforcing the mode set by preferences.
     606           0 :         if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[i])) {
     607           0 :           continue;
     608             :         }
     609             : 
     610             :         // Because of the try-strict and fallback approach, we have to clear any
     611             :         // previously noted telemetry information
     612           0 :         if (pinningTelemetryInfo) {
     613           0 :           pinningTelemetryInfo->Reset();
     614             :         }
     615             : 
     616             :         NSSCertDBTrustDomain
     617             :           trustDomain(trustSSL, evOCSPFetching,
     618             :                       mOCSPCache, pinArg, ocspGETConfig,
     619             :                       mOCSPTimeoutSoft, mOCSPTimeoutHard,
     620           0 :                       mCertShortLifetimeInDays, mPinningMode, MIN_RSA_BITS,
     621             :                       ValidityCheckingMode::CheckForEV,
     622           0 :                       sha1ModeConfigurations[i], mNetscapeStepUpPolicy,
     623             :                       originAttributes, builtChain, peerCertChain,
     624           0 :                       pinningTelemetryInfo, hostname);
     625             :         rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
     626             :                                           KeyUsage::digitalSignature,// (EC)DHE
     627             :                                           KeyUsage::keyEncipherment, // RSA
     628             :                                           KeyUsage::keyAgreement,    // (EC)DH
     629             :                                           KeyPurposeId::id_kp_serverAuth,
     630             :                                           evPolicy, stapledOCSPResponse,
     631           0 :                                           ocspStaplingStatus);
     632           0 :         if (rv == Success &&
     633           0 :             sha1ModeConfigurations[i] == SHA1Mode::ImportedRoot) {
     634           0 :           bool isBuiltInRoot = false;
     635           0 :           rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
     636           0 :           if (rv != Success) {
     637           0 :             break;
     638             :           }
     639           0 :           if (isBuiltInRoot) {
     640           0 :             rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
     641             :           }
     642             :         }
     643           0 :         if (rv == Success) {
     644           0 :           MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
     645             :                   ("cert is EV with status %i\n", static_cast<int>(sha1ModeResults[i])));
     646           0 :           if (evOidPolicy) {
     647           0 :             *evOidPolicy = evPolicyOidTag;
     648             :           }
     649           0 :           if (sha1ModeResult) {
     650           0 :             *sha1ModeResult = sha1ModeResults[i];
     651             :           }
     652             :           rv = VerifyCertificateTransparencyPolicy(trustDomain, builtChain,
     653             :                                                    sctsFromTLSInput, time,
     654           0 :                                                    ctInfo);
     655           0 :           if (rv != Success) {
     656           0 :             break;
     657             :           }
     658             :         }
     659             :       }
     660           0 :       if (rv == Success) {
     661           0 :         break;
     662             :       }
     663             : 
     664           0 :       if (flags & FLAG_MUST_BE_EV) {
     665           0 :         rv = Result::ERROR_POLICY_VALIDATION_FAILED;
     666           0 :         break;
     667             :       }
     668             : 
     669             :       // Now try non-EV.
     670             :       unsigned int keySizeOptions[] = {
     671             :         MIN_RSA_BITS,
     672             :         MIN_RSA_BITS_WEAK
     673           0 :       };
     674             : 
     675             :       KeySizeStatus keySizeStatuses[] = {
     676             :         KeySizeStatus::LargeMinimumSucceeded,
     677             :         KeySizeStatus::CompatibilityRisk
     678           0 :       };
     679             : 
     680             :       static_assert(MOZ_ARRAY_LENGTH(keySizeOptions) ==
     681             :                     MOZ_ARRAY_LENGTH(keySizeStatuses),
     682             :                     "keySize array lengths differ");
     683             : 
     684           0 :       size_t keySizeOptionsCount = MOZ_ARRAY_LENGTH(keySizeStatuses);
     685             : 
     686           0 :       for (size_t i = 0; i < keySizeOptionsCount && rv != Success; i++) {
     687           0 :         for (size_t j = 0; j < sha1ModeConfigurationsCount && rv != Success;
     688             :              j++) {
     689             :           // Don't attempt verification if the SHA1 mode set by preferences
     690             :           // (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
     691             :           // (To put it another way, only attempt verification if the SHA1 mode
     692             :           // option we're on is as restrictive or more restrictive than
     693             :           // mSHA1Mode.) This allows us to gather telemetry information while
     694             :           // still enforcing the mode set by preferences.
     695           0 :           if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[j])) {
     696           0 :             continue;
     697             :           }
     698             : 
     699             :           // invalidate any telemetry info relating to failed chains
     700           0 :           if (pinningTelemetryInfo) {
     701           0 :             pinningTelemetryInfo->Reset();
     702             :           }
     703             : 
     704             :           NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
     705             :                                            mOCSPCache, pinArg, ocspGETConfig,
     706             :                                            mOCSPTimeoutSoft, mOCSPTimeoutHard,
     707           0 :                                            mCertShortLifetimeInDays,
     708           0 :                                            mPinningMode, keySizeOptions[i],
     709             :                                            ValidityCheckingMode::CheckingOff,
     710             :                                            sha1ModeConfigurations[j],
     711           0 :                                            mNetscapeStepUpPolicy,
     712             :                                            originAttributes, builtChain,
     713             :                                            peerCertChain, pinningTelemetryInfo,
     714           0 :                                            hostname);
     715             :           rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
     716             :                                             KeyUsage::digitalSignature,//(EC)DHE
     717             :                                             KeyUsage::keyEncipherment,//RSA
     718             :                                             KeyUsage::keyAgreement,//(EC)DH
     719             :                                             KeyPurposeId::id_kp_serverAuth,
     720             :                                             CertPolicyId::anyPolicy,
     721             :                                             stapledOCSPResponse,
     722           0 :                                             ocspStaplingStatus);
     723           0 :           if (rv == Success &&
     724           0 :               sha1ModeConfigurations[j] == SHA1Mode::ImportedRoot) {
     725           0 :             bool isBuiltInRoot = false;
     726           0 :             rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
     727           0 :             if (rv != Success) {
     728           0 :               break;
     729             :             }
     730           0 :             if (isBuiltInRoot) {
     731           0 :               rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
     732             :             }
     733             :           }
     734           0 :           if (rv == Success) {
     735           0 :             if (keySizeStatus) {
     736           0 :               *keySizeStatus = keySizeStatuses[i];
     737             :             }
     738           0 :             if (sha1ModeResult) {
     739           0 :               *sha1ModeResult = sha1ModeResults[j];
     740             :             }
     741             :             rv = VerifyCertificateTransparencyPolicy(trustDomain, builtChain,
     742             :                                                      sctsFromTLSInput, time,
     743           0 :                                                      ctInfo);
     744           0 :             if (rv != Success) {
     745           0 :               break;
     746             :             }
     747             :           }
     748             :         }
     749             :       }
     750             : 
     751           0 :       if (rv == Success) {
     752           0 :         break;
     753             :       }
     754             : 
     755           0 :       if (keySizeStatus) {
     756           0 :         *keySizeStatus = KeySizeStatus::AlreadyBad;
     757             :       }
     758             :       // The telemetry probe CERT_CHAIN_SHA1_POLICY_STATUS gives us feedback on
     759             :       // the result of setting a specific policy. However, we don't want noise
     760             :       // from users who have manually set the policy to something other than the
     761             :       // default, so we only collect for ImportedRoot (which is the default).
     762           0 :       if (sha1ModeResult && mSHA1Mode == SHA1Mode::ImportedRoot) {
     763           0 :         *sha1ModeResult = SHA1ModeResult::Failed;
     764             :       }
     765             : 
     766           0 :       break;
     767             :     }
     768             : 
     769             :     case certificateUsageSSLCA: {
     770             :       NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
     771             :                                        mOCSPCache, pinArg, ocspGETConfig,
     772             :                                        mOCSPTimeoutSoft, mOCSPTimeoutHard,
     773           0 :                                        mCertShortLifetimeInDays,
     774             :                                        pinningDisabled, MIN_RSA_BITS_WEAK,
     775             :                                        ValidityCheckingMode::CheckingOff,
     776           0 :                                        SHA1Mode::Allowed, mNetscapeStepUpPolicy,
     777             :                                        originAttributes, builtChain,
     778           0 :                                        peerCertChain, nullptr, nullptr);
     779             :       rv = BuildCertChain(trustDomain, certDER, time,
     780             :                           EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
     781             :                           KeyPurposeId::id_kp_serverAuth,
     782           0 :                           CertPolicyId::anyPolicy, stapledOCSPResponse);
     783           0 :       break;
     784             :     }
     785             : 
     786             :     case certificateUsageEmailSigner: {
     787             :       NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
     788             :                                        mOCSPCache, pinArg, ocspGETConfig,
     789             :                                        mOCSPTimeoutSoft, mOCSPTimeoutHard,
     790           0 :                                        mCertShortLifetimeInDays,
     791             :                                        pinningDisabled, MIN_RSA_BITS_WEAK,
     792             :                                        ValidityCheckingMode::CheckingOff,
     793             :                                        SHA1Mode::Allowed,
     794             :                                        NetscapeStepUpPolicy::NeverMatch,
     795             :                                        originAttributes, builtChain,
     796           0 :                                        peerCertChain, nullptr, nullptr);
     797             :       rv = BuildCertChain(trustDomain, certDER, time,
     798             :                           EndEntityOrCA::MustBeEndEntity,
     799             :                           KeyUsage::digitalSignature,
     800             :                           KeyPurposeId::id_kp_emailProtection,
     801           0 :                           CertPolicyId::anyPolicy, stapledOCSPResponse);
     802           0 :       if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
     803             :         rv = BuildCertChain(trustDomain, certDER, time,
     804             :                             EndEntityOrCA::MustBeEndEntity,
     805             :                             KeyUsage::nonRepudiation,
     806             :                             KeyPurposeId::id_kp_emailProtection,
     807           0 :                             CertPolicyId::anyPolicy, stapledOCSPResponse);
     808             :       }
     809           0 :       break;
     810             :     }
     811             : 
     812             :     case certificateUsageEmailRecipient: {
     813             :       // TODO: The higher level S/MIME processing should pass in which key
     814             :       // usage it is trying to verify for, and base its algorithm choices
     815             :       // based on the result of the verification(s).
     816             :       NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
     817             :                                        mOCSPCache, pinArg, ocspGETConfig,
     818             :                                        mOCSPTimeoutSoft, mOCSPTimeoutHard,
     819           0 :                                        mCertShortLifetimeInDays,
     820             :                                        pinningDisabled, MIN_RSA_BITS_WEAK,
     821             :                                        ValidityCheckingMode::CheckingOff,
     822             :                                        SHA1Mode::Allowed,
     823             :                                        NetscapeStepUpPolicy::NeverMatch,
     824             :                                        originAttributes, builtChain,
     825           0 :                                        peerCertChain, nullptr, nullptr);
     826             :       rv = BuildCertChain(trustDomain, certDER, time,
     827             :                           EndEntityOrCA::MustBeEndEntity,
     828             :                           KeyUsage::keyEncipherment, // RSA
     829             :                           KeyPurposeId::id_kp_emailProtection,
     830           0 :                           CertPolicyId::anyPolicy, stapledOCSPResponse);
     831           0 :       if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
     832             :         rv = BuildCertChain(trustDomain, certDER, time,
     833             :                             EndEntityOrCA::MustBeEndEntity,
     834             :                             KeyUsage::keyAgreement, // ECDH/DH
     835             :                             KeyPurposeId::id_kp_emailProtection,
     836           0 :                             CertPolicyId::anyPolicy, stapledOCSPResponse);
     837             :       }
     838           0 :       break;
     839             :     }
     840             : 
     841             :     case certificateUsageObjectSigner: {
     842             :       NSSCertDBTrustDomain trustDomain(trustObjectSigning, defaultOCSPFetching,
     843             :                                        mOCSPCache, pinArg, ocspGETConfig,
     844             :                                        mOCSPTimeoutSoft, mOCSPTimeoutHard,
     845           0 :                                        mCertShortLifetimeInDays,
     846             :                                        pinningDisabled, MIN_RSA_BITS_WEAK,
     847             :                                        ValidityCheckingMode::CheckingOff,
     848             :                                        SHA1Mode::Allowed,
     849             :                                        NetscapeStepUpPolicy::NeverMatch,
     850             :                                        originAttributes, builtChain,
     851           0 :                                        peerCertChain, nullptr, nullptr);
     852             :       rv = BuildCertChain(trustDomain, certDER, time,
     853             :                           EndEntityOrCA::MustBeEndEntity,
     854             :                           KeyUsage::digitalSignature,
     855             :                           KeyPurposeId::id_kp_codeSigning,
     856           0 :                           CertPolicyId::anyPolicy, stapledOCSPResponse);
     857           0 :       break;
     858             :     }
     859             : 
     860             :     case certificateUsageVerifyCA:
     861             :     case certificateUsageStatusResponder: {
     862             :       // XXX This is a pretty useless way to verify a certificate. It is used
     863             :       // by the certificate viewer UI. Because we don't know what trust bit is
     864             :       // interesting, we just try them all.
     865             :       mozilla::pkix::EndEntityOrCA endEntityOrCA;
     866             :       mozilla::pkix::KeyUsage keyUsage;
     867             :       KeyPurposeId eku;
     868           0 :       if (usage == certificateUsageVerifyCA) {
     869           0 :         endEntityOrCA = EndEntityOrCA::MustBeCA;
     870           0 :         keyUsage = KeyUsage::keyCertSign;
     871           0 :         eku = KeyPurposeId::anyExtendedKeyUsage;
     872             :       } else {
     873           0 :         endEntityOrCA = EndEntityOrCA::MustBeEndEntity;
     874           0 :         keyUsage = KeyUsage::digitalSignature;
     875           0 :         eku = KeyPurposeId::id_kp_OCSPSigning;
     876             :       }
     877             : 
     878             :       NSSCertDBTrustDomain sslTrust(trustSSL, defaultOCSPFetching, mOCSPCache,
     879             :                                     pinArg, ocspGETConfig, mOCSPTimeoutSoft,
     880           0 :                                     mOCSPTimeoutHard, mCertShortLifetimeInDays,
     881             :                                     pinningDisabled, MIN_RSA_BITS_WEAK,
     882             :                                     ValidityCheckingMode::CheckingOff,
     883             :                                     SHA1Mode::Allowed,
     884             :                                     NetscapeStepUpPolicy::NeverMatch,
     885             :                                     originAttributes, builtChain, peerCertChain,
     886           0 :                                     nullptr, nullptr);
     887             :       rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
     888             :                           keyUsage, eku, CertPolicyId::anyPolicy,
     889           0 :                           stapledOCSPResponse);
     890           0 :       if (rv == Result::ERROR_UNKNOWN_ISSUER) {
     891             :         NSSCertDBTrustDomain emailTrust(trustEmail, defaultOCSPFetching,
     892             :                                         mOCSPCache, pinArg, ocspGETConfig,
     893             :                                         mOCSPTimeoutSoft, mOCSPTimeoutHard,
     894           0 :                                         mCertShortLifetimeInDays,
     895             :                                         pinningDisabled, MIN_RSA_BITS_WEAK,
     896             :                                         ValidityCheckingMode::CheckingOff,
     897             :                                         SHA1Mode::Allowed,
     898             :                                         NetscapeStepUpPolicy::NeverMatch,
     899             :                                         originAttributes, builtChain,
     900           0 :                                         peerCertChain, nullptr, nullptr);
     901             :         rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA,
     902             :                             keyUsage, eku, CertPolicyId::anyPolicy,
     903           0 :                             stapledOCSPResponse);
     904           0 :         if (rv == Result::ERROR_UNKNOWN_ISSUER) {
     905             :           NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
     906             :                                                   defaultOCSPFetching,
     907             :                                                   mOCSPCache, pinArg,
     908             :                                                   ocspGETConfig,
     909             :                                                   mOCSPTimeoutSoft,
     910             :                                                   mOCSPTimeoutHard,
     911           0 :                                                   mCertShortLifetimeInDays,
     912             :                                                   pinningDisabled,
     913             :                                                   MIN_RSA_BITS_WEAK,
     914             :                                                   ValidityCheckingMode::CheckingOff,
     915             :                                                   SHA1Mode::Allowed,
     916             :                                                   NetscapeStepUpPolicy::NeverMatch,
     917             :                                                   originAttributes, builtChain,
     918             :                                                   peerCertChain, nullptr,
     919           0 :                                                   nullptr);
     920             :           rv = BuildCertChain(objectSigningTrust, certDER, time,
     921             :                               endEntityOrCA, keyUsage, eku,
     922           0 :                               CertPolicyId::anyPolicy, stapledOCSPResponse);
     923             :         }
     924             :       }
     925             : 
     926           0 :       break;
     927             :     }
     928             : 
     929             :     default:
     930           0 :       rv = Result::FATAL_ERROR_INVALID_ARGS;
     931             :   }
     932             : 
     933           0 :   if (rv != Success) {
     934           0 :     return rv;
     935             :   }
     936             : 
     937           0 :   return Success;
     938             : }
     939             : 
     940             : Result
     941           0 : CertVerifier::VerifySSLServerCert(const UniqueCERTCertificate& peerCert,
     942             :                      /*optional*/ const SECItem* stapledOCSPResponse,
     943             :                      /*optional*/ const SECItem* sctsFromTLS,
     944             :                                   Time time,
     945             :                      /*optional*/ void* pinarg,
     946             :                                   const nsACString& hostname,
     947             :                           /*out*/ UniqueCERTCertList& builtChain,
     948             :                      /*optional*/ UniqueCERTCertList* peerCertChain,
     949             :                      /*optional*/ bool saveIntermediatesInPermanentDatabase,
     950             :                      /*optional*/ Flags flags,
     951             :                      /*optional*/ const OriginAttributes& originAttributes,
     952             :                  /*optional out*/ SECOidTag* evOidPolicy,
     953             :                  /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
     954             :                  /*optional out*/ KeySizeStatus* keySizeStatus,
     955             :                  /*optional out*/ SHA1ModeResult* sha1ModeResult,
     956             :                  /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
     957             :                  /*optional out*/ CertificateTransparencyInfo* ctInfo)
     958             : {
     959           0 :   MOZ_ASSERT(peerCert);
     960             :   // XXX: MOZ_ASSERT(pinarg);
     961           0 :   MOZ_ASSERT(!hostname.IsEmpty());
     962             : 
     963           0 :   if (evOidPolicy) {
     964           0 :     *evOidPolicy = SEC_OID_UNKNOWN;
     965             :   }
     966             : 
     967           0 :   if (hostname.IsEmpty()) {
     968           0 :     return Result::ERROR_BAD_CERT_DOMAIN;
     969             :   }
     970             : 
     971             :   // CreateCertErrorRunnable assumes that CheckCertHostname is only called
     972             :   // if VerifyCert succeeded.
     973           0 :   Result rv = VerifyCert(peerCert.get(), certificateUsageSSLServer, time,
     974           0 :                          pinarg, PromiseFlatCString(hostname).get(), builtChain,
     975             :                          peerCertChain, flags,
     976             :                          stapledOCSPResponse, sctsFromTLS, originAttributes,
     977             :                          evOidPolicy, ocspStaplingStatus, keySizeStatus,
     978           0 :                          sha1ModeResult, pinningTelemetryInfo, ctInfo);
     979           0 :   if (rv != Success) {
     980           0 :     return rv;
     981             :   }
     982             : 
     983           0 :   Input peerCertInput;
     984           0 :   rv = peerCertInput.Init(peerCert->derCert.data, peerCert->derCert.len);
     985           0 :   if (rv != Success) {
     986           0 :     return rv;
     987             :   }
     988             : 
     989           0 :   Input stapledOCSPResponseInput;
     990           0 :   Input* responseInputPtr = nullptr;
     991           0 :   if (stapledOCSPResponse) {
     992           0 :     rv = stapledOCSPResponseInput.Init(stapledOCSPResponse->data,
     993           0 :                                        stapledOCSPResponse->len);
     994           0 :     if (rv != Success) {
     995             :       // The stapled OCSP response was too big.
     996           0 :       return Result::ERROR_OCSP_MALFORMED_RESPONSE;
     997             :     }
     998           0 :     responseInputPtr = &stapledOCSPResponseInput;
     999             :   }
    1000             : 
    1001           0 :   if (!(flags & FLAG_TLS_IGNORE_STATUS_REQUEST)) {
    1002           0 :     rv = CheckTLSFeaturesAreSatisfied(peerCertInput, responseInputPtr);
    1003           0 :     if (rv != Success) {
    1004           0 :       return rv;
    1005             :     }
    1006             :   }
    1007             : 
    1008           0 :   Input hostnameInput;
    1009           0 :   rv = hostnameInput.Init(
    1010             :     BitwiseCast<const uint8_t*, const char*>(hostname.BeginReading()),
    1011           0 :     hostname.Length());
    1012           0 :   if (rv != Success) {
    1013           0 :     return Result::FATAL_ERROR_INVALID_ARGS;
    1014             :   }
    1015             :   bool isBuiltInRoot;
    1016           0 :   rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
    1017           0 :   if (rv != Success) {
    1018           0 :     return rv;
    1019             :   }
    1020             :   BRNameMatchingPolicy nameMatchingPolicy(
    1021             :     isBuiltInRoot ? mNameMatchingMode
    1022           0 :                   : BRNameMatchingPolicy::Mode::DoNotEnforce);
    1023           0 :   rv = CheckCertHostname(peerCertInput, hostnameInput, nameMatchingPolicy);
    1024           0 :   if (rv != Success) {
    1025             :     // Treat malformed name information as a domain mismatch.
    1026           0 :     if (rv == Result::ERROR_BAD_DER) {
    1027           0 :       return Result::ERROR_BAD_CERT_DOMAIN;
    1028             :     }
    1029             : 
    1030           0 :     return rv;
    1031             :   }
    1032             : 
    1033           0 :   if (saveIntermediatesInPermanentDatabase) {
    1034           0 :     SaveIntermediateCerts(builtChain);
    1035             :   }
    1036             : 
    1037           0 :   return Success;
    1038             : }
    1039             : 
    1040             : } } // namespace mozilla::psm

Generated by: LCOV version 1.13