Blame security/certverifier/CertVerifier.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "CertVerifier.h"
Packit f0b94e
Packit f0b94e
#include <stdint.h>
Packit f0b94e
Packit f0b94e
#include "CTDiversityPolicy.h"
Packit f0b94e
#include "CTKnownLogs.h"
Packit f0b94e
#include "CTLogVerifier.h"
Packit f0b94e
#include "ExtendedValidation.h"
Packit f0b94e
#include "MultiLogCTVerifier.h"
Packit f0b94e
#include "NSSCertDBTrustDomain.h"
Packit f0b94e
#include "NSSErrorsService.h"
Packit f0b94e
#include "cert.h"
Packit f0b94e
#include "mozilla/Assertions.h"
Packit f0b94e
#include "mozilla/Casting.h"
Packit f0b94e
#include "mozilla/IntegerPrintfMacros.h"
Packit f0b94e
#include "nsNSSComponent.h"
Packit f0b94e
#include "nsPromiseFlatString.h"
Packit f0b94e
#include "nsServiceManagerUtils.h"
Packit f0b94e
#include "pk11pub.h"
Packit f0b94e
#include "pkix/pkix.h"
Packit f0b94e
#include "pkix/pkixnss.h"
Packit f0b94e
#include "secmod.h"
Packit f0b94e
Packit f0b94e
using namespace mozilla::ct;
Packit f0b94e
using namespace mozilla::pkix;
Packit f0b94e
using namespace mozilla::psm;
Packit f0b94e
Packit f0b94e
mozilla::LazyLogModule gCertVerifierLog("certverifier");
Packit f0b94e
Packit f0b94e
// Returns the certificate validity period in calendar months (rounded down).
Packit f0b94e
// "extern" to allow unit tests in CTPolicyEnforcerTest.cpp.
Packit f0b94e
extern mozilla::pkix::Result GetCertLifetimeInFullMonths(PRTime certNotBefore,
Packit f0b94e
                                                         PRTime certNotAfter,
Packit f0b94e
                                                         size_t& months) {
Packit f0b94e
  if (certNotBefore >= certNotAfter) {
Packit f0b94e
    MOZ_ASSERT_UNREACHABLE("Expected notBefore < notAfter");
Packit f0b94e
    return mozilla::pkix::Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  PRExplodedTime explodedNotBefore;
Packit f0b94e
  PRExplodedTime explodedNotAfter;
Packit f0b94e
Packit f0b94e
  PR_ExplodeTime(certNotBefore, PR_LocalTimeParameters, &explodedNotBefore);
Packit f0b94e
  PR_ExplodeTime(certNotAfter, PR_LocalTimeParameters, &explodedNotAfter);
Packit f0b94e
Packit f0b94e
  PRInt32 signedMonths =
Packit f0b94e
      (explodedNotAfter.tm_year - explodedNotBefore.tm_year) * 12 +
Packit f0b94e
      (explodedNotAfter.tm_month - explodedNotBefore.tm_month);
Packit f0b94e
  if (explodedNotAfter.tm_mday < explodedNotBefore.tm_mday) {
Packit f0b94e
    --signedMonths;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Can't use `mozilla::AssertedCast<size_t>(signedMonths)` below
Packit f0b94e
  // since it currently generates a warning on Win x64 debug.
Packit f0b94e
  if (signedMonths < 0) {
Packit f0b94e
    MOZ_ASSERT_UNREACHABLE("Expected explodedNotBefore < explodedNotAfter");
Packit f0b94e
    return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  months = static_cast<size_t>(signedMonths);
Packit f0b94e
Packit f0b94e
  return Success;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
namespace psm {
Packit f0b94e
Packit f0b94e
const CertVerifier::Flags CertVerifier::FLAG_LOCAL_ONLY = 1;
Packit f0b94e
const CertVerifier::Flags CertVerifier::FLAG_MUST_BE_EV = 2;
Packit f0b94e
const CertVerifier::Flags CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST = 4;
Packit f0b94e
Packit f0b94e
void CertificateTransparencyInfo::Reset() {
Packit f0b94e
  enabled = false;
Packit f0b94e
  verifyResult.Reset();
Packit f0b94e
  policyCompliance = CTPolicyCompliance::Unknown;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
CertVerifier::CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
Packit f0b94e
                           OcspGetConfig ogc,
Packit f0b94e
                           mozilla::TimeDuration ocspTimeoutSoft,
Packit f0b94e
                           mozilla::TimeDuration ocspTimeoutHard,
Packit f0b94e
                           uint32_t certShortLifetimeInDays,
Packit f0b94e
                           PinningMode pinningMode, SHA1Mode sha1Mode,
Packit f0b94e
                           BRNameMatchingPolicy::Mode nameMatchingMode,
Packit f0b94e
                           NetscapeStepUpPolicy netscapeStepUpPolicy,
Packit f0b94e
                           CertificateTransparencyMode ctMode,
Packit f0b94e
                           DistrustedCAPolicy distrustedCAPolicy)
Packit f0b94e
    : mOCSPDownloadConfig(odc),
Packit f0b94e
      mOCSPStrict(osc == ocspStrict),
Packit f0b94e
      mOCSPGETEnabled(ogc == ocspGetEnabled),
Packit f0b94e
      mOCSPTimeoutSoft(ocspTimeoutSoft),
Packit f0b94e
      mOCSPTimeoutHard(ocspTimeoutHard),
Packit f0b94e
      mCertShortLifetimeInDays(certShortLifetimeInDays),
Packit f0b94e
      mPinningMode(pinningMode),
Packit f0b94e
      mSHA1Mode(sha1Mode),
Packit f0b94e
      mNameMatchingMode(nameMatchingMode),
Packit f0b94e
      mNetscapeStepUpPolicy(netscapeStepUpPolicy),
Packit f0b94e
      mCTMode(ctMode),
Packit f0b94e
      mDistrustedCAPolicy(distrustedCAPolicy) {
Packit f0b94e
  LoadKnownCTLogs();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
CertVerifier::~CertVerifier() {}
Packit f0b94e
Packit f0b94e
Result IsCertChainRootBuiltInRoot(const UniqueCERTCertList& chain,
Packit f0b94e
                                  bool& result) {
Packit f0b94e
  if (!chain || CERT_LIST_EMPTY(chain)) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  CERTCertListNode* rootNode = CERT_LIST_TAIL(chain);
Packit f0b94e
  if (!rootNode) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  CERTCertificate* root = rootNode->cert;
Packit f0b94e
  if (!root) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  return IsCertBuiltInRoot(root, result);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
// The term "builtin root" traditionally refers to a root CA certificate that
Packit f0b94e
// has been added to the NSS trust store, because it has been approved
Packit f0b94e
// for inclusion according to the Mozilla CA policy, and might be accepted
Packit f0b94e
// by Mozilla applications as an issuer for certificates seen on the public web.
Packit f0b94e
Result IsCertBuiltInRoot(CERTCertificate* cert, bool& result) {
Packit f0b94e
  if (NS_FAILED(BlockUntilLoadableRootsLoaded())) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  result = false;
Packit f0b94e
#ifdef DEBUG
Packit f0b94e
  nsCOMPtr<nsINSSComponent> component(do_GetService(PSM_COMPONENT_CONTRACTID));
Packit f0b94e
  if (!component) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  nsresult rv = component->IsCertTestBuiltInRoot(cert, result);
Packit f0b94e
  if (NS_FAILED(rv)) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  if (result) {
Packit f0b94e
    return Success;
Packit f0b94e
  }
Packit f0b94e
#endif  // DEBUG
Packit f0b94e
  AutoSECMODListReadLock lock;
Packit f0b94e
  for (SECMODModuleList* list = SECMOD_GetDefaultModuleList(); list;
Packit f0b94e
       list = list->next) {
Packit f0b94e
    for (int i = 0; i < list->module->slotCount; i++) {
Packit f0b94e
      PK11SlotInfo* slot = list->module->slots[i];
Packit f0b94e
      // We're searching for the "builtin root module", which is a module that
Packit f0b94e
      // contains an object with a CKA_CLASS of CKO_NETSCAPE_BUILTIN_ROOT_LIST.
Packit f0b94e
      // We use PK11_HasRootCerts() to identify a module with that property.
Packit f0b94e
      // In the past, we exclusively used the PKCS#11 module named nssckbi,
Packit f0b94e
      // which is provided by the NSS library.
Packit f0b94e
      // Nowadays, some distributions use a replacement module, which contains
Packit f0b94e
      // the builtin roots, but which also contains additional CA certificates,
Packit f0b94e
      // such as CAs trusted in a local deployment.
Packit f0b94e
      // We want to be able to distinguish between these two categories,
Packit f0b94e
      // because a CA, which may issue certificates for the public web,
Packit f0b94e
      // is expected to comply with additional requirements.
Packit f0b94e
      // If the certificate has attribute CKA_NSS_MOZILLA_CA_POLICY set to true,
Packit f0b94e
      // then we treat it as a "builtin root".
Packit f0b94e
      if (PK11_IsPresent(slot) && PK11_HasRootCerts(slot)) {
Packit f0b94e
        CK_OBJECT_HANDLE handle = PK11_FindCertInSlot(slot, cert, nullptr);
Packit f0b94e
        if (handle != CK_INVALID_HANDLE &&
Packit f0b94e
            PK11_HasAttributeSet(slot, handle, CKA_NSS_MOZILLA_CA_POLICY,
Packit f0b94e
                                 false)) {
Packit f0b94e
          // Attribute was found, and is set to true
Packit f0b94e
          result = true;
Packit f0b94e
          break;
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return Success;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static Result BuildCertChainForOneKeyUsage(
Packit f0b94e
    NSSCertDBTrustDomain& trustDomain, Input certDER, Time time, KeyUsage ku1,
Packit f0b94e
    KeyUsage ku2, KeyUsage ku3, KeyPurposeId eku,
Packit f0b94e
    const CertPolicyId& requiredPolicy, const Input* stapledOCSPResponse,
Packit f0b94e
    /*optional out*/ CertVerifier::OCSPStaplingStatus* ocspStaplingStatus) {
Packit f0b94e
  trustDomain.ResetAccumulatedState();
Packit f0b94e
  Result rv =
Packit f0b94e
      BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
Packit f0b94e
                     ku1, eku, requiredPolicy, stapledOCSPResponse);
Packit f0b94e
  if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
Packit f0b94e
    trustDomain.ResetAccumulatedState();
Packit f0b94e
    rv = BuildCertChain(trustDomain, certDER, time,
Packit f0b94e
                        EndEntityOrCA::MustBeEndEntity, ku2, eku,
Packit f0b94e
                        requiredPolicy, stapledOCSPResponse);
Packit f0b94e
    if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
Packit f0b94e
      trustDomain.ResetAccumulatedState();
Packit f0b94e
      rv = BuildCertChain(trustDomain, certDER, time,
Packit f0b94e
                          EndEntityOrCA::MustBeEndEntity, ku3, eku,
Packit f0b94e
                          requiredPolicy, stapledOCSPResponse);
Packit f0b94e
      if (rv != Success) {
Packit f0b94e
        rv = Result::ERROR_INADEQUATE_KEY_USAGE;
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  if (ocspStaplingStatus) {
Packit f0b94e
    *ocspStaplingStatus = trustDomain.GetOCSPStaplingStatus();
Packit f0b94e
  }
Packit f0b94e
  return rv;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void CertVerifier::LoadKnownCTLogs() {
Packit f0b94e
  mCTVerifier = MakeUnique<MultiLogCTVerifier>();
Packit f0b94e
  for (const CTLogInfo& log : kCTLogList) {
Packit f0b94e
    Input publicKey;
Packit f0b94e
    Result rv = publicKey.Init(
Packit f0b94e
        BitwiseCast<const uint8_t*, const char*>(log.key), log.keyLength);
Packit f0b94e
    if (rv != Success) {
Packit f0b94e
      MOZ_ASSERT_UNREACHABLE("Failed reading a log key for a known CT Log");
Packit f0b94e
      continue;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    CTLogVerifier logVerifier;
Packit f0b94e
    const CTLogOperatorInfo& logOperator =
Packit f0b94e
        kCTLogOperatorList[log.operatorIndex];
Packit f0b94e
    rv = logVerifier.Init(publicKey, logOperator.id, log.status,
Packit f0b94e
                          log.disqualificationTime);
Packit f0b94e
    if (rv != Success) {
Packit f0b94e
      MOZ_ASSERT_UNREACHABLE("Failed initializing a known CT Log");
Packit f0b94e
      continue;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    rv = mCTVerifier->AddLog(Move(logVerifier));
Packit f0b94e
    if (rv != Success) {
Packit f0b94e
      MOZ_ASSERT_UNREACHABLE("Failed activating a known CT Log");
Packit f0b94e
      continue;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  // TBD: Initialize mCTDiversityPolicy with the CA dependency map
Packit f0b94e
  // of the known CT logs operators.
Packit f0b94e
  mCTDiversityPolicy = MakeUnique<CTDiversityPolicy>();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
Result CertVerifier::VerifyCertificateTransparencyPolicy(
Packit f0b94e
    NSSCertDBTrustDomain& trustDomain, const UniqueCERTCertList& builtChain,
Packit f0b94e
    Input sctsFromTLS, Time time,
Packit f0b94e
    /*optional out*/ CertificateTransparencyInfo* ctInfo) {
Packit f0b94e
  if (ctInfo) {
Packit f0b94e
    ctInfo->Reset();
Packit f0b94e
  }
Packit f0b94e
  if (mCTMode == CertificateTransparencyMode::Disabled) {
Packit f0b94e
    return Success;
Packit f0b94e
  }
Packit f0b94e
  if (ctInfo) {
Packit f0b94e
    ctInfo->enabled = true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!builtChain || CERT_LIST_EMPTY(builtChain)) {
Packit f0b94e
    return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input embeddedSCTs = trustDomain.GetSCTListFromCertificate();
Packit f0b94e
  if (embeddedSCTs.GetLength() > 0) {
Packit f0b94e
    MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
            ("Got embedded SCT data of length %zu\n",
Packit f0b94e
             static_cast<size_t>(embeddedSCTs.GetLength())));
Packit f0b94e
  }
Packit f0b94e
  Input sctsFromOCSP = trustDomain.GetSCTListFromOCSPStapling();
Packit f0b94e
  if (sctsFromOCSP.GetLength() > 0) {
Packit f0b94e
    MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
            ("Got OCSP SCT data of length %zu\n",
Packit f0b94e
             static_cast<size_t>(sctsFromOCSP.GetLength())));
Packit f0b94e
  }
Packit f0b94e
  if (sctsFromTLS.GetLength() > 0) {
Packit f0b94e
    MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
            ("Got TLS SCT data of length %zu\n",
Packit f0b94e
             static_cast<size_t>(sctsFromTLS.GetLength())));
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  CERTCertListNode* endEntityNode = CERT_LIST_HEAD(builtChain);
Packit f0b94e
  if (!endEntityNode || CERT_LIST_END(endEntityNode, builtChain)) {
Packit f0b94e
    return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
  CERTCertListNode* issuerNode = CERT_LIST_NEXT(endEntityNode);
Packit f0b94e
  if (!issuerNode || CERT_LIST_END(issuerNode, builtChain)) {
Packit f0b94e
    // Issuer certificate is required for SCT verification.
Packit f0b94e
    return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  CERTCertificate* endEntity = endEntityNode->cert;
Packit f0b94e
  CERTCertificate* issuer = issuerNode->cert;
Packit f0b94e
  if (!endEntity || !issuer) {
Packit f0b94e
    return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (endEntity->subjectName) {
Packit f0b94e
    MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
            ("Verifying CT Policy compliance of subject %s\n",
Packit f0b94e
             endEntity->subjectName));
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input endEntityDER;
Packit f0b94e
  Result rv =
Packit f0b94e
      endEntityDER.Init(endEntity->derCert.data, endEntity->derCert.len);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input issuerPublicKeyDER;
Packit f0b94e
  rv = issuerPublicKeyDER.Init(issuer->derPublicKey.data,
Packit f0b94e
                               issuer->derPublicKey.len);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  CTVerifyResult result;
Packit f0b94e
  rv = mCTVerifier->Verify(endEntityDER, issuerPublicKeyDER, embeddedSCTs,
Packit f0b94e
                           sctsFromOCSP, sctsFromTLS, time, result);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
            ("SCT verification failed with fatal error %" PRId32 "\n",
Packit f0b94e
             static_cast<uint32_t>(rv)));
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (MOZ_LOG_TEST(gCertVerifierLog, LogLevel::Debug)) {
Packit f0b94e
    size_t validCount = 0;
Packit f0b94e
    size_t unknownLogCount = 0;
Packit f0b94e
    size_t disqualifiedLogCount = 0;
Packit f0b94e
    size_t invalidSignatureCount = 0;
Packit f0b94e
    size_t invalidTimestampCount = 0;
Packit f0b94e
    for (const VerifiedSCT& verifiedSct : result.verifiedScts) {
Packit f0b94e
      switch (verifiedSct.status) {
Packit f0b94e
        case VerifiedSCT::Status::Valid:
Packit f0b94e
          validCount++;
Packit f0b94e
          break;
Packit f0b94e
        case VerifiedSCT::Status::ValidFromDisqualifiedLog:
Packit f0b94e
          disqualifiedLogCount++;
Packit f0b94e
          break;
Packit f0b94e
        case VerifiedSCT::Status::UnknownLog:
Packit f0b94e
          unknownLogCount++;
Packit f0b94e
          break;
Packit f0b94e
        case VerifiedSCT::Status::InvalidSignature:
Packit f0b94e
          invalidSignatureCount++;
Packit f0b94e
          break;
Packit f0b94e
        case VerifiedSCT::Status::InvalidTimestamp:
Packit f0b94e
          invalidTimestampCount++;
Packit f0b94e
          break;
Packit f0b94e
        case VerifiedSCT::Status::None:
Packit f0b94e
        default:
Packit f0b94e
          MOZ_ASSERT_UNREACHABLE("Unexpected SCT verification status");
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
    MOZ_LOG(
Packit f0b94e
        gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
        ("SCT verification result: "
Packit f0b94e
         "valid=%zu unknownLog=%zu disqualifiedLog=%zu "
Packit f0b94e
         "invalidSignature=%zu invalidTimestamp=%zu "
Packit f0b94e
         "decodingErrors=%zu\n",
Packit f0b94e
         validCount, unknownLogCount, disqualifiedLogCount,
Packit f0b94e
         invalidSignatureCount, invalidTimestampCount, result.decodingErrors));
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  PRTime notBefore;
Packit f0b94e
  PRTime notAfter;
Packit f0b94e
  if (CERT_GetCertTimes(endEntity, &notBefore, &notAfter) != SECSuccess) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  size_t lifetimeInMonths;
Packit f0b94e
  rv = GetCertLifetimeInFullMonths(notBefore, notAfter, lifetimeInMonths);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  CTLogOperatorList allOperators;
Packit f0b94e
  rv = GetCTLogOperatorsFromVerifiedSCTList(result.verifiedScts, allOperators);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  CTLogOperatorList dependentOperators;
Packit f0b94e
  rv = mCTDiversityPolicy->GetDependentOperators(builtChain, allOperators,
Packit f0b94e
                                                 dependentOperators);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  CTPolicyEnforcer ctPolicyEnforcer;
Packit f0b94e
  CTPolicyCompliance ctPolicyCompliance;
Packit f0b94e
  rv = ctPolicyEnforcer.CheckCompliance(result.verifiedScts, lifetimeInMonths,
Packit f0b94e
                                        dependentOperators, ctPolicyCompliance);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
            ("CT policy check failed with fatal error %" PRIu32 "\n",
Packit f0b94e
             static_cast<uint32_t>(rv)));
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (ctInfo) {
Packit f0b94e
    ctInfo->verifyResult = Move(result);
Packit f0b94e
    ctInfo->policyCompliance = ctPolicyCompliance;
Packit f0b94e
  }
Packit f0b94e
  return Success;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool CertVerifier::SHA1ModeMoreRestrictiveThanGivenMode(SHA1Mode mode) {
Packit f0b94e
  switch (mSHA1Mode) {
Packit f0b94e
    case SHA1Mode::Forbidden:
Packit f0b94e
      return mode != SHA1Mode::Forbidden;
Packit f0b94e
    case SHA1Mode::ImportedRoot:
Packit f0b94e
      return mode != SHA1Mode::Forbidden && mode != SHA1Mode::ImportedRoot;
Packit f0b94e
    case SHA1Mode::ImportedRootOrBefore2016:
Packit f0b94e
      return mode == SHA1Mode::Allowed;
Packit f0b94e
    case SHA1Mode::Allowed:
Packit f0b94e
      return false;
Packit f0b94e
    // MSVC warns unless we explicitly handle this now-unused option.
Packit f0b94e
    case SHA1Mode::UsedToBeBefore2016ButNowIsForbidden:
Packit f0b94e
    default:
Packit f0b94e
      MOZ_ASSERT(false, "unexpected SHA1Mode type");
Packit f0b94e
      return true;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
static const unsigned int MIN_RSA_BITS = 2048;
Packit f0b94e
static const unsigned int MIN_RSA_BITS_WEAK = 1024;
Packit f0b94e
Packit f0b94e
Result CertVerifier::VerifyCert(
Packit f0b94e
    CERTCertificate* cert, SECCertificateUsage usage, Time time, void* pinArg,
Packit f0b94e
    const char* hostname,
Packit f0b94e
    /*out*/ UniqueCERTCertList& builtChain,
Packit f0b94e
    /*optional*/ const Flags flags,
Packit f0b94e
    /*optional*/ const SECItem* stapledOCSPResponseSECItem,
Packit f0b94e
    /*optional*/ const SECItem* sctsFromTLSSECItem,
Packit f0b94e
    /*optional*/ const OriginAttributes& originAttributes,
Packit f0b94e
    /*optional out*/ SECOidTag* evOidPolicy,
Packit f0b94e
    /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
Packit f0b94e
    /*optional out*/ KeySizeStatus* keySizeStatus,
Packit f0b94e
    /*optional out*/ SHA1ModeResult* sha1ModeResult,
Packit f0b94e
    /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
Packit f0b94e
    /*optional out*/ CertificateTransparencyInfo* ctInfo) {
Packit f0b94e
  MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Top of VerifyCert\n"));
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(cert);
Packit f0b94e
  MOZ_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
Packit f0b94e
  MOZ_ASSERT(usage == certificateUsageSSLServer || !keySizeStatus);
Packit f0b94e
  MOZ_ASSERT(usage == certificateUsageSSLServer || !sha1ModeResult);
Packit f0b94e
Packit f0b94e
  if (NS_FAILED(BlockUntilLoadableRootsLoaded())) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
  if (NS_FAILED(CheckForSmartCardChanges())) {
Packit f0b94e
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (evOidPolicy) {
Packit f0b94e
    *evOidPolicy = SEC_OID_UNKNOWN;
Packit f0b94e
  }
Packit f0b94e
  if (ocspStaplingStatus) {
Packit f0b94e
    if (usage != certificateUsageSSLServer) {
Packit f0b94e
      return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
    }
Packit f0b94e
    *ocspStaplingStatus = OCSP_STAPLING_NEVER_CHECKED;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (keySizeStatus) {
Packit f0b94e
    if (usage != certificateUsageSSLServer) {
Packit f0b94e
      return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
    }
Packit f0b94e
    *keySizeStatus = KeySizeStatus::NeverChecked;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (sha1ModeResult) {
Packit f0b94e
    if (usage != certificateUsageSSLServer) {
Packit f0b94e
      return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
    }
Packit f0b94e
    *sha1ModeResult = SHA1ModeResult::NeverChecked;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!cert ||
Packit f0b94e
      (usage != certificateUsageSSLServer && (flags & FLAG_MUST_BE_EV))) {
Packit f0b94e
    return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input certDER;
Packit f0b94e
  Result rv = certDER.Init(cert->derCert.data, cert->derCert.len);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // We configure the OCSP fetching modes separately for EV and non-EV
Packit f0b94e
  // verifications.
Packit f0b94e
  NSSCertDBTrustDomain::OCSPFetching defaultOCSPFetching =
Packit f0b94e
      (mOCSPDownloadConfig == ocspOff) || (mOCSPDownloadConfig == ocspEVOnly) ||
Packit f0b94e
              (flags & FLAG_LOCAL_ONLY)
Packit f0b94e
          ? NSSCertDBTrustDomain::NeverFetchOCSP
Packit f0b94e
          : !mOCSPStrict ? NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
Packit f0b94e
                         : NSSCertDBTrustDomain::FetchOCSPForDVHardFail;
Packit f0b94e
Packit f0b94e
  OcspGetConfig ocspGETConfig =
Packit f0b94e
      mOCSPGETEnabled ? ocspGetEnabled : ocspGetDisabled;
Packit f0b94e
Packit f0b94e
  Input stapledOCSPResponseInput;
Packit f0b94e
  const Input* stapledOCSPResponse = nullptr;
Packit f0b94e
  if (stapledOCSPResponseSECItem) {
Packit f0b94e
    rv = stapledOCSPResponseInput.Init(stapledOCSPResponseSECItem->data,
Packit f0b94e
                                       stapledOCSPResponseSECItem->len);
Packit f0b94e
    if (rv != Success) {
Packit f0b94e
      // The stapled OCSP response was too big.
Packit f0b94e
      return Result::ERROR_OCSP_MALFORMED_RESPONSE;
Packit f0b94e
    }
Packit f0b94e
    stapledOCSPResponse = &stapledOCSPResponseInput;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input sctsFromTLSInput;
Packit f0b94e
  if (sctsFromTLSSECItem) {
Packit f0b94e
    rv = sctsFromTLSInput.Init(sctsFromTLSSECItem->data,
Packit f0b94e
                               sctsFromTLSSECItem->len);
Packit f0b94e
    // Silently discard the error of the extension being too big,
Packit f0b94e
    // do not fail the verification.
Packit f0b94e
    MOZ_ASSERT(rv == Success);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  switch (usage) {
Packit f0b94e
    case certificateUsageSSLClient: {
Packit f0b94e
      // XXX: We don't really have a trust bit for SSL client authentication so
Packit f0b94e
      // just use trustEmail as it is the closest alternative.
Packit f0b94e
      NSSCertDBTrustDomain trustDomain(
Packit f0b94e
          trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, ocspGETConfig,
Packit f0b94e
          mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
Packit f0b94e
          pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
Packit f0b94e
          SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch,
Packit f0b94e
          mDistrustedCAPolicy, originAttributes, builtChain, nullptr, nullptr);
Packit f0b94e
      rv = BuildCertChain(
Packit f0b94e
          trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
Packit f0b94e
          KeyUsage::digitalSignature, KeyPurposeId::id_kp_clientAuth,
Packit f0b94e
          CertPolicyId::anyPolicy, stapledOCSPResponse);
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    case certificateUsageSSLServer: {
Packit f0b94e
      // TODO: When verifying a certificate in an SSL handshake, we should
Packit f0b94e
      // restrict the acceptable key usage based on the key exchange method
Packit f0b94e
      // chosen by the server.
Packit f0b94e
Packit f0b94e
      // These configurations are in order of most restrictive to least
Packit f0b94e
      // restrictive. This enables us to gather telemetry on the expected
Packit f0b94e
      // results of setting the default policy to a particular configuration.
Packit f0b94e
      SHA1Mode sha1ModeConfigurations[] = {
Packit f0b94e
          SHA1Mode::Forbidden,
Packit f0b94e
          SHA1Mode::ImportedRoot,
Packit f0b94e
          SHA1Mode::ImportedRootOrBefore2016,
Packit f0b94e
          SHA1Mode::Allowed,
Packit f0b94e
      };
Packit f0b94e
Packit f0b94e
      SHA1ModeResult sha1ModeResults[] = {
Packit f0b94e
          SHA1ModeResult::SucceededWithoutSHA1,
Packit f0b94e
          SHA1ModeResult::SucceededWithImportedRoot,
Packit f0b94e
          SHA1ModeResult::SucceededWithImportedRootOrSHA1Before2016,
Packit f0b94e
          SHA1ModeResult::SucceededWithSHA1,
Packit f0b94e
      };
Packit f0b94e
Packit f0b94e
      size_t sha1ModeConfigurationsCount =
Packit f0b94e
          MOZ_ARRAY_LENGTH(sha1ModeConfigurations);
Packit f0b94e
Packit f0b94e
      static_assert(MOZ_ARRAY_LENGTH(sha1ModeConfigurations) ==
Packit f0b94e
                        MOZ_ARRAY_LENGTH(sha1ModeResults),
Packit f0b94e
                    "digestAlgorithm array lengths differ");
Packit f0b94e
Packit f0b94e
      rv = Result::ERROR_UNKNOWN_ERROR;
Packit f0b94e
Packit f0b94e
      // Try to validate for EV first.
Packit f0b94e
      NSSCertDBTrustDomain::OCSPFetching evOCSPFetching =
Packit f0b94e
          (mOCSPDownloadConfig == ocspOff) || (flags & FLAG_LOCAL_ONLY)
Packit f0b94e
              ? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
Packit f0b94e
              : NSSCertDBTrustDomain::FetchOCSPForEV;
Packit f0b94e
Packit f0b94e
      CertPolicyId evPolicy;
Packit f0b94e
      SECOidTag evPolicyOidTag;
Packit f0b94e
      bool foundEVPolicy = GetFirstEVPolicy(*cert, evPolicy, evPolicyOidTag);
Packit f0b94e
      for (size_t i = 0;
Packit f0b94e
           i < sha1ModeConfigurationsCount && rv != Success && foundEVPolicy;
Packit f0b94e
           i++) {
Packit f0b94e
        // Don't attempt verification if the SHA1 mode set by preferences
Packit f0b94e
        // (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
Packit f0b94e
        // (To put it another way, only attempt verification if the SHA1 mode
Packit f0b94e
        // option we're on is as restrictive or more restrictive than
Packit f0b94e
        // mSHA1Mode.) This allows us to gather telemetry information while
Packit f0b94e
        // still enforcing the mode set by preferences.
Packit f0b94e
        if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[i])) {
Packit f0b94e
          continue;
Packit f0b94e
        }
Packit f0b94e
Packit f0b94e
        // Because of the try-strict and fallback approach, we have to clear any
Packit f0b94e
        // previously noted telemetry information
Packit f0b94e
        if (pinningTelemetryInfo) {
Packit f0b94e
          pinningTelemetryInfo->Reset();
Packit f0b94e
        }
Packit f0b94e
Packit f0b94e
        NSSCertDBTrustDomain trustDomain(
Packit f0b94e
            trustSSL, evOCSPFetching, mOCSPCache, pinArg, ocspGETConfig,
Packit f0b94e
            mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
Packit f0b94e
            mPinningMode, MIN_RSA_BITS, ValidityCheckingMode::CheckForEV,
Packit f0b94e
            sha1ModeConfigurations[i], mNetscapeStepUpPolicy,
Packit f0b94e
            mDistrustedCAPolicy, originAttributes, builtChain,
Packit f0b94e
            pinningTelemetryInfo, hostname);
Packit f0b94e
        rv = BuildCertChainForOneKeyUsage(
Packit f0b94e
            trustDomain, certDER, time,
Packit f0b94e
            KeyUsage::digitalSignature,  // (EC)DHE
Packit f0b94e
            KeyUsage::keyEncipherment,   // RSA
Packit f0b94e
            KeyUsage::keyAgreement,      // (EC)DH
Packit f0b94e
            KeyPurposeId::id_kp_serverAuth, evPolicy, stapledOCSPResponse,
Packit f0b94e
            ocspStaplingStatus);
Packit f0b94e
        if (rv == Success &&
Packit f0b94e
            sha1ModeConfigurations[i] == SHA1Mode::ImportedRoot) {
Packit f0b94e
          bool isBuiltInRoot = false;
Packit f0b94e
          rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
Packit f0b94e
          if (rv != Success) {
Packit f0b94e
            break;
Packit f0b94e
          }
Packit f0b94e
          if (isBuiltInRoot) {
Packit f0b94e
            rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
Packit f0b94e
          }
Packit f0b94e
        }
Packit f0b94e
        if (rv == Success) {
Packit f0b94e
          MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
Packit f0b94e
                  ("cert is EV with status %i\n",
Packit f0b94e
                   static_cast<int>(sha1ModeResults[i])));
Packit f0b94e
          if (evOidPolicy) {
Packit f0b94e
            *evOidPolicy = evPolicyOidTag;
Packit f0b94e
          }
Packit f0b94e
          if (sha1ModeResult) {
Packit f0b94e
            *sha1ModeResult = sha1ModeResults[i];
Packit f0b94e
          }
Packit f0b94e
          rv = VerifyCertificateTransparencyPolicy(
Packit f0b94e
              trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
Packit f0b94e
          if (rv != Success) {
Packit f0b94e
            break;
Packit f0b94e
          }
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
      if (rv == Success) {
Packit f0b94e
        break;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      if (flags & FLAG_MUST_BE_EV) {
Packit f0b94e
        rv = Result::ERROR_POLICY_VALIDATION_FAILED;
Packit f0b94e
        break;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      // Now try non-EV.
Packit f0b94e
      unsigned int keySizeOptions[] = {MIN_RSA_BITS, MIN_RSA_BITS_WEAK};
Packit f0b94e
Packit f0b94e
      KeySizeStatus keySizeStatuses[] = {KeySizeStatus::LargeMinimumSucceeded,
Packit f0b94e
                                         KeySizeStatus::CompatibilityRisk};
Packit f0b94e
Packit f0b94e
      static_assert(
Packit f0b94e
          MOZ_ARRAY_LENGTH(keySizeOptions) == MOZ_ARRAY_LENGTH(keySizeStatuses),
Packit f0b94e
          "keySize array lengths differ");
Packit f0b94e
Packit f0b94e
      size_t keySizeOptionsCount = MOZ_ARRAY_LENGTH(keySizeStatuses);
Packit f0b94e
Packit f0b94e
      for (size_t i = 0; i < keySizeOptionsCount && rv != Success; i++) {
Packit f0b94e
        for (size_t j = 0; j < sha1ModeConfigurationsCount && rv != Success;
Packit f0b94e
             j++) {
Packit f0b94e
          // Don't attempt verification if the SHA1 mode set by preferences
Packit f0b94e
          // (mSHA1Mode) is more restrictive than the SHA1 mode option we're on.
Packit f0b94e
          // (To put it another way, only attempt verification if the SHA1 mode
Packit f0b94e
          // option we're on is as restrictive or more restrictive than
Packit f0b94e
          // mSHA1Mode.) This allows us to gather telemetry information while
Packit f0b94e
          // still enforcing the mode set by preferences.
Packit f0b94e
          if (SHA1ModeMoreRestrictiveThanGivenMode(sha1ModeConfigurations[j])) {
Packit f0b94e
            continue;
Packit f0b94e
          }
Packit f0b94e
Packit f0b94e
          // invalidate any telemetry info relating to failed chains
Packit f0b94e
          if (pinningTelemetryInfo) {
Packit f0b94e
            pinningTelemetryInfo->Reset();
Packit f0b94e
          }
Packit f0b94e
Packit f0b94e
          NSSCertDBTrustDomain trustDomain(
Packit f0b94e
              trustSSL, defaultOCSPFetching, mOCSPCache, pinArg, ocspGETConfig,
Packit f0b94e
              mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
Packit f0b94e
              mPinningMode, keySizeOptions[i],
Packit f0b94e
              ValidityCheckingMode::CheckingOff, sha1ModeConfigurations[j],
Packit f0b94e
              mNetscapeStepUpPolicy, mDistrustedCAPolicy, originAttributes,
Packit f0b94e
              builtChain, pinningTelemetryInfo, hostname);
Packit f0b94e
          rv = BuildCertChainForOneKeyUsage(
Packit f0b94e
              trustDomain, certDER, time,
Packit f0b94e
              KeyUsage::digitalSignature,  //(EC)DHE
Packit f0b94e
              KeyUsage::keyEncipherment,   // RSA
Packit f0b94e
              KeyUsage::keyAgreement,      //(EC)DH
Packit f0b94e
              KeyPurposeId::id_kp_serverAuth, CertPolicyId::anyPolicy,
Packit f0b94e
              stapledOCSPResponse, ocspStaplingStatus);
Packit f0b94e
          if (rv != Success && !IsFatalError(rv) &&
Packit f0b94e
              rv != Result::ERROR_REVOKED_CERTIFICATE &&
Packit f0b94e
              trustDomain.GetIsErrorDueToDistrustedCAPolicy()) {
Packit f0b94e
            // Bug 1444440 - If there are multiple paths, at least one to a CA
Packit f0b94e
            // distrusted-by-policy, and none of them ending in a trusted root,
Packit f0b94e
            // then we might show a different error (UNKNOWN_ISSUER) than we
Packit f0b94e
            // intend, confusing users.
Packit f0b94e
            rv = Result::ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED;
Packit f0b94e
          }
Packit f0b94e
          if (rv == Success &&
Packit f0b94e
              sha1ModeConfigurations[j] == SHA1Mode::ImportedRoot) {
Packit f0b94e
            bool isBuiltInRoot = false;
Packit f0b94e
            rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
Packit f0b94e
            if (rv != Success) {
Packit f0b94e
              break;
Packit f0b94e
            }
Packit f0b94e
            if (isBuiltInRoot) {
Packit f0b94e
              rv = Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
Packit f0b94e
            }
Packit f0b94e
          }
Packit f0b94e
          if (rv == Success) {
Packit f0b94e
            if (keySizeStatus) {
Packit f0b94e
              *keySizeStatus = keySizeStatuses[i];
Packit f0b94e
            }
Packit f0b94e
            if (sha1ModeResult) {
Packit f0b94e
              *sha1ModeResult = sha1ModeResults[j];
Packit f0b94e
            }
Packit f0b94e
            rv = VerifyCertificateTransparencyPolicy(
Packit f0b94e
                trustDomain, builtChain, sctsFromTLSInput, time, ctInfo);
Packit f0b94e
            if (rv != Success) {
Packit f0b94e
              break;
Packit f0b94e
            }
Packit f0b94e
          }
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      if (rv == Success) {
Packit f0b94e
        break;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      if (keySizeStatus) {
Packit f0b94e
        *keySizeStatus = KeySizeStatus::AlreadyBad;
Packit f0b94e
      }
Packit f0b94e
      // The telemetry probe CERT_CHAIN_SHA1_POLICY_STATUS gives us feedback on
Packit f0b94e
      // the result of setting a specific policy. However, we don't want noise
Packit f0b94e
      // from users who have manually set the policy to something other than the
Packit f0b94e
      // default, so we only collect for ImportedRoot (which is the default).
Packit f0b94e
      if (sha1ModeResult && mSHA1Mode == SHA1Mode::ImportedRoot) {
Packit f0b94e
        *sha1ModeResult = SHA1ModeResult::Failed;
Packit f0b94e
      }
Packit f0b94e
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    case certificateUsageSSLCA: {
Packit f0b94e
      NSSCertDBTrustDomain trustDomain(
Packit f0b94e
          trustSSL, defaultOCSPFetching, mOCSPCache, pinArg, ocspGETConfig,
Packit f0b94e
          mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
Packit f0b94e
          pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
Packit f0b94e
          SHA1Mode::Allowed, mNetscapeStepUpPolicy, mDistrustedCAPolicy,
Packit f0b94e
          originAttributes, builtChain, nullptr, nullptr);
Packit f0b94e
      rv = BuildCertChain(trustDomain, certDER, time, EndEntityOrCA::MustBeCA,
Packit f0b94e
                          KeyUsage::keyCertSign, KeyPurposeId::id_kp_serverAuth,
Packit f0b94e
                          CertPolicyId::anyPolicy, stapledOCSPResponse);
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    case certificateUsageEmailSigner: {
Packit f0b94e
      NSSCertDBTrustDomain trustDomain(
Packit f0b94e
          trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, ocspGETConfig,
Packit f0b94e
          mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
Packit f0b94e
          pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
Packit f0b94e
          SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch,
Packit f0b94e
          mDistrustedCAPolicy, originAttributes, builtChain, nullptr, nullptr);
Packit f0b94e
      rv = BuildCertChain(
Packit f0b94e
          trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
Packit f0b94e
          KeyUsage::digitalSignature, KeyPurposeId::id_kp_emailProtection,
Packit f0b94e
          CertPolicyId::anyPolicy, stapledOCSPResponse);
Packit f0b94e
      if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
Packit f0b94e
        rv = BuildCertChain(
Packit f0b94e
            trustDomain, certDER, time, EndEntityOrCA::MustBeEndEntity,
Packit f0b94e
            KeyUsage::nonRepudiation, KeyPurposeId::id_kp_emailProtection,
Packit f0b94e
            CertPolicyId::anyPolicy, stapledOCSPResponse);
Packit f0b94e
      }
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    case certificateUsageEmailRecipient: {
Packit f0b94e
      // TODO: The higher level S/MIME processing should pass in which key
Packit f0b94e
      // usage it is trying to verify for, and base its algorithm choices
Packit f0b94e
      // based on the result of the verification(s).
Packit f0b94e
      NSSCertDBTrustDomain trustDomain(
Packit f0b94e
          trustEmail, defaultOCSPFetching, mOCSPCache, pinArg, ocspGETConfig,
Packit f0b94e
          mOCSPTimeoutSoft, mOCSPTimeoutHard, mCertShortLifetimeInDays,
Packit f0b94e
          pinningDisabled, MIN_RSA_BITS_WEAK, ValidityCheckingMode::CheckingOff,
Packit f0b94e
          SHA1Mode::Allowed, NetscapeStepUpPolicy::NeverMatch,
Packit f0b94e
          mDistrustedCAPolicy, originAttributes, builtChain, nullptr, nullptr);
Packit f0b94e
      rv = BuildCertChain(trustDomain, certDER, time,
Packit f0b94e
                          EndEntityOrCA::MustBeEndEntity,
Packit f0b94e
                          KeyUsage::keyEncipherment,  // RSA
Packit f0b94e
                          KeyPurposeId::id_kp_emailProtection,
Packit f0b94e
                          CertPolicyId::anyPolicy, stapledOCSPResponse);
Packit f0b94e
      if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
Packit f0b94e
        rv = BuildCertChain(trustDomain, certDER, time,
Packit f0b94e
                            EndEntityOrCA::MustBeEndEntity,
Packit f0b94e
                            KeyUsage::keyAgreement,  // ECDH/DH
Packit f0b94e
                            KeyPurposeId::id_kp_emailProtection,
Packit f0b94e
                            CertPolicyId::anyPolicy, stapledOCSPResponse);
Packit f0b94e
      }
Packit f0b94e
      break;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    default:
Packit f0b94e
      rv = Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return Success;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
Result CertVerifier::VerifySSLServerCert(
Packit f0b94e
    const UniqueCERTCertificate& peerCert,
Packit f0b94e
    /*optional*/ const SECItem* stapledOCSPResponse,
Packit f0b94e
    /*optional*/ const SECItem* sctsFromTLS, Time time,
Packit f0b94e
    /*optional*/ void* pinarg, const nsACString& hostname,
Packit f0b94e
    /*out*/ UniqueCERTCertList& builtChain,
Packit f0b94e
    /*optional*/ bool saveIntermediatesInPermanentDatabase,
Packit f0b94e
    /*optional*/ Flags flags,
Packit f0b94e
    /*optional*/ const OriginAttributes& originAttributes,
Packit f0b94e
    /*optional out*/ SECOidTag* evOidPolicy,
Packit f0b94e
    /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
Packit f0b94e
    /*optional out*/ KeySizeStatus* keySizeStatus,
Packit f0b94e
    /*optional out*/ SHA1ModeResult* sha1ModeResult,
Packit f0b94e
    /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo,
Packit f0b94e
    /*optional out*/ CertificateTransparencyInfo* ctInfo) {
Packit f0b94e
  MOZ_ASSERT(peerCert);
Packit f0b94e
  // XXX: MOZ_ASSERT(pinarg);
Packit f0b94e
  MOZ_ASSERT(!hostname.IsEmpty());
Packit f0b94e
Packit f0b94e
  if (evOidPolicy) {
Packit f0b94e
    *evOidPolicy = SEC_OID_UNKNOWN;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (hostname.IsEmpty()) {
Packit f0b94e
    return Result::ERROR_BAD_CERT_DOMAIN;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // CreateCertErrorRunnable assumes that CheckCertHostname is only called
Packit f0b94e
  // if VerifyCert succeeded.
Packit f0b94e
  Result rv =
Packit f0b94e
      VerifyCert(peerCert.get(), certificateUsageSSLServer, time, pinarg,
Packit f0b94e
                 PromiseFlatCString(hostname).get(), builtChain, flags,
Packit f0b94e
                 stapledOCSPResponse, sctsFromTLS, originAttributes,
Packit f0b94e
                 evOidPolicy, ocspStaplingStatus, keySizeStatus, sha1ModeResult,
Packit f0b94e
                 pinningTelemetryInfo, ctInfo);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input peerCertInput;
Packit f0b94e
  rv = peerCertInput.Init(peerCert->derCert.data, peerCert->derCert.len);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input stapledOCSPResponseInput;
Packit f0b94e
  Input* responseInputPtr = nullptr;
Packit f0b94e
  if (stapledOCSPResponse) {
Packit f0b94e
    rv = stapledOCSPResponseInput.Init(stapledOCSPResponse->data,
Packit f0b94e
                                       stapledOCSPResponse->len);
Packit f0b94e
    if (rv != Success) {
Packit f0b94e
      // The stapled OCSP response was too big.
Packit f0b94e
      return Result::ERROR_OCSP_MALFORMED_RESPONSE;
Packit f0b94e
    }
Packit f0b94e
    responseInputPtr = &stapledOCSPResponseInput;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!(flags & FLAG_TLS_IGNORE_STATUS_REQUEST)) {
Packit f0b94e
    rv = CheckTLSFeaturesAreSatisfied(peerCertInput, responseInputPtr);
Packit f0b94e
    if (rv != Success) {
Packit f0b94e
      return rv;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  Input hostnameInput;
Packit f0b94e
  rv = hostnameInput.Init(
Packit f0b94e
      BitwiseCast<const uint8_t*, const char*>(hostname.BeginReading()),
Packit f0b94e
      hostname.Length());
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return Result::FATAL_ERROR_INVALID_ARGS;
Packit f0b94e
  }
Packit f0b94e
  bool isBuiltInRoot;
Packit f0b94e
  rv = IsCertChainRootBuiltInRoot(builtChain, isBuiltInRoot);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
  BRNameMatchingPolicy nameMatchingPolicy(
Packit f0b94e
      isBuiltInRoot ? mNameMatchingMode
Packit f0b94e
                    : BRNameMatchingPolicy::Mode::DoNotEnforce);
Packit f0b94e
  rv = CheckCertHostname(peerCertInput, hostnameInput, nameMatchingPolicy);
Packit f0b94e
  if (rv != Success) {
Packit f0b94e
    // Treat malformed name information as a domain mismatch.
Packit f0b94e
    if (rv == Result::ERROR_BAD_DER) {
Packit f0b94e
      return Result::ERROR_BAD_CERT_DOMAIN;
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (saveIntermediatesInPermanentDatabase) {
Packit f0b94e
    SaveIntermediateCerts(builtChain);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return Success;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace psm
Packit f0b94e
}  // namespace mozilla