tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AppTrustDomain.cpp (11879B)


      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 "AppTrustDomain.h"
      8 
      9 #include "MainThreadUtils.h"
     10 #include "cert_storage/src/cert_storage.h"
     11 // FIXME: these two must be included before certdb.h {
     12 #include "seccomon.h"
     13 #include "certt.h"
     14 // }
     15 #include "certdb.h"
     16 #include "mozilla/Logging.h"
     17 #include "mozilla/Preferences.h"
     18 #include "mozpkix/pkixnss.h"
     19 #include "NSSCertDBTrustDomain.h"
     20 #include "nsComponentManagerUtils.h"
     21 #include "nsDirectoryServiceUtils.h"
     22 #include "nsIContentSignatureVerifier.h"
     23 #include "nsIX509CertDB.h"
     24 #include "nsNSSCertificate.h"
     25 #include "nsNetUtil.h"
     26 #include "prerror.h"
     27 
     28 // Generated by gen_cert_header.py, which gets called by the build system.
     29 #include "xpcshell.inc"
     30 // Add-on signing Certificates
     31 #include "addons-public.inc"
     32 #include "addons-public-intermediate.inc"
     33 #include "addons-stage.inc"
     34 #include "addons-stage-intermediate.inc"
     35 // Content signature root certificates
     36 #include "content-signature-dev.inc"
     37 #include "content-signature-local.inc"
     38 #include "content-signature-prod.inc"
     39 #include "content-signature-stage.inc"
     40 
     41 using namespace mozilla::pkix;
     42 
     43 extern mozilla::LazyLogModule gPIPNSSLog;
     44 
     45 namespace mozilla {
     46 namespace psm {
     47 
     48 AppTrustDomain::AppTrustDomain(nsTArray<Span<const uint8_t>>&& collectedCerts)
     49    : mIntermediates(std::move(collectedCerts)),
     50      mCertBlocklist(do_GetService(NS_CERT_STORAGE_CID)) {}
     51 
     52 nsresult AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) {
     53  if (!mTrustedRoots.IsEmpty()) {
     54    return NS_ERROR_ALREADY_INITIALIZED;
     55  }
     56  switch (trustedRoot) {
     57    case nsIX509CertDB::AppXPCShellRoot:
     58      mTrustedRoots.AppendElements(xpcshellRoots, std::size(xpcshellRoots));
     59      break;
     60 
     61    case nsIX509CertDB::AddonsPublicRoot:
     62      mTrustedRoots.AppendElements(addonsPublicRoots,
     63                                   std::size(addonsPublicRoots));
     64      break;
     65 
     66    case nsIX509CertDB::AddonsStageRoot:
     67      mTrustedRoots.AppendElements(addonsStageRoots,
     68                                   std::size(addonsStageRoots));
     69      break;
     70 
     71    case nsIContentSignatureVerifier::ContentSignatureLocalRoot:
     72      mTrustedRoots.AppendElements(contentSignatureLocalRoots,
     73                                   std::size(contentSignatureLocalRoots));
     74      break;
     75 
     76    case nsIContentSignatureVerifier::ContentSignatureProdRoot:
     77      mTrustedRoots.AppendElements(contentSignatureProdRoots,
     78                                   std::size(contentSignatureProdRoots));
     79      break;
     80 
     81    case nsIContentSignatureVerifier::ContentSignatureStageRoot:
     82      mTrustedRoots.AppendElements(contentSignatureStageRoots,
     83                                   std::size(contentSignatureStageRoots));
     84      break;
     85 
     86    case nsIContentSignatureVerifier::ContentSignatureDevRoot:
     87      mTrustedRoots.AppendElements(contentSignatureDevRoots,
     88                                   std::size(contentSignatureDevRoots));
     89      break;
     90 
     91    default:
     92      return NS_ERROR_INVALID_ARG;
     93  }
     94 
     95  // If we're verifying add-ons signed by our production root, we want to make
     96  // sure a valid intermediate certificate is available for path building.
     97  // The intermediate bundled with signed XPI files may have expired and be
     98  // considered invalid, which can result in bug 1548973.
     99  if (trustedRoot == nsIX509CertDB::AddonsPublicRoot) {
    100    mAddonsIntermediates.AppendElements(addonsPublicIntermediates,
    101                                        std::size(addonsPublicIntermediates));
    102  }
    103  // Similarly to the above logic for production, we hardcode the intermediate
    104  // stage certificate here, so that stage is equivalent to production.
    105  if (trustedRoot == nsIX509CertDB::AddonsStageRoot) {
    106    mAddonsIntermediates.AppendElements(addonsStageIntermediates,
    107                                        std::size(addonsStageIntermediates));
    108  }
    109 
    110  return NS_OK;
    111 }
    112 
    113 pkix::Result AppTrustDomain::FindIssuer(Input encodedIssuerName,
    114                                        IssuerChecker& checker, Time) {
    115  MOZ_ASSERT(!mTrustedRoots.IsEmpty());
    116  if (mTrustedRoots.IsEmpty()) {
    117    return pkix::Result::FATAL_ERROR_INVALID_STATE;
    118  }
    119 
    120  nsTArray<Input> candidates;
    121  for (const auto& root : mTrustedRoots) {
    122    Input rootInput;
    123    pkix::Result rv = rootInput.Init(root.Elements(), root.Length());
    124    // This should never fail, since the possible roots are all hard-coded and
    125    // they should never be too long.
    126    if (rv != Success) {
    127      return rv;
    128    }
    129    candidates.AppendElement(std::move(rootInput));
    130  }
    131  for (const auto& intermediate : mAddonsIntermediates) {
    132    Input intermediateInput;
    133    pkix::Result rv =
    134        intermediateInput.Init(intermediate.Elements(), intermediate.Length());
    135    // Again, this should never fail for the same reason as above.
    136    if (rv != Success) {
    137      return rv;
    138    }
    139    candidates.AppendElement(std::move(intermediateInput));
    140  }
    141  for (const auto& intermediate : mIntermediates) {
    142    Input intermediateInput;
    143    pkix::Result rv =
    144        intermediateInput.Init(intermediate.Elements(), intermediate.Length());
    145    // This is untrusted input, so skip any intermediates that are too large.
    146    if (rv != Success) {
    147      continue;
    148    }
    149    candidates.AppendElement(std::move(intermediateInput));
    150  }
    151 
    152  for (const auto& candidate : candidates) {
    153    bool keepGoing;
    154    pkix::Result rv = checker.Check(
    155        candidate, nullptr /*additionalNameConstraints*/, keepGoing);
    156    if (rv != Success) {
    157      return rv;
    158    }
    159    if (!keepGoing) {
    160      return Success;
    161    }
    162  }
    163 
    164  // If the above did not succeed in building a verified certificate chain,
    165  // fall back to searching for candidates in NSS. This is important in case an
    166  // intermediate involved in add-on signing expires before it is replaced. See
    167  // bug 1548973.
    168  SECItem encodedIssuerNameSECItem = UnsafeMapInputToSECItem(encodedIssuerName);
    169  UniqueCERTCertList nssCandidates(CERT_CreateSubjectCertList(
    170      nullptr, CERT_GetDefaultCertDB(), &encodedIssuerNameSECItem, 0, false));
    171  if (nssCandidates) {
    172    for (CERTCertListNode* n = CERT_LIST_HEAD(nssCandidates);
    173         !CERT_LIST_END(n, nssCandidates); n = CERT_LIST_NEXT(n)) {
    174      Input certDER;
    175      pkix::Result rv =
    176          certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
    177      if (rv != Success) {
    178        continue;  // probably too big
    179      }
    180 
    181      bool keepGoing;
    182      rv = checker.Check(certDER, nullptr /*additionalNameConstraints*/,
    183                         keepGoing);
    184      if (rv != Success) {
    185        return rv;
    186      }
    187      if (!keepGoing) {
    188        break;
    189      }
    190    }
    191  }
    192 
    193  return Success;
    194 }
    195 
    196 pkix::Result AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
    197                                          const CertPolicyId& policy,
    198                                          Input candidateCertDER,
    199                                          /*out*/ TrustLevel& trustLevel) {
    200  MOZ_ASSERT(policy.IsAnyPolicy());
    201  MOZ_ASSERT(!mTrustedRoots.IsEmpty());
    202  if (!policy.IsAnyPolicy()) {
    203    return pkix::Result::FATAL_ERROR_INVALID_ARGS;
    204  }
    205  if (mTrustedRoots.IsEmpty()) {
    206    return pkix::Result::FATAL_ERROR_INVALID_STATE;
    207  }
    208 
    209  nsTArray<uint8_t> issuerBytes;
    210  nsTArray<uint8_t> serialBytes;
    211  nsTArray<uint8_t> subjectBytes;
    212  nsTArray<uint8_t> pubKeyBytes;
    213 
    214  pkix::Result result =
    215      BuildRevocationCheckArrays(candidateCertDER, endEntityOrCA, issuerBytes,
    216                                 serialBytes, subjectBytes, pubKeyBytes);
    217  if (result != Success) {
    218    return result;
    219  }
    220 
    221  int16_t revocationState;
    222  nsresult nsrv = mCertBlocklist->GetRevocationState(
    223      issuerBytes, serialBytes, subjectBytes, pubKeyBytes, &revocationState);
    224  if (NS_FAILED(nsrv)) {
    225    return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
    226  }
    227 
    228  if (revocationState == nsICertStorage::STATE_ENFORCE) {
    229    return pkix::Result::ERROR_REVOKED_CERTIFICATE;
    230  }
    231 
    232  // mTrustedRoots are the only trust anchors for this validation.
    233  Span<const uint8_t> candidateCertDERSpan = {candidateCertDER.UnsafeGetData(),
    234                                              candidateCertDER.GetLength()};
    235  for (const auto& trustedRoot : mTrustedRoots) {
    236    if (trustedRoot == candidateCertDERSpan) {
    237      trustLevel = TrustLevel::TrustAnchor;
    238      return Success;
    239    }
    240  }
    241 
    242  trustLevel = TrustLevel::InheritsTrust;
    243  return Success;
    244 }
    245 
    246 pkix::Result AppTrustDomain::DigestBuf(Input item, DigestAlgorithm digestAlg,
    247                                       /*out*/ uint8_t* digestBuf,
    248                                       size_t digestBufLen) {
    249  return DigestBufNSS(item, digestAlg, digestBuf, digestBufLen);
    250 }
    251 
    252 pkix::Result AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, Time,
    253                                             Duration,
    254                                             /*optional*/ const Input*,
    255                                             /*optional*/ const Input*) {
    256  // We don't currently do revocation checking. If we need to distrust an Apps
    257  // certificate, we will use the active distrust mechanism.
    258  return Success;
    259 }
    260 
    261 pkix::Result AppTrustDomain::IsChainValid(const DERArray& certChain, Time time,
    262                                          const CertPolicyId& requiredPolicy) {
    263  MOZ_ASSERT(requiredPolicy.IsAnyPolicy());
    264  return Success;
    265 }
    266 
    267 pkix::Result AppTrustDomain::CheckSignatureDigestAlgorithm(
    268    DigestAlgorithm digestAlg, EndEntityOrCA, Time) {
    269  switch (digestAlg) {
    270    case DigestAlgorithm::sha256:  // fall through
    271    case DigestAlgorithm::sha384:  // fall through
    272    case DigestAlgorithm::sha512:
    273      return Success;
    274    case DigestAlgorithm::sha1:
    275      return pkix::Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
    276  }
    277  return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
    278 }
    279 
    280 pkix::Result AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
    281    EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits) {
    282  if (modulusSizeInBits < 2048u) {
    283    return pkix::Result::ERROR_INADEQUATE_KEY_SIZE;
    284  }
    285  return Success;
    286 }
    287 
    288 pkix::Result AppTrustDomain::VerifyRSAPKCS1SignedData(
    289    Input data, DigestAlgorithm digestAlgorithm, Input signature,
    290    Input subjectPublicKeyInfo) {
    291  // TODO: We should restrict signatures to SHA-256 or better.
    292  return VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature,
    293                                     subjectPublicKeyInfo, nullptr);
    294 }
    295 
    296 pkix::Result AppTrustDomain::VerifyRSAPSSSignedData(
    297    Input data, DigestAlgorithm digestAlgorithm, Input signature,
    298    Input subjectPublicKeyInfo) {
    299  return VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature,
    300                                   subjectPublicKeyInfo, nullptr);
    301 }
    302 
    303 pkix::Result AppTrustDomain::CheckECDSACurveIsAcceptable(
    304    EndEntityOrCA /*endEntityOrCA*/, NamedCurve curve) {
    305  switch (curve) {
    306    case NamedCurve::secp256r1:  // fall through
    307    case NamedCurve::secp384r1:  // fall through
    308    case NamedCurve::secp521r1:
    309      return Success;
    310  }
    311 
    312  return pkix::Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
    313 }
    314 
    315 pkix::Result AppTrustDomain::VerifyECDSASignedData(
    316    Input data, DigestAlgorithm digestAlgorithm, Input signature,
    317    Input subjectPublicKeyInfo) {
    318  return VerifyECDSASignedDataNSS(data, digestAlgorithm, signature,
    319                                  subjectPublicKeyInfo, nullptr);
    320 }
    321 
    322 pkix::Result AppTrustDomain::CheckValidityIsAcceptable(
    323    Time /*notBefore*/, Time /*notAfter*/, EndEntityOrCA /*endEntityOrCA*/,
    324    KeyPurposeId /*keyPurpose*/) {
    325  return Success;
    326 }
    327 
    328 void AppTrustDomain::NoteAuxiliaryExtension(AuxiliaryExtension /*extension*/,
    329                                            Input /*extensionData*/) {}
    330 
    331 }  // namespace psm
    332 }  // namespace mozilla