Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BSSL_PKI_CRL_H_ |
| 6 | #define BSSL_PKI_CRL_H_ |
| 7 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 8 | #include <optional> |
Bob Beck | 3cd30cc | 2023-11-22 16:59:00 -0700 | [diff] [blame] | 9 | |
| 10 | #include <openssl/base.h> |
| 11 | |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 12 | #include "general_names.h" |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 13 | #include "input.h" |
| 14 | #include "parse_values.h" |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 15 | #include "parsed_certificate.h" |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 16 | |
| 17 | namespace bssl { |
| 18 | |
| 19 | struct ParsedCrlTbsCertList; |
| 20 | struct ParsedDistributionPoint; |
| 21 | |
| 22 | // TODO(https://crbug.com/749276): This is the same enum with the same meaning |
| 23 | // as OCSPRevocationStatus, maybe they should be merged? |
| 24 | enum class CRLRevocationStatus { |
| 25 | GOOD = 0, |
| 26 | REVOKED = 1, |
| 27 | UNKNOWN = 2, |
| 28 | MAX_VALUE = UNKNOWN |
| 29 | }; |
| 30 | |
| 31 | // Parses a DER-encoded CRL "CertificateList" as specified by RFC 5280 Section |
| 32 | // 5.1. Returns true on success and sets the results in the |out_*| parameters. |
| 33 | // The contents of the output data is not validated. |
| 34 | // |
| 35 | // Note that on success the out parameters alias data from the input |crl_tlv|. |
| 36 | // Hence the output values are only valid as long as |crl_tlv| remains valid. |
| 37 | // |
| 38 | // On failure the out parameters have an undefined state. Some of them may have |
| 39 | // been updated during parsing, whereas others may not have been changed. |
| 40 | // |
| 41 | // CertificateList ::= SEQUENCE { |
| 42 | // tbsCertList TBSCertList, |
| 43 | // signatureAlgorithm AlgorithmIdentifier, |
| 44 | // signatureValue BIT STRING } |
| 45 | [[nodiscard]] OPENSSL_EXPORT bool ParseCrlCertificateList( |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 46 | der::Input crl_tlv, der::Input *out_tbs_cert_list_tlv, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 47 | der::Input *out_signature_algorithm_tlv, |
| 48 | der::BitString *out_signature_value); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 49 | |
| 50 | // Parses a DER-encoded "TBSCertList" as specified by RFC 5280 Section 5.1. |
| 51 | // Returns true on success and sets the results in |out|. |
| 52 | // |
| 53 | // Note that on success |out| aliases data from the input |tbs_tlv|. |
| 54 | // Hence the fields of the ParsedCrlTbsCertList are only valid as long as |
| 55 | // |tbs_tlv| remains valid. |
| 56 | // |
| 57 | // On failure |out| has an undefined state. Some of its fields may have been |
| 58 | // updated during parsing, whereas others may not have been changed. |
| 59 | // |
| 60 | // Refer to the per-field documentation of ParsedCrlTbsCertList for details on |
| 61 | // what validity checks parsing performs. |
| 62 | // |
| 63 | // TBSCertList ::= SEQUENCE { |
| 64 | // version Version OPTIONAL, |
| 65 | // -- if present, MUST be v2 |
| 66 | // signature AlgorithmIdentifier, |
| 67 | // issuer Name, |
| 68 | // thisUpdate Time, |
| 69 | // nextUpdate Time OPTIONAL, |
| 70 | // revokedCertificates SEQUENCE OF SEQUENCE { |
| 71 | // userCertificate CertificateSerialNumber, |
| 72 | // revocationDate Time, |
| 73 | // crlEntryExtensions Extensions OPTIONAL |
| 74 | // -- if present, version MUST be v2 |
| 75 | // } OPTIONAL, |
| 76 | // crlExtensions [0] EXPLICIT Extensions OPTIONAL |
| 77 | // -- if present, version MUST be v2 |
| 78 | // } |
| 79 | [[nodiscard]] OPENSSL_EXPORT bool ParseCrlTbsCertList( |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 80 | der::Input tbs_tlv, ParsedCrlTbsCertList *out); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 81 | |
| 82 | // Represents a CRL "Version" from RFC 5280. TBSCertList reuses the same |
| 83 | // Version definition from TBSCertificate, however only v1(not present) and |
| 84 | // v2(1) are valid values, so a unique enum is used to avoid confusion. |
| 85 | enum class CrlVersion { |
| 86 | V1, |
| 87 | V2, |
| 88 | }; |
| 89 | |
| 90 | // Corresponds with "TBSCertList" from RFC 5280 Section 5.1: |
| 91 | struct OPENSSL_EXPORT ParsedCrlTbsCertList { |
| 92 | ParsedCrlTbsCertList(); |
| 93 | ~ParsedCrlTbsCertList(); |
| 94 | |
| 95 | // version Version OPTIONAL, |
| 96 | // -- if present, MUST be v2 |
| 97 | // |
| 98 | // Parsing guarantees that the version is one of v1 or v2. |
| 99 | CrlVersion version = CrlVersion::V1; |
| 100 | |
| 101 | // signature AlgorithmIdentifier, |
| 102 | // |
| 103 | // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| 104 | // guarantees are made regarding the value of this SEQUENCE. |
| 105 | // |
| 106 | // This can be further parsed using SignatureValue::Create(). |
| 107 | der::Input signature_algorithm_tlv; |
| 108 | |
| 109 | // issuer Name, |
| 110 | // |
| 111 | // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| 112 | // guarantees are made regarding the value of this SEQUENCE. |
| 113 | der::Input issuer_tlv; |
| 114 | |
| 115 | // thisUpdate Time, |
| 116 | // nextUpdate Time OPTIONAL, |
| 117 | // |
| 118 | // Parsing guarantees that thisUpdate and nextUpdate(if present) are valid |
| 119 | // DER-encoded dates, however it DOES NOT guarantee anything about their |
| 120 | // values. For instance notAfter could be before notBefore, or the dates |
| 121 | // could indicate an expired CRL. |
| 122 | der::GeneralizedTime this_update; |
| 123 | std::optional<der::GeneralizedTime> next_update; |
| 124 | |
| 125 | // revokedCertificates SEQUENCE OF SEQUENCE { |
| 126 | // userCertificate CertificateSerialNumber, |
| 127 | // revocationDate Time, |
| 128 | // crlEntryExtensions Extensions OPTIONAL |
| 129 | // -- if present, version MUST be v2 |
| 130 | // } OPTIONAL, |
| 131 | // |
| 132 | // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| 133 | // guarantees are made regarding the value of this SEQUENCE. |
| 134 | std::optional<der::Input> revoked_certificates_tlv; |
| 135 | |
| 136 | // crlExtensions [0] EXPLICIT Extensions OPTIONAL |
| 137 | // -- if present, version MUST be v2 |
| 138 | // |
| 139 | // This contains the full (unverified) Tag-Length-Value for a SEQUENCE. No |
| 140 | // guarantees are made regarding the value of this SEQUENCE. (Note that the |
| 141 | // EXPLICIT outer tag is stripped.) |
| 142 | // |
| 143 | // Parsing guarantees that if extensions is present the version is v2. |
| 144 | std::optional<der::Input> crl_extensions_tlv; |
| 145 | }; |
| 146 | |
| 147 | // Represents the IssuingDistributionPoint certificate type constraints: |
| 148 | enum class ContainedCertsType { |
| 149 | // Neither onlyContainsUserCerts or onlyContainsCACerts was present. |
| 150 | ANY_CERTS, |
| 151 | // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, |
| 152 | USER_CERTS, |
| 153 | // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, |
| 154 | CA_CERTS, |
| 155 | }; |
| 156 | |
| 157 | // Parses a DER-encoded IssuingDistributionPoint extension value. |
| 158 | // Returns true on success and sets the results in the |out_*| parameters. |
| 159 | // |
| 160 | // If the IssuingDistributionPoint contains a distributionPoint fullName field, |
| 161 | // |out_distribution_point_names| will contain the parsed representation. |
| 162 | // If the distributionPoint type is nameRelativeToCRLIssuer, parsing will fail. |
| 163 | // |
| 164 | // |out_only_contains_cert_type| will contain the logical representation of the |
| 165 | // onlyContainsUserCerts and onlyContainsCACerts fields (or their absence). |
| 166 | // |
| 167 | // indirectCRL and onlyContainsAttributeCerts are not supported and parsing will |
| 168 | // fail if they are present. |
| 169 | // |
| 170 | // Note that on success |out_distribution_point_names| aliases data from the |
| 171 | // input |extension_value|. |
| 172 | // |
| 173 | // On failure the |out_*| parameters have undefined state. |
| 174 | // |
| 175 | // IssuingDistributionPoint ::= SEQUENCE { |
| 176 | // distributionPoint [0] DistributionPointName OPTIONAL, |
| 177 | // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, |
| 178 | // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, |
| 179 | // onlySomeReasons [3] ReasonFlags OPTIONAL, |
| 180 | // indirectCRL [4] BOOLEAN DEFAULT FALSE, |
| 181 | // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } |
| 182 | [[nodiscard]] OPENSSL_EXPORT bool ParseIssuingDistributionPoint( |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 183 | der::Input extension_value, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 184 | std::unique_ptr<GeneralNames> *out_distribution_point_names, |
| 185 | ContainedCertsType *out_only_contains_cert_type); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 186 | |
| 187 | OPENSSL_EXPORT CRLRevocationStatus |
David Benjamin | 81138bc | 2024-01-23 14:53:40 -0500 | [diff] [blame] | 188 | GetCRLStatusForCert(der::Input cert_serial, CrlVersion crl_version, |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 189 | const std::optional<der::Input> &revoked_certificates_tlv); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 190 | |
| 191 | // Checks the revocation status of the certificate |cert| by using the |
| 192 | // DER-encoded |raw_crl|. |cert| must already have passed certificate path |
| 193 | // validation. |
| 194 | // |
| 195 | // Returns GOOD if the CRL indicates the certificate is not revoked, |
| 196 | // REVOKED if it indicates it is revoked, or UNKNOWN for all other cases. |
| 197 | // |
| 198 | // * |raw_crl|: A DER encoded CRL CertificateList. |
| 199 | // * |valid_chain|: The validated certificate chain containing the target cert. |
| 200 | // * |target_cert_index|: The index into |valid_chain| of the certificate being |
| 201 | // checked for revocation. |
| 202 | // * |cert_dp|: The distribution point from the target certificate's CRL |
| 203 | // distribution points extension that |raw_crl| corresponds to. If |
| 204 | // |raw_crl| was not specified in a distribution point, the caller must |
| 205 | // synthesize a ParsedDistributionPoint object as specified by RFC 5280 |
| 206 | // 6.3.3. |
| 207 | // * |verify_time_epoch_seconds|: The time as the difference in seconds from |
| 208 | // the POSIX epoch to use when checking revocation status. |
| 209 | // * |max_age_seconds|: If present, the maximum age in seconds for a CRL, |
| 210 | // implemented as time since the |thisUpdate| field in the CRL |
| 211 | // TBSCertList. Responses older than |max_age_seconds| will be |
| 212 | // considered invalid. |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 213 | [[nodiscard]] OPENSSL_EXPORT CRLRevocationStatus CheckCRL( |
| 214 | std::string_view raw_crl, const ParsedCertificateList &valid_chain, |
| 215 | size_t target_cert_index, const ParsedDistributionPoint &cert_dp, |
| 216 | int64_t verify_time_epoch_seconds, std::optional<int64_t> max_age_seconds); |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 217 | |
Bob Beck | 5c7a2a0 | 2023-11-20 17:28:21 -0700 | [diff] [blame] | 218 | } // namespace bssl |
Bob Beck | bc97b7a | 2023-04-18 08:35:15 -0600 | [diff] [blame] | 219 | |
| 220 | #endif // BSSL_PKI_CRL_H_ |