| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| /* This code is made available to you under your choice of the following sets |
| * of licensing terms: |
| */ |
| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| */ |
| /* Copyright 2013 Mozilla Contributors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef mozilla_pkix_pkixtypes_h |
| #define mozilla_pkix_pkixtypes_h |
| |
| #include <memory> |
| |
| #include "mozpkix/Input.h" |
| #include "mozpkix/Time.h" |
| #include "stdint.h" |
| |
| namespace mozilla { |
| namespace pkix { |
| |
| enum class DigestAlgorithm { |
| sha512 = 1, |
| sha384 = 2, |
| sha256 = 3, |
| sha1 = 4, |
| }; |
| |
| enum class NamedCurve { |
| // secp521r1 (OID 1.3.132.0.35, RFC 5480) |
| secp521r1 = 1, |
| |
| // secp384r1 (OID 1.3.132.0.34, RFC 5480) |
| secp384r1 = 2, |
| |
| // secp256r1 (OID 1.2.840.10045.3.1.7, RFC 5480) |
| secp256r1 = 3, |
| }; |
| |
| struct SignedDigest final { |
| Input digest; |
| DigestAlgorithm digestAlgorithm; |
| Input signature; |
| |
| void operator=(const SignedDigest&) = delete; |
| }; |
| |
| enum class EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 }; |
| |
| enum class KeyUsage : uint8_t { |
| digitalSignature = 0, |
| nonRepudiation = 1, |
| keyEncipherment = 2, |
| dataEncipherment = 3, |
| keyAgreement = 4, |
| keyCertSign = 5, |
| // cRLSign = 6, |
| // encipherOnly = 7, |
| // decipherOnly = 8, |
| noParticularKeyUsageRequired = 0xff, |
| }; |
| |
| enum class KeyPurposeId { |
| anyExtendedKeyUsage = 0, |
| id_kp_serverAuth = 1, // id-kp-serverAuth |
| id_kp_clientAuth = 2, // id-kp-clientAuth |
| id_kp_codeSigning = 3, // id-kp-codeSigning |
| id_kp_emailProtection = 4, // id-kp-emailProtection |
| id_kp_OCSPSigning = 9, // id-kp-OCSPSigning |
| }; |
| |
| struct CertPolicyId final { |
| uint16_t numBytes; |
| static const uint16_t MAX_BYTES = 24; |
| uint8_t bytes[MAX_BYTES]; |
| |
| bool IsAnyPolicy() const; |
| bool operator==(const CertPolicyId& other) const; |
| |
| static const CertPolicyId anyPolicy; |
| }; |
| |
| enum class TrustLevel { |
| TrustAnchor = 1, // certificate is a trusted root CA certificate or |
| // equivalent *for the given policy*. |
| ActivelyDistrusted = 2, // certificate is known to be bad |
| InheritsTrust = 3 // certificate must chain to a trust anchor |
| }; |
| |
| // Extensions extracted during the verification flow. |
| // See TrustDomain::NoteAuxiliaryExtension. |
| enum class AuxiliaryExtension { |
| // Certificate Transparency data, specifically Signed Certificate |
| // Timestamps (SCTs). See RFC 6962. |
| |
| // SCT list embedded in the end entity certificate. Called by BuildCertChain |
| // after the certificate containing the SCTs has passed the revocation checks. |
| EmbeddedSCTList = 1, |
| // SCT list from OCSP response. Called by VerifyEncodedOCSPResponse |
| // when its result is a success and the SCT list is present. |
| SCTListFromOCSPResponse = 2 |
| }; |
| |
| // CertID references the information needed to do revocation checking for the |
| // certificate issued by the given issuer with the given serial number. |
| // |
| // issuer must be the DER-encoded issuer field from the certificate for which |
| // revocation checking is being done, **NOT** the subject field of the issuer |
| // certificate. (Those two fields must be equal to each other, but they may not |
| // be encoded exactly the same, and the encoding matters for OCSP.) |
| // issuerSubjectPublicKeyInfo is the entire DER-encoded subjectPublicKeyInfo |
| // field from the issuer's certificate. serialNumber is the entire DER-encoded |
| // serial number from the subject certificate (the certificate for which we are |
| // checking the revocation status). |
| struct CertID final { |
| public: |
| CertID(Input aIssuer, Input aIssuerSubjectPublicKeyInfo, Input aSerialNumber) |
| : issuer(aIssuer), |
| issuerSubjectPublicKeyInfo(aIssuerSubjectPublicKeyInfo), |
| serialNumber(aSerialNumber) {} |
| const Input issuer; |
| const Input issuerSubjectPublicKeyInfo; |
| const Input serialNumber; |
| |
| void operator=(const CertID&) = delete; |
| }; |
| typedef std::unique_ptr<CertID> ScopedCertID; |
| |
| class DERArray { |
| public: |
| // Returns the number of DER-encoded items in the array. |
| virtual size_t GetLength() const = 0; |
| |
| // Returns a weak (non-owning) pointer the ith DER-encoded item in the array |
| // (0-indexed). The result is guaranteed to be non-null if i < GetLength(), |
| // and the result is guaranteed to be nullptr if i >= GetLength(). |
| virtual const Input* GetDER(size_t i) const = 0; |
| |
| protected: |
| DERArray() {} |
| virtual ~DERArray() {} |
| }; |
| |
| // Applications control the behavior of path building and verification by |
| // implementing the TrustDomain interface. The TrustDomain is used for all |
| // cryptography and for determining which certificates are trusted or |
| // distrusted. |
| class TrustDomain { |
| public: |
| virtual ~TrustDomain() {} |
| |
| // Determine the level of trust in the given certificate for the given role. |
| // This will be called for every certificate encountered during path |
| // building. |
| // |
| // When policy.IsAnyPolicy(), then no policy-related checking should be done. |
| // When !policy.IsAnyPolicy(), then GetCertTrust MUST NOT return with |
| // trustLevel == TrustAnchor unless the given cert is considered a trust |
| // anchor *for that policy*. In particular, if the user has marked an |
| // intermediate certificate as trusted, but that intermediate isn't in the |
| // list of EV roots, then GetCertTrust must result in |
| // trustLevel == InheritsTrust instead of trustLevel == TrustAnchor |
| // (assuming the candidate cert is not actively distrusted). |
| virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA, |
| const CertPolicyId& policy, |
| Input candidateCertDER, |
| /*out*/ TrustLevel& trustLevel) = 0; |
| |
| class IssuerChecker { |
| public: |
| // potentialIssuerDER is the complete DER encoding of the certificate to |
| // be checked as a potential issuer. |
| // |
| // If additionalNameConstraints is not nullptr then it must point to an |
| // encoded NameConstraints extension value; in that case, those name |
| // constraints will be checked in addition to any any name constraints |
| // contained in potentialIssuerDER. |
| virtual Result Check(Input potentialIssuerDER, |
| /*optional*/ const Input* additionalNameConstraints, |
| /*out*/ bool& keepGoing) = 0; |
| |
| protected: |
| IssuerChecker(); |
| virtual ~IssuerChecker(); |
| |
| IssuerChecker(const IssuerChecker&) = delete; |
| void operator=(const IssuerChecker&) = delete; |
| }; |
| |
| // Search for a CA certificate with the given name. The implementation must |
| // call checker.Check with the DER encoding of the potential issuer |
| // certificate. The implementation must follow these rules: |
| // |
| // * The implementation must be reentrant and must limit the amount of stack |
| // space it uses; see the note on reentrancy and stack usage below. |
| // * When checker.Check does not return Success then immediately return its |
| // return value. |
| // * When checker.Check returns Success and sets keepGoing = false, then |
| // immediately return Success. |
| // * When checker.Check returns Success and sets keepGoing = true, then |
| // call checker.Check again with a different potential issuer certificate, |
| // if any more are available. |
| // * When no more potential issuer certificates are available, return |
| // Success. |
| // * Don't call checker.Check with the same potential issuer certificate more |
| // than once in a given call of FindIssuer. |
| // * The given time parameter may be used to filter out certificates that are |
| // not valid at the given time, or it may be ignored. |
| // |
| // Note on reentrancy and stack usage: checker.Check will attempt to |
| // recursively build a certificate path from the potential issuer it is given |
| // to a trusted root, as determined by this TrustDomain. That means that |
| // checker.Check may call any/all of the methods on this TrustDomain. In |
| // particular, there will be call stacks that look like this: |
| // |
| // BuildCertChain |
| // [...] |
| // TrustDomain::FindIssuer |
| // [...] |
| // IssuerChecker::Check |
| // [...] |
| // TrustDomain::FindIssuer |
| // [...] |
| // IssuerChecker::Check |
| // [...] |
| // |
| // checker.Check is responsible for limiting the recursion to a reasonable |
| // limit. |
| // |
| // checker.Check will verify that the subject's issuer field matches the |
| // potential issuer's subject field. It will also check that the potential |
| // issuer is valid at the given time. However, if the FindIssuer |
| // implementation has an efficient way of filtering potential issuers by name |
| // and/or validity period itself, then it is probably better for performance |
| // for it to do so. |
| virtual Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, |
| Time time) = 0; |
| |
| // Called as soon as we think we have a valid chain but before revocation |
| // checks are done. This function can be used to compute additional checks, |
| // especially checks that require the entire certificate chain. This callback |
| // can also be used to save a copy of the built certificate chain for later |
| // use. |
| // |
| // This function may be called multiple times, regardless of whether it |
| // returns success or failure. It is guaranteed that BuildCertChain will not |
| // return Success unless the last call to IsChainValid returns Success. |
| // Further, |
| // it is guaranteed that when BuildCertChain returns Success the last chain |
| // passed to IsChainValid is the valid chain that should be used for further |
| // operations that require the whole chain. |
| // |
| // Keep in mind, in particular, that if the application saves a copy of the |
| // certificate chain the last invocation of IsChainValid during a validation, |
| // it is still possible for BuildCertChain to fail, in which case the |
| // application must not assume anything about the validity of the last |
| // certificate chain passed to IsChainValid; especially, it would be very |
| // wrong to assume that the certificate chain is valid. |
| // |
| // certChain.GetDER(0) is the trust anchor. |
| virtual Result IsChainValid(const DERArray& certChain, Time time, |
| const CertPolicyId& requiredPolicy) = 0; |
| |
| virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA, |
| const CertID& certID, Time time, |
| Duration validityDuration, |
| /*optional*/ const Input* stapledOCSPresponse, |
| /*optional*/ const Input* aiaExtension, |
| /*optional*/ const Input* sctExtension) = 0; |
| |
| // Check that the given digest algorithm is acceptable for use in signatures. |
| // |
| // Return Success if the algorithm is acceptable, |
| // Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED if the algorithm is not |
| // acceptable, or another error code if another error occurred. |
| virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg, |
| EndEntityOrCA endEntityOrCA, |
| Time notBefore) = 0; |
| |
| // Check that the RSA public key size is acceptable. |
| // |
| // Return Success if the key size is acceptable, |
| // Result::ERROR_INADEQUATE_KEY_SIZE if the key size is not acceptable, |
| // or another error code if another error occurred. |
| virtual Result CheckRSAPublicKeyModulusSizeInBits( |
| EndEntityOrCA endEntityOrCA, unsigned int modulusSizeInBits) = 0; |
| |
| // Verify the given RSA PKCS#1.5 signature on the given digest using the |
| // given RSA public key. |
| // |
| // CheckRSAPublicKeyModulusSizeInBits will be called before calling this |
| // function, so it is not necessary to repeat those checks here. However, |
| // VerifyRSAPKCS1SignedDigest *is* responsible for doing the mathematical |
| // verification of the public key validity as specified in NIST SP 800-56A. |
| virtual Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest, |
| Input subjectPublicKeyInfo) = 0; |
| |
| // Check that the given named ECC curve is acceptable for ECDSA signatures. |
| // |
| // Return Success if the curve is acceptable, |
| // Result::ERROR_UNSUPPORTED_ELLIPTIC_CURVE if the curve is not acceptable, |
| // or another error code if another error occurred. |
| virtual Result CheckECDSACurveIsAcceptable(EndEntityOrCA endEntityOrCA, |
| NamedCurve curve) = 0; |
| |
| // Verify the given ECDSA signature on the given digest using the given ECC |
| // public key. |
| // |
| // CheckECDSACurveIsAcceptable will be called before calling this function, |
| // so it is not necessary to repeat that check here. However, |
| // VerifyECDSASignedDigest *is* responsible for doing the mathematical |
| // verification of the public key validity as specified in NIST SP 800-56A. |
| virtual Result VerifyECDSASignedDigest(const SignedDigest& signedDigest, |
| Input subjectPublicKeyInfo) = 0; |
| |
| // Check that the validity duration is acceptable. |
| // |
| // Return Success if the validity duration is acceptable, |
| // Result::ERROR_VALIDITY_TOO_LONG if the validity duration is not acceptable, |
| // or another error code if another error occurred. |
| virtual Result CheckValidityIsAcceptable(Time notBefore, Time notAfter, |
| EndEntityOrCA endEntityOrCA, |
| KeyPurposeId keyPurpose) = 0; |
| |
| // For compatibility, a CA certificate with an extended key usage that |
| // contains the id-Netscape-stepUp OID but does not contain the |
| // id-kp-serverAuth OID may be considered valid for issuing server auth |
| // certificates. This function allows TrustDomain implementations to control |
| // this setting based on the start of the validity period of the certificate |
| // in question. |
| virtual Result NetscapeStepUpMatchesServerAuth(Time notBefore, |
| /*out*/ bool& matches) = 0; |
| |
| // Some certificate or OCSP response extensions do not directly participate |
| // in the verification flow, but might still be of interest to the clients |
| // (notably Certificate Transparency data, RFC 6962). Such extensions are |
| // extracted and passed to this function for further processing. |
| virtual void NoteAuxiliaryExtension(AuxiliaryExtension extension, |
| Input extensionData) = 0; |
| |
| // Compute a digest of the data in item using the given digest algorithm. |
| // |
| // item contains the data to hash. |
| // digestBuf points to a buffer to where the digest will be written. |
| // digestBufLen will be the size of the digest output (20 for SHA-1, |
| // 32 for SHA-256, etc.). |
| // |
| // TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our |
| // other, extensive, memory safety efforts in mozilla::pkix, and we should |
| // find a way to provide a more-obviously-safe interface. |
| virtual Result DigestBuf(Input item, DigestAlgorithm digestAlg, |
| /*out*/ uint8_t* digestBuf, size_t digestBufLen) = 0; |
| |
| protected: |
| TrustDomain() {} |
| |
| TrustDomain(const TrustDomain&) = delete; |
| void operator=(const TrustDomain&) = delete; |
| }; |
| |
| enum class FallBackToSearchWithinSubject { No = 0, Yes = 1 }; |
| |
| // Applications control the behavior of matching presented name information from |
| // a certificate against a reference hostname by implementing the |
| // NameMatchingPolicy interface. Used in concert with CheckCertHostname. |
| class NameMatchingPolicy { |
| public: |
| virtual ~NameMatchingPolicy() {} |
| |
| // Given that the certificate in question has a notBefore field with the given |
| // value, should name matching fall back to searching within the subject |
| // common name field? |
| virtual Result FallBackToCommonName( |
| Time notBefore, |
| /*out*/ FallBackToSearchWithinSubject& fallBackToCommonName) = 0; |
| |
| protected: |
| NameMatchingPolicy() {} |
| |
| NameMatchingPolicy(const NameMatchingPolicy&) = delete; |
| void operator=(const NameMatchingPolicy&) = delete; |
| }; |
| } |
| } // namespace mozilla::pkix |
| |
| #endif // mozilla_pkix_pkixtypes_h |