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 "BRNameMatchingPolicy.h"
11 #include "CTVerifyResult.h"
12 #include "OCSPCache.h"
13 #include "ScopedNSSTypes.h"
14 #include "mozilla/Telemetry.h"
15 #include "mozilla/UniquePtr.h"
16 #include "pkix/pkixtypes.h"
17 
18 #if defined(_MSC_VER)
19 #pragma warning(push)
20 // Silence "RootingAPI.h(718): warning C4324: 'js::DispatchWrapper<T>':
21 // structure was padded due to alignment specifier with [ T=void * ]"
22 #pragma warning(disable:4324)
23 // Silence "Value.h(448): warning C4365: 'return': conversion from 'const
24 // int32_t' to 'JS::Value::PayloadType', signed/unsigned mismatch"
25 #pragma warning(disable:4365)
26 // Silence "warning C5031: #pragma warning(pop): likely mismatch, popping
27 // warning state pushed in different file
28 #pragma warning(disable:5031)
29 #endif /* defined(_MSC_VER) */
30 #include "mozilla/BasePrincipal.h"
31 #if defined(_MSC_VER)
32 #pragma warning(pop) /* popping the pragma in Vector.h */
33 #pragma warning(pop) /* popping the pragma in this file */
34 #endif /* defined(_MSC_VER) */
35 
36 namespace mozilla { namespace ct {
37 
38 // Including MultiLogCTVerifier.h would bring along all of its dependent
39 // headers and force us to export them in moz.build. Just forward-declare
40 // the class here instead.
41 class MultiLogCTVerifier;
42 
43 } } // namespace mozilla::ct
44 
45 namespace mozilla { namespace psm {
46 
47 typedef mozilla::pkix::Result Result;
48 
49 // These values correspond to the CERT_CHAIN_KEY_SIZE_STATUS telemetry.
50 enum class KeySizeStatus {
51   NeverChecked = 0,
52   LargeMinimumSucceeded = 1,
53   CompatibilityRisk = 2,
54   AlreadyBad = 3,
55 };
56 
57 // These values correspond to the CERT_CHAIN_SHA1_POLICY_STATUS telemetry.
58 enum class SHA1ModeResult {
59   NeverChecked = 0,
60   SucceededWithoutSHA1 = 1,
61   SucceededWithImportedRoot = 2,
62   SucceededWithImportedRootOrSHA1Before2016 = 3,
63   SucceededWithSHA1 = 4,
64   Failed = 5,
65 };
66 
67 enum class NetscapeStepUpPolicy : uint32_t;
68 
69 class PinningTelemetryInfo
70 {
71 public:
PinningTelemetryInfo()72   PinningTelemetryInfo() { Reset(); }
73 
74   // Should we accumulate pinning telemetry for the result?
75   bool accumulateResult;
76   Telemetry::ID certPinningResultHistogram;
77   int32_t certPinningResultBucket;
78   // Should we accumulate telemetry for the root?
79   bool accumulateForRoot;
80   int32_t rootBucket;
81 
Reset()82   void Reset() { accumulateForRoot = false; accumulateResult = false; }
83 };
84 
85 class CertificateTransparencyInfo
86 {
87 public:
CertificateTransparencyInfo()88   CertificateTransparencyInfo() { Reset(); }
89 
90   // Was CT enabled?
91   bool enabled;
92   // Did we receive and process any binary SCT data from the supported sources?
93   bool processedSCTs;
94   // Verification result of the processed SCTs.
95   mozilla::ct::CTVerifyResult verifyResult;
96 
Reset()97   void Reset() { enabled = false; processedSCTs = false; verifyResult.Reset(); }
98 };
99 
100 class NSSCertDBTrustDomain;
101 
102 class CertVerifier
103 {
104 public:
105   typedef unsigned int Flags;
106   // XXX: FLAG_LOCAL_ONLY is ignored in the classic verification case
107   static const Flags FLAG_LOCAL_ONLY;
108   // Don't perform fallback DV validation on EV validation failure.
109   static const Flags FLAG_MUST_BE_EV;
110   // TLS feature request_status should be ignored
111   static const Flags FLAG_TLS_IGNORE_STATUS_REQUEST;
112 
113   // These values correspond to the SSL_OCSP_STAPLING telemetry.
114   enum OCSPStaplingStatus {
115     OCSP_STAPLING_NEVER_CHECKED = 0,
116     OCSP_STAPLING_GOOD = 1,
117     OCSP_STAPLING_NONE = 2,
118     OCSP_STAPLING_EXPIRED = 3,
119     OCSP_STAPLING_INVALID = 4,
120   };
121 
122   // *evOidPolicy == SEC_OID_UNKNOWN means the cert is NOT EV
123   // Only one usage per verification is supported.
124   mozilla::pkix::Result VerifyCert(
125                     CERTCertificate* cert,
126                     SECCertificateUsage usage,
127                     mozilla::pkix::Time time,
128                     void* pinArg,
129                     const char* hostname,
130             /*out*/ UniqueCERTCertList& builtChain,
131                     Flags flags = 0,
132     /*optional in*/ const SECItem* stapledOCSPResponse = nullptr,
133     /*optional in*/ const SECItem* sctsFromTLS = nullptr,
134     /*optional in*/ const NeckoOriginAttributes& originAttributes =
135                       NeckoOriginAttributes(),
136    /*optional out*/ SECOidTag* evOidPolicy = nullptr,
137    /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
138    /*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
139    /*optional out*/ SHA1ModeResult* sha1ModeResult = nullptr,
140    /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
141    /*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr);
142 
143   mozilla::pkix::Result VerifySSLServerCert(
144                     const UniqueCERTCertificate& peerCert,
145        /*optional*/ const SECItem* stapledOCSPResponse,
146        /*optional*/ const SECItem* sctsFromTLS,
147                     mozilla::pkix::Time time,
148        /*optional*/ void* pinarg,
149                     const char* hostname,
150             /*out*/ UniqueCERTCertList& builtChain,
151        /*optional*/ bool saveIntermediatesInPermanentDatabase = false,
152        /*optional*/ Flags flags = 0,
153        /*optional*/ const NeckoOriginAttributes& originAttributes =
154                       NeckoOriginAttributes(),
155    /*optional out*/ SECOidTag* evOidPolicy = nullptr,
156    /*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
157    /*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
158    /*optional out*/ SHA1ModeResult* sha1ModeResult = nullptr,
159    /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr,
160    /*optional out*/ CertificateTransparencyInfo* ctInfo = nullptr);
161 
162   enum PinningMode {
163     pinningDisabled = 0,
164     pinningAllowUserCAMITM = 1,
165     pinningStrict = 2,
166     pinningEnforceTestMode = 3
167   };
168 
169   enum class SHA1Mode {
170     Allowed = 0,
171     Forbidden = 1,
172     // There used to be a policy that only allowed SHA1 for certificates issued
173     // before 2016. This is no longer available. If a user has selected this
174     // policy in about:config, it now maps to Forbidden.
175     UsedToBeBefore2016ButNowIsForbidden = 2,
176     ImportedRoot = 3,
177     ImportedRootOrBefore2016 = 4,
178   };
179 
180   enum OcspDownloadConfig {
181     ocspOff = 0,
182     ocspOn = 1,
183     ocspEVOnly = 2
184   };
185   enum OcspStrictConfig { ocspRelaxed = 0, ocspStrict };
186   enum OcspGetConfig { ocspGetDisabled = 0, ocspGetEnabled = 1 };
187 
188   enum class CertificateTransparencyMode {
189     Disabled = 0,
190     TelemetryOnly = 1,
191   };
192 
193   CertVerifier(OcspDownloadConfig odc, OcspStrictConfig osc,
194                OcspGetConfig ogc, uint32_t certShortLifetimeInDays,
195                PinningMode pinningMode, SHA1Mode sha1Mode,
196                BRNameMatchingPolicy::Mode nameMatchingMode,
197                NetscapeStepUpPolicy netscapeStepUpPolicy,
198                CertificateTransparencyMode ctMode);
199   ~CertVerifier();
200 
ClearOCSPCache()201   void ClearOCSPCache() { mOCSPCache.Clear(); }
202 
203   const OcspDownloadConfig mOCSPDownloadConfig;
204   const bool mOCSPStrict;
205   const bool mOCSPGETEnabled;
206   const uint32_t mCertShortLifetimeInDays;
207   const PinningMode mPinningMode;
208   const SHA1Mode mSHA1Mode;
209   const BRNameMatchingPolicy::Mode mNameMatchingMode;
210   const NetscapeStepUpPolicy mNetscapeStepUpPolicy;
211   const CertificateTransparencyMode mCTMode;
212 
213 private:
214   OCSPCache mOCSPCache;
215 
216   // We only have a forward declaration of MultiLogCTVerifier (see above),
217   // so we keep a pointer to it and allocate dynamically.
218   UniquePtr<mozilla::ct::MultiLogCTVerifier> mCTVerifier;
219 
220   void LoadKnownCTLogs();
221   mozilla::pkix::Result VerifySignedCertificateTimestamps(
222                      NSSCertDBTrustDomain& trustDomain,
223                      const UniqueCERTCertList& builtChain,
224                      mozilla::pkix::Input sctsFromTLS,
225                      mozilla::pkix::Time time,
226     /*optional out*/ CertificateTransparencyInfo* ctInfo);
227 
228   // Returns true if the configured SHA1 mode is more restrictive than the given
229   // mode. SHA1Mode::Forbidden is more restrictive than any other mode except
230   // Forbidden. Next is ImportedRoot, then ImportedRootOrBefore2016, then
231   // Allowed. (A mode is never more restrictive than itself.)
232   bool SHA1ModeMoreRestrictiveThanGivenMode(SHA1Mode mode);
233 };
234 
235 mozilla::pkix::Result IsCertBuiltInRoot(CERTCertificate* cert, bool& result);
236 mozilla::pkix::Result CertListContainsExpectedKeys(
237   const CERTCertList* certList, const char* hostname, mozilla::pkix::Time time,
238   CertVerifier::PinningMode pinningMode);
239 
240 } } // namespace mozilla::psm
241 
242 #endif // CertVerifier_h
243