tor-browser

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

CertVerifier.h (12357B)


      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 #ifndef CertVerifier_h
      8 #define CertVerifier_h
      9 
     10 #include "CTPolicyEnforcer.h"
     11 #include "CTVerifyResult.h"
     12 #include "EnterpriseRoots.h"
     13 #include "OCSPCache.h"
     14 #include "RootCertificateTelemetryUtils.h"
     15 #include "ScopedNSSTypes.h"
     16 #include "mozilla/EnumSet.h"
     17 #include "mozilla/TimeStamp.h"
     18 #include "mozilla/UniquePtr.h"
     19 #include "mozilla/glean/bindings/MetricTypes.h"
     20 #include "mozpkix/pkixder.h"
     21 #include "mozpkix/pkixtypes.h"
     22 #include "nsString.h"
     23 #include "signature_cache_ffi.h"
     24 #include "sslt.h"
     25 
     26 #if defined(_MSC_VER)
     27 #  pragma warning(push)
     28 // Silence "RootingAPI.h(718): warning C4324: 'js::DispatchWrapper<T>':
     29 // structure was padded due to alignment specifier with [ T=void * ]"
     30 #  pragma warning(disable : 4324)
     31 #endif /* defined(_MSC_VER) */
     32 #include "mozilla/BasePrincipal.h"
     33 #if defined(_MSC_VER)
     34 #  pragma warning(pop) /* popping the pragma in this file */
     35 #endif                 /* defined(_MSC_VER) */
     36 
     37 namespace mozilla {
     38 namespace ct {
     39 
     40 // Including the headers of the classes below would bring along all of their
     41 // dependent headers and force us to export them in moz.build.
     42 // Just forward-declare the classes here instead.
     43 class MultiLogCTVerifier;
     44 
     45 }  // namespace ct
     46 }  // namespace mozilla
     47 
     48 namespace mozilla {
     49 namespace psm {
     50 
     51 typedef mozilla::pkix::Result Result;
     52 
     53 enum class EVStatus : uint8_t {
     54  NotEV = 0,
     55  EV = 1,
     56 };
     57 
     58 // These values correspond to the CERT_CHAIN_KEY_SIZE_STATUS telemetry.
     59 enum class KeySizeStatus {
     60  NeverChecked = 0,
     61  LargeMinimumSucceeded = 1,
     62  CompatibilityRisk = 2,
     63  AlreadyBad = 3,
     64 };
     65 
     66 enum class CRLiteMode {
     67  Disabled = 0,
     68  TelemetryOnly = 1,
     69  Enforce = 2,
     70 };
     71 
     72 enum class VerifyUsage {
     73  TLSServer = 1,
     74  TLSServerCA = 2,
     75  TLSClient = 3,
     76  TLSClientCA = 4,
     77  EmailSigner = 5,
     78  EmailRecipient = 6,
     79  EmailCA = 7,
     80 };
     81 
     82 // Describes the source of the associated issuer.
     83 enum class IssuerSource {
     84  TLSHandshake,            // included by the peer in the TLS handshake
     85  PreloadedIntermediates,  // a preloaded intermediate (via remote settings)
     86  ThirdPartyCertificates,  // a third-party certificate gleaned from the OS
     87  NSSCertDB,  // a certificate found in the profile's NSS certificate DB
     88  BuiltInRootsModule,  // a root from the built-in roots module
     89 };
     90 
     91 using IssuerSources = EnumSet<IssuerSource>;
     92 
     93 class PinningTelemetryInfo {
     94 public:
     95  PinningTelemetryInfo()
     96      : certPinningResultBucket(0), rootBucket(ROOT_CERTIFICATE_UNKNOWN) {
     97    Reset();
     98  }
     99 
    100  // Should we accumulate pinning telemetry for the result?
    101  bool accumulateResult;
    102  bool isMoz;
    103  bool testMode;
    104  int32_t certPinningResultBucket;
    105  // Should we accumulate telemetry for the root?
    106  bool accumulateForRoot;
    107  int32_t rootBucket;
    108 
    109  void Reset() {
    110    accumulateForRoot = false;
    111    accumulateResult = false;
    112    isMoz = false;
    113    testMode = false;
    114  }
    115 };
    116 
    117 class CertificateTransparencyInfo {
    118 public:
    119  CertificateTransparencyInfo() : enabled(false), policyCompliance(Nothing()) {
    120    Reset();
    121  }
    122 
    123  // Was CT enabled?
    124  bool enabled;
    125  // Verification result of the processed SCTs.
    126  mozilla::ct::CTVerifyResult verifyResult;
    127  // Connection compliance to the CT Policy.
    128  Maybe<mozilla::ct::CTPolicyCompliance> policyCompliance;
    129 
    130  void Reset();
    131 };
    132 
    133 class DelegatedCredentialInfo {
    134 public:
    135  DelegatedCredentialInfo() : scheme(ssl_sig_none), authKeyBits(0) {}
    136  DelegatedCredentialInfo(SSLSignatureScheme scheme, uint32_t authKeyBits)
    137      : scheme(scheme), authKeyBits(authKeyBits) {}
    138 
    139  // The signature scheme to be used in CertVerify. This tells us
    140  // whether to interpret |authKeyBits| in an RSA or ECDSA context.
    141  SSLSignatureScheme scheme;
    142 
    143  // The size of the key, in bits.
    144  uint32_t authKeyBits;
    145 };
    146 
    147 class SkipInvalidSANsForNonBuiltInRootsPolicy
    148    : public pkix::NameMatchingPolicy {
    149 public:
    150  explicit SkipInvalidSANsForNonBuiltInRootsPolicy(bool rootIsBuiltIn)
    151      : mRootIsBuiltIn(rootIsBuiltIn) {}
    152 
    153  virtual pkix::Result FallBackToCommonName(
    154      pkix::Time,
    155      /*out*/ pkix::FallBackToSearchWithinSubject& fallBackToCommonName)
    156      override {
    157    fallBackToCommonName = pkix::FallBackToSearchWithinSubject::No;
    158    return pkix::Success;
    159  }
    160 
    161  virtual pkix::HandleInvalidSubjectAlternativeNamesBy
    162  HandleInvalidSubjectAlternativeNames() override {
    163    return mRootIsBuiltIn
    164               ? pkix::HandleInvalidSubjectAlternativeNamesBy::Halting
    165               : pkix::HandleInvalidSubjectAlternativeNamesBy::Skipping;
    166  }
    167 
    168 private:
    169  bool mRootIsBuiltIn;
    170 };
    171 
    172 class NSSCertDBTrustDomain;
    173 
    174 class CertVerifier {
    175 public:
    176  typedef unsigned int Flags;
    177  // XXX: FLAG_LOCAL_ONLY is ignored in the classic verification case
    178  static const Flags FLAG_LOCAL_ONLY;
    179  // Don't perform fallback DV validation on EV validation failure.
    180  static const Flags FLAG_MUST_BE_EV;
    181  // TLS feature request_status should be ignored
    182  static const Flags FLAG_TLS_IGNORE_STATUS_REQUEST;
    183 
    184  // These values correspond to the SSL_OCSP_STAPLING telemetry.
    185  enum OCSPStaplingStatus {
    186    OCSP_STAPLING_NEVER_CHECKED = 0,
    187    OCSP_STAPLING_GOOD = 1,
    188    OCSP_STAPLING_NONE = 2,
    189    OCSP_STAPLING_EXPIRED = 3,
    190    OCSP_STAPLING_INVALID = 4,
    191  };
    192 
    193  // *evOidPolicy == SEC_OID_UNKNOWN means the cert is NOT EV
    194  // Only one usage per verification is supported.
    195  mozilla::pkix::Result VerifyCert(
    196      const nsTArray<uint8_t>& certBytes, VerifyUsage usage,
    197      mozilla::pkix::Time time, void* pinArg, const char* hostname,
    198      /*out*/ nsTArray<nsTArray<uint8_t>>& builtChain, Flags flags = 0,
    199      /*optional in*/
    200      const Maybe<nsTArray<nsTArray<uint8_t>>>& extraCertificates = Nothing(),
    201      /*optional in*/ const Maybe<nsTArray<uint8_t>>& stapledOCSPResponseArg =
    202          Nothing(),
    203      /*optional in*/ const Maybe<nsTArray<uint8_t>>& sctsFromTLS = Nothing(),
    204      /*optional in*/ const OriginAttributes& originAttributes =
    205          OriginAttributes(),
    206      /*optional out*/ EVStatus* evStatus = nullptr,
    207      /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
    208      /*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
    209      /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
    210      /*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
    211      /*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr,
    212      /*optional out*/ bool* madeOCSPRequests = nullptr,
    213      /*optional out*/ IssuerSources* = nullptr);
    214 
    215  mozilla::pkix::Result VerifySSLServerCert(
    216      const nsTArray<uint8_t>& peerCert, mozilla::pkix::Time time, void* pinarg,
    217      const nsACString& hostname,
    218      /*out*/ nsTArray<nsTArray<uint8_t>>& builtChain,
    219      /*optional*/ Flags flags = 0,
    220      /*optional*/ const Maybe<nsTArray<nsTArray<uint8_t>>>& extraCertificates =
    221          Nothing(),
    222      /*optional*/ const Maybe<nsTArray<uint8_t>>& stapledOCSPResponse =
    223          Nothing(),
    224      /*optional*/ const Maybe<nsTArray<uint8_t>>& sctsFromTLS = Nothing(),
    225      /*optional*/ const Maybe<DelegatedCredentialInfo>& dcInfo = Nothing(),
    226      /*optional*/ const OriginAttributes& originAttributes =
    227          OriginAttributes(),
    228      /*optional out*/ EVStatus* evStatus = nullptr,
    229      /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
    230      /*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
    231      /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
    232      /*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr,
    233      /*optional out*/ bool* isBuiltChainRootBuiltInRoot = nullptr,
    234      /*optional out*/ bool* madeOCSPRequests = nullptr,
    235      /*optional out*/ IssuerSources* = nullptr);
    236 
    237  enum OcspDownloadConfig { ocspOff = 0, ocspOn = 1, ocspEVOnly = 2 };
    238  enum OcspStrictConfig { ocspRelaxed = 0, ocspStrict };
    239 
    240  enum class CertificateTransparencyMode {
    241    Disabled = 0,
    242    TelemetryOnly = 1,
    243    Enforce = 2,
    244  };
    245 
    246  struct CertificateTransparencyConfig {
    247    CertificateTransparencyConfig(
    248        CertificateTransparencyMode mode, nsCString&& skipForHosts,
    249        nsTArray<CopyableTArray<uint8_t>>&& skipForSPKIHashes)
    250        : mMode(mode),
    251          mSkipForHosts(std::move(skipForHosts)),
    252          mSkipForSPKIHashes(std::move(skipForSPKIHashes)) {}
    253 
    254    CertificateTransparencyMode mMode;
    255    nsCString mSkipForHosts;
    256    nsTArray<CopyableTArray<uint8_t>> mSkipForSPKIHashes;
    257  };
    258 
    259  CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
    260               mozilla::TimeDuration ocspTimeoutSoft,
    261               mozilla::TimeDuration ocspTimeoutHard,
    262               uint32_t certShortLifetimeInDays,
    263               CertificateTransparencyConfig&& ctConfig, CRLiteMode crliteMode,
    264               const nsTArray<EnterpriseCert>& thirdPartyCerts);
    265  ~CertVerifier();
    266 
    267  void ClearOCSPCache() { mOCSPCache.Clear(); }
    268  void ClearTrustCache() { trust_cache_clear(mTrustCache.get()); }
    269 
    270  const OcspDownloadConfig mOCSPDownloadConfig;
    271  const bool mOCSPStrict;
    272  const mozilla::TimeDuration mOCSPTimeoutSoft;
    273  const mozilla::TimeDuration mOCSPTimeoutHard;
    274  const uint32_t mCertShortLifetimeInDays;
    275  const CertificateTransparencyConfig mCTConfig;
    276  const CRLiteMode mCRLiteMode;
    277 
    278 private:
    279  OCSPCache mOCSPCache;
    280  // We keep a copy of the bytes of each third party root to own.
    281  nsTArray<EnterpriseCert> mThirdPartyCerts;
    282  // This is a reusable, precomputed list of Inputs corresponding to each root
    283  // in mThirdPartyCerts that wasn't too long to make an Input out of.
    284  nsTArray<mozilla::pkix::Input> mThirdPartyRootInputs;
    285  // Similarly, but with intermediates.
    286  nsTArray<mozilla::pkix::Input> mThirdPartyIntermediateInputs;
    287 
    288  // We only have a forward declarations of these classes (see above)
    289  // so we must allocate dynamically.
    290  UniquePtr<mozilla::ct::MultiLogCTVerifier> mCTVerifier;
    291 
    292  // If many connections are made to a site using a particular certificate,
    293  // this cache will speed up verifications after the first one by saving the
    294  // results of signature verification.
    295  // This will also be beneficial in situations where different sites use
    296  // different certificates that happen to be issued by the same intermediate.
    297  UniquePtr<SignatureCache, decltype(&signature_cache_free)> mSignatureCache;
    298  // Similarly, this caches the results of looking up the trust of a
    299  // certificate in NSS, which is slow.
    300  UniquePtr<TrustCache, decltype(&trust_cache_free)> mTrustCache;
    301 
    302  void LoadKnownCTLogs();
    303  mozilla::pkix::Result VerifyCertificateTransparencyPolicy(
    304      NSSCertDBTrustDomain& trustDomain,
    305      const nsTArray<nsTArray<uint8_t>>& builtChain,
    306      mozilla::pkix::Input sctsFromTLS, mozilla::pkix::Time time,
    307      const char* hostname,
    308      /*optional out*/ CertificateTransparencyInfo* ctInfo);
    309  mozilla::pkix::Result VerifyCertificateTransparencyPolicyInner(
    310      NSSCertDBTrustDomain& trustDomain,
    311      const nsTArray<nsTArray<uint8_t>>& builtChain,
    312      mozilla::pkix::Input sctsFromTLS, mozilla::pkix::Time time,
    313      /*optional out*/ CertificateTransparencyInfo* ctInfo);
    314 };
    315 
    316 mozilla::pkix::Result IsCertBuiltInRoot(pkix::Input certInput, bool& result);
    317 mozilla::pkix::Result CertListContainsExpectedKeys(const CERTCertList* certList,
    318                                                   const char* hostname,
    319                                                   mozilla::pkix::Time time);
    320 
    321 // Verify signed data, making use of the given SignatureCache. That is, if the
    322 // (data, digestAlgorithm, signature, subjectPublicKeyInfo) tuple has already
    323 // been verified and is in the cache, this skips the work of verifying the
    324 // signature (which is slow) and returns the already-known result.
    325 mozilla::pkix::Result VerifySignedDataWithCache(
    326    mozilla::pkix::der::PublicKeyAlgorithm publicKeyAlg,
    327    mozilla::glean::impl::DenominatorMetric telemetryDenominator,
    328    mozilla::glean::impl::NumeratorMetric telemetryNumerator,
    329    mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm,
    330    mozilla::pkix::Input signature, mozilla::pkix::Input subjectPublicKeyInfo,
    331    SignatureCache* signatureCache, void* pinArg);
    332 
    333 }  // namespace psm
    334 }  // namespace mozilla
    335 
    336 #endif  // CertVerifier_h