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