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