| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef BSSL_PKI_CRL_H_ |
| #define BSSL_PKI_CRL_H_ |
| |
| #include <optional> |
| |
| #include <openssl/base.h> |
| |
| #include "general_names.h" |
| #include "input.h" |
| #include "parse_values.h" |
| #include "parsed_certificate.h" |
| |
| namespace bssl { |
| |
| struct ParsedCrlTbsCertList; |
| struct ParsedDistributionPoint; |
| |
| // TODO(https://crbug.com/749276): This is the same enum with the same meaning |
| // as OCSPRevocationStatus, maybe they should be merged? |
| enum class CRLRevocationStatus { |
| GOOD = 0, |
| REVOKED = 1, |
| UNKNOWN = 2, |
| MAX_VALUE = UNKNOWN |
| }; |
| |
| // Parses a DER-encoded CRL "CertificateList" as specified by RFC 5280 Section |
| // 5.1. Returns true on success and sets the results in the |out_*| parameters. |
| // The contents of the output data is not validated. |
| // |
| // Note that on success the out parameters alias data from the input |crl_tlv|. |
| // Hence the output values are only valid as long as |crl_tlv| remains valid. |
| // |
| // On failure the out parameters have an undefined state. Some of them may have |
| // been updated during parsing, whereas others may not have been changed. |
| // |
| // CertificateList ::= SEQUENCE { |
| // tbsCertList TBSCertList, |
| // signatureAlgorithm AlgorithmIdentifier, |
| // signatureValue BIT STRING } |
| [[nodiscard]] OPENSSL_EXPORT bool ParseCrlCertificateList( |
| der::Input crl_tlv, der::Input *out_tbs_cert_list_tlv, |
| der::Input *out_signature_algorithm_tlv, |
| der::BitString *out_signature_value); |
| |
| // Parses a DER-encoded "TBSCertList" as specified by RFC 5280 Section 5.1. |
| // Returns true on success and sets the results in |out|. |
| // |
| // Note that on success |out| aliases data from the input |tbs_tlv|. |
| // Hence the fields of the ParsedCrlTbsCertList are only valid as long as |
| // |tbs_tlv| remains valid. |
| // |
| // On failure |out| has an undefined state. Some of its fields may have been |
| // updated during parsing, whereas others may not have been changed. |
| // |
| // Refer to the per-field documentation of ParsedCrlTbsCertList for details on |
| // what validity checks parsing performs. |
| // |
| // TBSCertList ::= SEQUENCE { |
| // version Version OPTIONAL, |
| // -- if present, MUST be v2 |
| // signature AlgorithmIdentifier, |
| // issuer Name, |
| // thisUpdate Time, |
| // nextUpdate Time OPTIONAL, |
| // revokedCertificates SEQUENCE OF SEQUENCE { |
| // userCertificate CertificateSerialNumber, |
| // revocationDate Time, |
| // crlEntryExtensions Extensions OPTIONAL |
| // -- if present, version MUST be v2 |
| // } OPTIONAL, |
| // crlExtensions [0] EXPLICIT Extensions OPTIONAL |
| // -- if present, version MUST be v2 |
| // } |
| [[nodiscard]] OPENSSL_EXPORT bool ParseCrlTbsCertList( |
| der::Input tbs_tlv, ParsedCrlTbsCertList *out); |
| |
| // Represents a CRL "Version" from RFC 5280. TBSCertList reuses the same |
| // Version definition from TBSCertificate, however only v1(not present) and |
| // v2(1) are valid values, so a unique enum is used to avoid confusion. |
| enum class CrlVersion { |
| V1, |
| V2, |
| }; |
| |
| // Corresponds with "TBSCertList" from RFC 5280 Section 5.1: |
| struct OPENSSL_EXPORT ParsedCrlTbsCertList { |
| ParsedCrlTbsCertList(); |
| ~ParsedCrlTbsCertList(); |
| |
| // version Version OPTIONAL, |
| // -- if present, MUST be v2 |
| // |
| // Parsing guarantees that the version is one of v1 or v2. |
| CrlVersion version = CrlVersion::V1; |
| |
| // signature AlgorithmIdentifier, |
| // |
| // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| // guarantees are made regarding the value of this SEQUENCE. |
| // |
| // This can be further parsed using SignatureValue::Create(). |
| der::Input signature_algorithm_tlv; |
| |
| // issuer Name, |
| // |
| // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| // guarantees are made regarding the value of this SEQUENCE. |
| der::Input issuer_tlv; |
| |
| // thisUpdate Time, |
| // nextUpdate Time OPTIONAL, |
| // |
| // Parsing guarantees that thisUpdate and nextUpdate(if present) are valid |
| // DER-encoded dates, however it DOES NOT guarantee anything about their |
| // values. For instance notAfter could be before notBefore, or the dates |
| // could indicate an expired CRL. |
| der::GeneralizedTime this_update; |
| std::optional<der::GeneralizedTime> next_update; |
| |
| // revokedCertificates SEQUENCE OF SEQUENCE { |
| // userCertificate CertificateSerialNumber, |
| // revocationDate Time, |
| // crlEntryExtensions Extensions OPTIONAL |
| // -- if present, version MUST be v2 |
| // } OPTIONAL, |
| // |
| // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| // guarantees are made regarding the value of this SEQUENCE. |
| std::optional<der::Input> revoked_certificates_tlv; |
| |
| // crlExtensions [0] EXPLICIT Extensions OPTIONAL |
| // -- if present, version MUST be v2 |
| // |
| // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| // guarantees are made regarding the value of this SEQUENCE. (Note that the |
| // EXPLICIT outer tag is stripped.) |
| // |
| // Parsing guarantees that if extensions is present the version is v2. |
| std::optional<der::Input> crl_extensions_tlv; |
| }; |
| |
| // Represents the IssuingDistributionPoint certificate type constraints: |
| enum class ContainedCertsType { |
| // Neither onlyContainsUserCerts or onlyContainsCACerts was present. |
| ANY_CERTS, |
| // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, |
| USER_CERTS, |
| // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, |
| CA_CERTS, |
| }; |
| |
| // Parses a DER-encoded IssuingDistributionPoint extension value. |
| // Returns true on success and sets the results in the |out_*| parameters. |
| // |
| // If the IssuingDistributionPoint contains a distributionPoint fullName field, |
| // |out_distribution_point_names| will contain the parsed representation. |
| // If the distributionPoint type is nameRelativeToCRLIssuer, parsing will fail. |
| // |
| // |out_only_contains_cert_type| will contain the logical representation of the |
| // onlyContainsUserCerts and onlyContainsCACerts fields (or their absence). |
| // |
| // indirectCRL and onlyContainsAttributeCerts are not supported and parsing will |
| // fail if they are present. |
| // |
| // Note that on success |out_distribution_point_names| aliases data from the |
| // input |extension_value|. |
| // |
| // On failure the |out_*| parameters have undefined state. |
| // |
| // IssuingDistributionPoint ::= SEQUENCE { |
| // distributionPoint [0] DistributionPointName OPTIONAL, |
| // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, |
| // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, |
| // onlySomeReasons [3] ReasonFlags OPTIONAL, |
| // indirectCRL [4] BOOLEAN DEFAULT FALSE, |
| // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } |
| [[nodiscard]] OPENSSL_EXPORT bool ParseIssuingDistributionPoint( |
| der::Input extension_value, |
| std::unique_ptr<GeneralNames> *out_distribution_point_names, |
| ContainedCertsType *out_only_contains_cert_type); |
| |
| OPENSSL_EXPORT CRLRevocationStatus |
| GetCRLStatusForCert(der::Input cert_serial, CrlVersion crl_version, |
| const std::optional<der::Input> &revoked_certificates_tlv); |
| |
| // Checks the revocation status of the certificate |cert| by using the |
| // DER-encoded |raw_crl|. |cert| must already have passed certificate path |
| // validation. |
| // |
| // Returns GOOD if the CRL indicates the certificate is not revoked, |
| // REVOKED if it indicates it is revoked, or UNKNOWN for all other cases. |
| // |
| // * |raw_crl|: A DER encoded CRL CertificateList. |
| // * |valid_chain|: The validated certificate chain containing the target cert. |
| // * |target_cert_index|: The index into |valid_chain| of the certificate being |
| // checked for revocation. |
| // * |cert_dp|: The distribution point from the target certificate's CRL |
| // distribution points extension that |raw_crl| corresponds to. If |
| // |raw_crl| was not specified in a distribution point, the caller must |
| // synthesize a ParsedDistributionPoint object as specified by RFC 5280 |
| // 6.3.3. |
| // * |verify_time_epoch_seconds|: The time as the difference in seconds from |
| // the POSIX epoch to use when checking revocation status. |
| // * |max_age_seconds|: If present, the maximum age in seconds for a CRL, |
| // implemented as time since the |thisUpdate| field in the CRL |
| // TBSCertList. Responses older than |max_age_seconds| will be |
| // considered invalid. |
| [[nodiscard]] OPENSSL_EXPORT CRLRevocationStatus CheckCRL( |
| std::string_view raw_crl, const ParsedCertificateList &valid_chain, |
| size_t target_cert_index, const ParsedDistributionPoint &cert_dp, |
| int64_t verify_time_epoch_seconds, std::optional<int64_t> max_age_seconds); |
| |
| } // namespace bssl |
| |
| #endif // BSSL_PKI_CRL_H_ |