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