Line data Source code
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 code is made available to you under your choice of the following sets
4 : * of licensing terms:
5 : */
6 : /* This Source Code Form is subject to the terms of the Mozilla Public
7 : * License, v. 2.0. If a copy of the MPL was not distributed with this
8 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 : */
10 : /* Copyright 2013 Mozilla Contributors
11 : *
12 : * Licensed under the Apache License, Version 2.0 (the "License");
13 : * you may not use this file except in compliance with the License.
14 : * You may obtain a copy of the License at
15 : *
16 : * http://www.apache.org/licenses/LICENSE-2.0
17 : *
18 : * Unless required by applicable law or agreed to in writing, software
19 : * distributed under the License is distributed on an "AS IS" BASIS,
20 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 : * See the License for the specific language governing permissions and
22 : * limitations under the License.
23 : */
24 :
25 : #ifndef mozilla_pkix_pkixtypes_h
26 : #define mozilla_pkix_pkixtypes_h
27 :
28 : #include "pkix/Input.h"
29 : #include "pkix/Time.h"
30 : #include "stdint.h"
31 :
32 : namespace mozilla { namespace pkix {
33 :
34 : enum class DigestAlgorithm
35 : {
36 : sha512 = 1,
37 : sha384 = 2,
38 : sha256 = 3,
39 : sha1 = 4,
40 : };
41 :
42 : enum class NamedCurve
43 : {
44 : // secp521r1 (OID 1.3.132.0.35, RFC 5480)
45 : secp521r1 = 1,
46 :
47 : // secp384r1 (OID 1.3.132.0.34, RFC 5480)
48 : secp384r1 = 2,
49 :
50 : // secp256r1 (OID 1.2.840.10045.3.1.7, RFC 5480)
51 : secp256r1 = 3,
52 : };
53 :
54 0 : struct SignedDigest final
55 : {
56 : Input digest;
57 : DigestAlgorithm digestAlgorithm;
58 : Input signature;
59 :
60 : void operator=(const SignedDigest&) = delete;
61 : };
62 :
63 : enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
64 :
65 : enum class KeyUsage : uint8_t
66 : {
67 : digitalSignature = 0,
68 : nonRepudiation = 1,
69 : keyEncipherment = 2,
70 : dataEncipherment = 3,
71 : keyAgreement = 4,
72 : keyCertSign = 5,
73 : // cRLSign = 6,
74 : // encipherOnly = 7,
75 : // decipherOnly = 8,
76 : noParticularKeyUsageRequired = 0xff,
77 : };
78 :
79 : enum class KeyPurposeId
80 : {
81 : anyExtendedKeyUsage = 0,
82 : id_kp_serverAuth = 1, // id-kp-serverAuth
83 : id_kp_clientAuth = 2, // id-kp-clientAuth
84 : id_kp_codeSigning = 3, // id-kp-codeSigning
85 : id_kp_emailProtection = 4, // id-kp-emailProtection
86 : id_kp_OCSPSigning = 9, // id-kp-OCSPSigning
87 : };
88 :
89 : struct CertPolicyId final
90 : {
91 : uint16_t numBytes;
92 : static const uint16_t MAX_BYTES = 24;
93 : uint8_t bytes[MAX_BYTES];
94 :
95 : bool IsAnyPolicy() const;
96 : bool operator==(const CertPolicyId& other) const;
97 :
98 : static const CertPolicyId anyPolicy;
99 : };
100 :
101 : enum class TrustLevel
102 : {
103 : TrustAnchor = 1, // certificate is a trusted root CA certificate or
104 : // equivalent *for the given policy*.
105 : ActivelyDistrusted = 2, // certificate is known to be bad
106 : InheritsTrust = 3 // certificate must chain to a trust anchor
107 : };
108 :
109 : // Extensions extracted during the verification flow.
110 : // See TrustDomain::NoteAuxiliaryExtension.
111 : enum class AuxiliaryExtension
112 : {
113 : // Certificate Transparency data, specifically Signed Certificate
114 : // Timestamps (SCTs). See RFC 6962.
115 :
116 : // SCT list embedded in the end entity certificate. Called by BuildCertChain
117 : // after the certificate containing the SCTs has passed the revocation checks.
118 : EmbeddedSCTList = 1,
119 : // SCT list from OCSP response. Called by VerifyEncodedOCSPResponse
120 : // when its result is a success and the SCT list is present.
121 : SCTListFromOCSPResponse = 2
122 : };
123 :
124 : // CertID references the information needed to do revocation checking for the
125 : // certificate issued by the given issuer with the given serial number.
126 : //
127 : // issuer must be the DER-encoded issuer field from the certificate for which
128 : // revocation checking is being done, **NOT** the subject field of the issuer
129 : // certificate. (Those two fields must be equal to each other, but they may not
130 : // be encoded exactly the same, and the encoding matters for OCSP.)
131 : // issuerSubjectPublicKeyInfo is the entire DER-encoded subjectPublicKeyInfo
132 : // field from the issuer's certificate. serialNumber is the entire DER-encoded
133 : // serial number from the subject certificate (the certificate for which we are
134 : // checking the revocation status).
135 : struct CertID final
136 : {
137 : public:
138 0 : CertID(Input issuer, Input issuerSubjectPublicKeyInfo, Input serialNumber)
139 0 : : issuer(issuer)
140 : , issuerSubjectPublicKeyInfo(issuerSubjectPublicKeyInfo)
141 0 : , serialNumber(serialNumber)
142 : {
143 0 : }
144 : const Input issuer;
145 : const Input issuerSubjectPublicKeyInfo;
146 : const Input serialNumber;
147 :
148 : void operator=(const CertID&) = delete;
149 : };
150 :
151 : class DERArray
152 : {
153 : public:
154 : // Returns the number of DER-encoded items in the array.
155 : virtual size_t GetLength() const = 0;
156 :
157 : // Returns a weak (non-owning) pointer the ith DER-encoded item in the array
158 : // (0-indexed). The result is guaranteed to be non-null if i < GetLength(),
159 : // and the result is guaranteed to be nullptr if i >= GetLength().
160 : virtual const Input* GetDER(size_t i) const = 0;
161 : protected:
162 0 : DERArray() { }
163 0 : virtual ~DERArray() { }
164 : };
165 :
166 : // Applications control the behavior of path building and verification by
167 : // implementing the TrustDomain interface. The TrustDomain is used for all
168 : // cryptography and for determining which certificates are trusted or
169 : // distrusted.
170 : class TrustDomain
171 : {
172 : public:
173 15 : virtual ~TrustDomain() { }
174 :
175 : // Determine the level of trust in the given certificate for the given role.
176 : // This will be called for every certificate encountered during path
177 : // building.
178 : //
179 : // When policy.IsAnyPolicy(), then no policy-related checking should be done.
180 : // When !policy.IsAnyPolicy(), then GetCertTrust MUST NOT return with
181 : // trustLevel == TrustAnchor unless the given cert is considered a trust
182 : // anchor *for that policy*. In particular, if the user has marked an
183 : // intermediate certificate as trusted, but that intermediate isn't in the
184 : // list of EV roots, then GetCertTrust must result in
185 : // trustLevel == InheritsTrust instead of trustLevel == TrustAnchor
186 : // (assuming the candidate cert is not actively distrusted).
187 : virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
188 : const CertPolicyId& policy,
189 : Input candidateCertDER,
190 : /*out*/ TrustLevel& trustLevel) = 0;
191 :
192 : class IssuerChecker
193 : {
194 : public:
195 : // potentialIssuerDER is the complete DER encoding of the certificate to
196 : // be checked as a potential issuer.
197 : //
198 : // If additionalNameConstraints is not nullptr then it must point to an
199 : // encoded NameConstraints extension value; in that case, those name
200 : // constraints will be checked in addition to any any name constraints
201 : // contained in potentialIssuerDER.
202 : virtual Result Check(Input potentialIssuerDER,
203 : /*optional*/ const Input* additionalNameConstraints,
204 : /*out*/ bool& keepGoing) = 0;
205 : protected:
206 : IssuerChecker();
207 : virtual ~IssuerChecker();
208 :
209 : IssuerChecker(const IssuerChecker&) = delete;
210 : void operator=(const IssuerChecker&) = delete;
211 : };
212 :
213 : // Search for a CA certificate with the given name. The implementation must
214 : // call checker.Check with the DER encoding of the potential issuer
215 : // certificate. The implementation must follow these rules:
216 : //
217 : // * The implementation must be reentrant and must limit the amount of stack
218 : // space it uses; see the note on reentrancy and stack usage below.
219 : // * When checker.Check does not return Success then immediately return its
220 : // return value.
221 : // * When checker.Check returns Success and sets keepGoing = false, then
222 : // immediately return Success.
223 : // * When checker.Check returns Success and sets keepGoing = true, then
224 : // call checker.Check again with a different potential issuer certificate,
225 : // if any more are available.
226 : // * When no more potential issuer certificates are available, return
227 : // Success.
228 : // * Don't call checker.Check with the same potential issuer certificate more
229 : // than once in a given call of FindIssuer.
230 : // * The given time parameter may be used to filter out certificates that are
231 : // not valid at the given time, or it may be ignored.
232 : //
233 : // Note on reentrancy and stack usage: checker.Check will attempt to
234 : // recursively build a certificate path from the potential issuer it is given
235 : // to a trusted root, as determined by this TrustDomain. That means that
236 : // checker.Check may call any/all of the methods on this TrustDomain. In
237 : // particular, there will be call stacks that look like this:
238 : //
239 : // BuildCertChain
240 : // [...]
241 : // TrustDomain::FindIssuer
242 : // [...]
243 : // IssuerChecker::Check
244 : // [...]
245 : // TrustDomain::FindIssuer
246 : // [...]
247 : // IssuerChecker::Check
248 : // [...]
249 : //
250 : // checker.Check is responsible for limiting the recursion to a reasonable
251 : // limit.
252 : //
253 : // checker.Check will verify that the subject's issuer field matches the
254 : // potential issuer's subject field. It will also check that the potential
255 : // issuer is valid at the given time. However, if the FindIssuer
256 : // implementation has an efficient way of filtering potential issuers by name
257 : // and/or validity period itself, then it is probably better for performance
258 : // for it to do so.
259 : virtual Result FindIssuer(Input encodedIssuerName,
260 : IssuerChecker& checker, Time time) = 0;
261 :
262 : // Called as soon as we think we have a valid chain but before revocation
263 : // checks are done. This function can be used to compute additional checks,
264 : // especially checks that require the entire certificate chain. This callback
265 : // can also be used to save a copy of the built certificate chain for later
266 : // use.
267 : //
268 : // This function may be called multiple times, regardless of whether it
269 : // returns success or failure. It is guaranteed that BuildCertChain will not
270 : // return Success unless the last call to IsChainValid returns Success. Further,
271 : // it is guaranteed that when BuildCertChain returns Success the last chain
272 : // passed to IsChainValid is the valid chain that should be used for further
273 : // operations that require the whole chain.
274 : //
275 : // Keep in mind, in particular, that if the application saves a copy of the
276 : // certificate chain the last invocation of IsChainValid during a validation,
277 : // it is still possible for BuildCertChain to fail, in which case the
278 : // application must not assume anything about the validity of the last
279 : // certificate chain passed to IsChainValid; especially, it would be very
280 : // wrong to assume that the certificate chain is valid.
281 : //
282 : // certChain.GetDER(0) is the trust anchor.
283 : virtual Result IsChainValid(const DERArray& certChain, Time time,
284 : const CertPolicyId& requiredPolicy) = 0;
285 :
286 : virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA,
287 : const CertID& certID, Time time,
288 : Duration validityDuration,
289 : /*optional*/ const Input* stapledOCSPresponse,
290 : /*optional*/ const Input* aiaExtension) = 0;
291 :
292 : // Check that the given digest algorithm is acceptable for use in signatures.
293 : //
294 : // Return Success if the algorithm is acceptable,
295 : // Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED if the algorithm is not
296 : // acceptable, or another error code if another error occurred.
297 : virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
298 : EndEntityOrCA endEntityOrCA,
299 : Time notBefore) = 0;
300 :
301 : // Check that the RSA public key size is acceptable.
302 : //
303 : // Return Success if the key size is acceptable,
304 : // Result::ERROR_INADEQUATE_KEY_SIZE if the key size is not acceptable,
305 : // or another error code if another error occurred.
306 : virtual Result CheckRSAPublicKeyModulusSizeInBits(
307 : EndEntityOrCA endEntityOrCA,
308 : unsigned int modulusSizeInBits) = 0;
309 :
310 : // Verify the given RSA PKCS#1.5 signature on the given digest using the
311 : // given RSA public key.
312 : //
313 : // CheckRSAPublicKeyModulusSizeInBits will be called before calling this
314 : // function, so it is not necessary to repeat those checks here. However,
315 : // VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical
316 : // verification of the public key validity as specified in NIST SP 800-56A.
317 : virtual Result VerifyRSAPKCS1SignedDigest(
318 : const SignedDigest& signedDigest,
319 : Input subjectPublicKeyInfo) = 0;
320 :
321 : // Check that the given named ECC curve is acceptable for ECDSA signatures.
322 : //
323 : // Return Success if the curve is acceptable,
324 : // Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE if the curve is not acceptable,
325 : // or another error code if another error occurred.
326 : virtual Result CheckECDSACurveIsAcceptable(EndEntityOrCA endEntityOrCA,
327 : NamedCurve curve) = 0;
328 :
329 : // Verify the given ECDSA signature on the given digest using the given ECC
330 : // public key.
331 : //
332 : // CheckECDSACurveIsAcceptable will be called before calling this function,
333 : // so it is not necessary to repeat that check here. However,
334 : // VerifyECDSASignedDigest *is* responsible for doing the mathematical
335 : // verification of the public key validity as specified in NIST SP 800-56A.
336 : virtual Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
337 : Input subjectPublicKeyInfo) = 0;
338 :
339 : // Check that the validity duration is acceptable.
340 : //
341 : // Return Success if the validity duration is acceptable,
342 : // Result::ERROR_VALIDITY_TOO_LONG if the validity duration is not acceptable,
343 : // or another error code if another error occurred.
344 : virtual Result CheckValidityIsAcceptable(Time notBefore, Time notAfter,
345 : EndEntityOrCA endEntityOrCA,
346 : KeyPurposeId keyPurpose) = 0;
347 :
348 : // For compatibility, a CA certificate with an extended key usage that
349 : // contains the id-Netscape-stepUp OID but does not contain the
350 : // id-kp-serverAuth OID may be considered valid for issuing server auth
351 : // certificates. This function allows TrustDomain implementations to control
352 : // this setting based on the start of the validity period of the certificate
353 : // in question.
354 : virtual Result NetscapeStepUpMatchesServerAuth(Time notBefore,
355 : /*out*/ bool& matches) = 0;
356 :
357 : // Some certificate or OCSP response extensions do not directly participate
358 : // in the verification flow, but might still be of interest to the clients
359 : // (notably Certificate Transparency data, RFC 6962). Such extensions are
360 : // extracted and passed to this function for further processing.
361 : virtual void NoteAuxiliaryExtension(AuxiliaryExtension extension,
362 : Input extensionData) = 0;
363 :
364 : // Compute a digest of the data in item using the given digest algorithm.
365 : //
366 : // item contains the data to hash.
367 : // digestBuf points to a buffer to where the digest will be written.
368 : // digestBufLen will be the size of the digest output (20 for SHA-1,
369 : // 32 for SHA-256, etc.).
370 : //
371 : // TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
372 : // other, extensive, memory safety efforts in mozilla::pkix, and we should
373 : // find a way to provide a more-obviously-safe interface.
374 : virtual Result DigestBuf(Input item,
375 : DigestAlgorithm digestAlg,
376 : /*out*/ uint8_t* digestBuf,
377 : size_t digestBufLen) = 0;
378 : protected:
379 15 : TrustDomain() { }
380 :
381 : TrustDomain(const TrustDomain&) = delete;
382 : void operator=(const TrustDomain&) = delete;
383 : };
384 :
385 : enum class FallBackToSearchWithinSubject { No = 0, Yes = 1 };
386 :
387 : // Applications control the behavior of matching presented name information from
388 : // a certificate against a reference hostname by implementing the
389 : // NameMatchingPolicy interface. Used in concert with CheckCertHostname.
390 : class NameMatchingPolicy
391 : {
392 : public:
393 0 : virtual ~NameMatchingPolicy() { }
394 :
395 : // Given that the certificate in question has a notBefore field with the given
396 : // value, should name matching fall back to searching within the subject
397 : // common name field?
398 : virtual Result FallBackToCommonName(
399 : Time notBefore,
400 : /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0;
401 :
402 : protected:
403 0 : NameMatchingPolicy() { }
404 :
405 : NameMatchingPolicy(const NameMatchingPolicy&) = delete;
406 : void operator=(const NameMatchingPolicy&) = delete;
407 : };
408 :
409 : } } // namespace mozilla::pkix
410 :
411 : #endif // mozilla_pkix_pkixtypes_h
|