blob: 63e1cc6d9e566b4843006120dd6d7c0979bd78cd [file] [log] [blame]
Bob Beckbc97b7a2023-04-18 08:35:15 -06001// 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#include <algorithm>
6#include <iterator>
7
Bob Beck05007562023-08-17 20:22:17 +00008#include <openssl/base.h>
David Benjamin2a5db682024-02-06 21:56:57 -05009#include <openssl/bytestring.h>
Bob Beck05007562023-08-17 20:22:17 +000010
Bob Beckbc97b7a2023-04-18 08:35:15 -060011#include "cert_errors.h"
12#include "crl.h"
Bob Beckbc97b7a2023-04-18 08:35:15 -060013#include "input.h"
14#include "parse_values.h"
15#include "parser.h"
Bob Beck5c7a2a02023-11-20 17:28:21 -070016#include "revocation_util.h"
17#include "signature_algorithm.h"
Bob Beck5c7a2a02023-11-20 17:28:21 -070018#include "verify_name_match.h"
19#include "verify_signed_data.h"
Bob Beckbc97b7a2023-04-18 08:35:15 -060020
21namespace bssl {
22
23namespace {
24
25// id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
26// In dotted notation: 2.5.29.28
27inline constexpr uint8_t kIssuingDistributionPointOid[] = {0x55, 0x1d, 0x1c};
28
David Benjamin81138bc2024-01-23 14:53:40 -050029[[nodiscard]] bool NormalizeNameTLV(der::Input name_tlv,
Bob Beck5c7a2a02023-11-20 17:28:21 -070030 std::string *out_normalized_name) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060031 der::Parser parser(name_tlv);
32 der::Input name_rdn;
33 bssl::CertErrors unused_errors;
David Benjamin2a5db682024-02-06 21:56:57 -050034 return parser.ReadTag(CBS_ASN1_SEQUENCE, &name_rdn) &&
Bob Beckbc97b7a2023-04-18 08:35:15 -060035 NormalizeName(name_rdn, out_normalized_name, &unused_errors) &&
36 !parser.HasMore();
37}
38
39bool ContainsExactMatchingName(std::vector<std::string_view> a,
40 std::vector<std::string_view> b) {
41 std::sort(a.begin(), a.end());
42 std::sort(b.begin(), b.end());
43 std::vector<std::string_view> names_in_common;
44 std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
45 std::back_inserter(names_in_common));
46 return !names_in_common.empty();
47}
48
49} // namespace
50
David Benjamin81138bc2024-01-23 14:53:40 -050051bool ParseCrlCertificateList(der::Input crl_tlv,
Bob Beck5c7a2a02023-11-20 17:28:21 -070052 der::Input *out_tbs_cert_list_tlv,
53 der::Input *out_signature_algorithm_tlv,
54 der::BitString *out_signature_value) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060055 der::Parser parser(crl_tlv);
56
57 // CertificateList ::= SEQUENCE {
58 der::Parser certificate_list_parser;
Bob Beck6beabf32023-11-21 09:43:52 -070059 if (!parser.ReadSequence(&certificate_list_parser)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060060 return false;
Bob Beck6beabf32023-11-21 09:43:52 -070061 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060062
63 // tbsCertList TBSCertList
Bob Beck6beabf32023-11-21 09:43:52 -070064 if (!certificate_list_parser.ReadRawTLV(out_tbs_cert_list_tlv)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060065 return false;
Bob Beck6beabf32023-11-21 09:43:52 -070066 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060067
68 // signatureAlgorithm AlgorithmIdentifier,
Bob Beck6beabf32023-11-21 09:43:52 -070069 if (!certificate_list_parser.ReadRawTLV(out_signature_algorithm_tlv)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060070 return false;
Bob Beck6beabf32023-11-21 09:43:52 -070071 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060072
73 // signatureValue BIT STRING }
74 std::optional<der::BitString> signature_value =
75 certificate_list_parser.ReadBitString();
Bob Beck6beabf32023-11-21 09:43:52 -070076 if (!signature_value) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060077 return false;
Bob Beck6beabf32023-11-21 09:43:52 -070078 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060079 *out_signature_value = signature_value.value();
80
81 // There isn't an extension point at the end of CertificateList.
Bob Beck6beabf32023-11-21 09:43:52 -070082 if (certificate_list_parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060083 return false;
Bob Beck6beabf32023-11-21 09:43:52 -070084 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060085
86 // By definition the input was a single CertificateList, so there shouldn't be
87 // unconsumed data.
Bob Beck6beabf32023-11-21 09:43:52 -070088 if (parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060089 return false;
Bob Beck6beabf32023-11-21 09:43:52 -070090 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060091
92 return true;
93}
94
David Benjamin81138bc2024-01-23 14:53:40 -050095bool ParseCrlTbsCertList(der::Input tbs_tlv, ParsedCrlTbsCertList *out) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060096 der::Parser parser(tbs_tlv);
97
98 // TBSCertList ::= SEQUENCE {
99 der::Parser tbs_parser;
Bob Beck6beabf32023-11-21 09:43:52 -0700100 if (!parser.ReadSequence(&tbs_parser)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600101 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700102 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600103
104 // version Version OPTIONAL,
105 // -- if present, MUST be v2
106 std::optional<der::Input> version_der;
David Benjamin2a5db682024-02-06 21:56:57 -0500107 if (!tbs_parser.ReadOptionalTag(CBS_ASN1_INTEGER, &version_der)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600108 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700109 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600110 if (version_der.has_value()) {
111 uint64_t version64;
Bob Beck6beabf32023-11-21 09:43:52 -0700112 if (!der::ParseUint64(*version_der, &version64)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600113 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700114 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600115 // If version is present, it MUST be v2(1).
Bob Beck6beabf32023-11-21 09:43:52 -0700116 if (version64 != 1) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600117 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700118 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600119 out->version = CrlVersion::V2;
120 } else {
121 // Uh, RFC 5280 doesn't actually say it anywhere, but presumably if version
122 // is not specified, it is V1.
123 out->version = CrlVersion::V1;
124 }
125
126 // signature AlgorithmIdentifier,
Bob Beck6beabf32023-11-21 09:43:52 -0700127 if (!tbs_parser.ReadRawTLV(&out->signature_algorithm_tlv)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600128 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700129 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600130
131 // issuer Name,
Bob Beck6beabf32023-11-21 09:43:52 -0700132 if (!tbs_parser.ReadRawTLV(&out->issuer_tlv)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600133 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700134 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600135
136 // thisUpdate Time,
Bob Beck6beabf32023-11-21 09:43:52 -0700137 if (!ReadUTCOrGeneralizedTime(&tbs_parser, &out->this_update)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600138 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700139 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600140
141 // nextUpdate Time OPTIONAL,
David Benjamin2a5db682024-02-06 21:56:57 -0500142 CBS_ASN1_TAG maybe_next_update_tag;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600143 der::Input unused_next_update_input;
144 if (tbs_parser.PeekTagAndValue(&maybe_next_update_tag,
145 &unused_next_update_input) &&
David Benjamin2a5db682024-02-06 21:56:57 -0500146 (maybe_next_update_tag == CBS_ASN1_UTCTIME ||
147 maybe_next_update_tag == CBS_ASN1_GENERALIZEDTIME)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600148 der::GeneralizedTime next_update_time;
Bob Beck6beabf32023-11-21 09:43:52 -0700149 if (!ReadUTCOrGeneralizedTime(&tbs_parser, &next_update_time)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600150 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700151 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600152 out->next_update = next_update_time;
153 } else {
154 out->next_update = std::nullopt;
155 }
156
157 // revokedCertificates SEQUENCE OF SEQUENCE { ... } OPTIONAL,
158 der::Input unused_revoked_certificates;
David Benjamin2a5db682024-02-06 21:56:57 -0500159 CBS_ASN1_TAG maybe_revoked_certifigates_tag;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600160 if (tbs_parser.PeekTagAndValue(&maybe_revoked_certifigates_tag,
161 &unused_revoked_certificates) &&
David Benjamin2a5db682024-02-06 21:56:57 -0500162 maybe_revoked_certifigates_tag == CBS_ASN1_SEQUENCE) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600163 der::Input revoked_certificates_tlv;
Bob Beck6beabf32023-11-21 09:43:52 -0700164 if (!tbs_parser.ReadRawTLV(&revoked_certificates_tlv)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600165 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700166 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600167 out->revoked_certificates_tlv = revoked_certificates_tlv;
168 } else {
169 out->revoked_certificates_tlv = std::nullopt;
170 }
171
172 // crlExtensions [0] EXPLICIT Extensions OPTIONAL
173 // -- if present, version MUST be v2
David Benjamin2a5db682024-02-06 21:56:57 -0500174 if (!tbs_parser.ReadOptionalTag(
175 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
176 &out->crl_extensions_tlv)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600177 return false;
178 }
179 if (out->crl_extensions_tlv.has_value()) {
Bob Beck6beabf32023-11-21 09:43:52 -0700180 if (out->version != CrlVersion::V2) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600181 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700182 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600183 }
184
185 if (tbs_parser.HasMore()) {
186 // Invalid or extraneous elements.
187 return false;
188 }
189
190 // By definition the input was a single sequence, so there shouldn't be
191 // unconsumed data.
Bob Beck6beabf32023-11-21 09:43:52 -0700192 if (parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600193 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700194 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600195
196 return true;
197}
198
199bool ParseIssuingDistributionPoint(
David Benjamin81138bc2024-01-23 14:53:40 -0500200 der::Input extension_value,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700201 std::unique_ptr<GeneralNames> *out_distribution_point_names,
202 ContainedCertsType *out_only_contains_cert_type) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600203 der::Parser idp_extension_value_parser(extension_value);
204 // IssuingDistributionPoint ::= SEQUENCE {
205 der::Parser idp_parser;
Bob Beck6beabf32023-11-21 09:43:52 -0700206 if (!idp_extension_value_parser.ReadSequence(&idp_parser)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600207 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700208 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600209
210 // 5.2.5. Conforming CRLs issuers MUST NOT issue CRLs where the DER
211 // encoding of the issuing distribution point extension is an empty
212 // sequence.
Bob Beck6beabf32023-11-21 09:43:52 -0700213 if (!idp_parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600214 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700215 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600216
217 // distributionPoint [0] DistributionPointName OPTIONAL,
218 std::optional<der::Input> distribution_point;
219 if (!idp_parser.ReadOptionalTag(
David Benjamin2a5db682024-02-06 21:56:57 -0500220 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600221 &distribution_point)) {
222 return false;
223 }
224
225 if (distribution_point.has_value()) {
226 // DistributionPointName ::= CHOICE {
227 der::Parser dp_name_parser(*distribution_point);
228 // fullName [0] GeneralNames,
229 // nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
230 std::optional<der::Input> der_full_name;
231 if (!dp_name_parser.ReadOptionalTag(
David Benjamin2a5db682024-02-06 21:56:57 -0500232 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600233 &der_full_name)) {
234 return false;
235 }
236 if (!der_full_name) {
237 // Only fullName is supported.
238 return false;
239 }
240 CertErrors errors;
241 *out_distribution_point_names =
242 GeneralNames::CreateFromValue(*der_full_name, &errors);
Bob Beck6beabf32023-11-21 09:43:52 -0700243 if (!*out_distribution_point_names) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600244 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700245 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600246
247 if (dp_name_parser.HasMore()) {
248 // CHOICE represents a single value.
249 return false;
250 }
251 }
252
253 *out_only_contains_cert_type = ContainedCertsType::ANY_CERTS;
254
255 // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
256 std::optional<der::Input> only_contains_user_certs;
David Benjamin2a5db682024-02-06 21:56:57 -0500257 if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 1,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600258 &only_contains_user_certs)) {
259 return false;
260 }
261 if (only_contains_user_certs.has_value()) {
262 bool bool_value;
Bob Beck6beabf32023-11-21 09:43:52 -0700263 if (!der::ParseBool(*only_contains_user_certs, &bool_value)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600264 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700265 }
266 if (!bool_value) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600267 return false; // DER-encoding requires DEFAULT values be omitted.
Bob Beck6beabf32023-11-21 09:43:52 -0700268 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600269 *out_only_contains_cert_type = ContainedCertsType::USER_CERTS;
270 }
271
272 // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
273 std::optional<der::Input> only_contains_ca_certs;
David Benjamin2a5db682024-02-06 21:56:57 -0500274 if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 2,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600275 &only_contains_ca_certs)) {
276 return false;
277 }
278 if (only_contains_ca_certs.has_value()) {
279 bool bool_value;
Bob Beck6beabf32023-11-21 09:43:52 -0700280 if (!der::ParseBool(*only_contains_ca_certs, &bool_value)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600281 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700282 }
283 if (!bool_value) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600284 return false; // DER-encoding requires DEFAULT values be omitted.
Bob Beck6beabf32023-11-21 09:43:52 -0700285 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600286 if (*out_only_contains_cert_type != ContainedCertsType::ANY_CERTS) {
287 // 5.2.5. at most one of onlyContainsUserCerts, onlyContainsCACerts,
288 // and onlyContainsAttributeCerts may be set to TRUE.
289 return false;
290 }
291 *out_only_contains_cert_type = ContainedCertsType::CA_CERTS;
292 }
293
294 // onlySomeReasons [3] ReasonFlags OPTIONAL,
295 // indirectCRL [4] BOOLEAN DEFAULT FALSE,
296 // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
297 // onlySomeReasons, indirectCRL, and onlyContainsAttributeCerts are not
298 // supported, fail parsing if they are present.
Bob Beck6beabf32023-11-21 09:43:52 -0700299 if (idp_parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600300 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700301 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600302
303 return true;
304}
305
306CRLRevocationStatus GetCRLStatusForCert(
David Benjamin81138bc2024-01-23 14:53:40 -0500307 der::Input cert_serial, CrlVersion crl_version,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700308 const std::optional<der::Input> &revoked_certificates_tlv) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600309 if (!revoked_certificates_tlv.has_value()) {
310 // RFC 5280 Section 5.1.2.6: "When there are no revoked certificates, the
311 // revoked certificates list MUST be absent."
312 // No covered certificates are revoked, therefore the cert is good.
313 return CRLRevocationStatus::GOOD;
314 }
315
316 der::Parser parser(*revoked_certificates_tlv);
317
318 // revokedCertificates SEQUENCE OF SEQUENCE {
319 der::Parser revoked_certificates_parser;
Bob Beck6beabf32023-11-21 09:43:52 -0700320 if (!parser.ReadSequence(&revoked_certificates_parser)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600321 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700322 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600323
324 // RFC 5280 Section 5.1.2.6: "When there are no revoked certificates, the
325 // revoked certificates list MUST be absent."
Bob Beck6beabf32023-11-21 09:43:52 -0700326 if (!revoked_certificates_parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600327 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700328 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600329
330 // By definition the input was a single Extensions sequence, so there
331 // shouldn't be unconsumed data.
Bob Beck6beabf32023-11-21 09:43:52 -0700332 if (parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600333 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700334 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600335
336 bool found_matching_serial = false;
337
338 while (revoked_certificates_parser.HasMore()) {
339 // revokedCertificates SEQUENCE OF SEQUENCE {
340 der::Parser crl_entry_parser;
Bob Beck6beabf32023-11-21 09:43:52 -0700341 if (!revoked_certificates_parser.ReadSequence(&crl_entry_parser)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600342 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700343 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600344
345 der::Input revoked_cert_serial_number;
346 // userCertificate CertificateSerialNumber,
David Benjamin2a5db682024-02-06 21:56:57 -0500347 if (!crl_entry_parser.ReadTag(CBS_ASN1_INTEGER,
348 &revoked_cert_serial_number)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600349 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700350 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600351
352 // revocationDate Time,
353 der::GeneralizedTime unused_revocation_date;
Bob Beck6beabf32023-11-21 09:43:52 -0700354 if (!ReadUTCOrGeneralizedTime(&crl_entry_parser, &unused_revocation_date)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600355 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700356 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600357
358 // crlEntryExtensions Extensions OPTIONAL
359 if (crl_entry_parser.HasMore()) {
360 // -- if present, version MUST be v2
Bob Beck6beabf32023-11-21 09:43:52 -0700361 if (crl_version != CrlVersion::V2) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600362 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700363 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600364
365 der::Input crl_entry_extensions_tlv;
Bob Beck6beabf32023-11-21 09:43:52 -0700366 if (!crl_entry_parser.ReadRawTLV(&crl_entry_extensions_tlv)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600367 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700368 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600369
370 std::map<der::Input, ParsedExtension> extensions;
Bob Beck6beabf32023-11-21 09:43:52 -0700371 if (!ParseExtensions(crl_entry_extensions_tlv, &extensions)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600372 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700373 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600374
375 // RFC 5280 Section 5.3: "If a CRL contains a critical CRL entry
376 // extension that the application cannot process, then the application
377 // MUST NOT use that CRL to determine the status of any certificates."
Bob Beck5c7a2a02023-11-20 17:28:21 -0700378 for (const auto &ext : extensions) {
Bob Beck6beabf32023-11-21 09:43:52 -0700379 if (ext.second.critical) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600380 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700381 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600382 }
383 }
384
Bob Beck6beabf32023-11-21 09:43:52 -0700385 if (crl_entry_parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600386 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700387 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600388
389 if (revoked_cert_serial_number == cert_serial) {
390 // Cert is revoked, but can't return yet since there might be critical
391 // extensions on later entries that would prevent use of this CRL.
392 found_matching_serial = true;
393 }
394 }
395
Bob Beck6beabf32023-11-21 09:43:52 -0700396 if (found_matching_serial) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600397 return CRLRevocationStatus::REVOKED;
Bob Beck6beabf32023-11-21 09:43:52 -0700398 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600399
400 // |cert| is not present in the revokedCertificates list.
401 return CRLRevocationStatus::GOOD;
402}
403
404ParsedCrlTbsCertList::ParsedCrlTbsCertList() = default;
405ParsedCrlTbsCertList::~ParsedCrlTbsCertList() = default;
406
407CRLRevocationStatus CheckCRL(std::string_view raw_crl,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700408 const ParsedCertificateList &valid_chain,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600409 size_t target_cert_index,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700410 const ParsedDistributionPoint &cert_dp,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600411 int64_t verify_time_epoch_seconds,
412 std::optional<int64_t> max_age_seconds) {
Bob Beck05007562023-08-17 20:22:17 +0000413 BSSL_CHECK(target_cert_index < valid_chain.size());
Bob Beckbc97b7a2023-04-18 08:35:15 -0600414
415 if (cert_dp.reasons) {
416 // Reason codes are not supported. If the distribution point contains a
417 // subset of reasons then skip it. We aren't interested in subsets of CRLs
418 // and the RFC states that there MUST be a CRL that covers all reasons.
419 return CRLRevocationStatus::UNKNOWN;
420 }
421 if (cert_dp.crl_issuer) {
422 // Indirect CRLs are not supported.
423 return CRLRevocationStatus::UNKNOWN;
424 }
425
Bob Beck5c7a2a02023-11-20 17:28:21 -0700426 const ParsedCertificate *target_cert = valid_chain[target_cert_index].get();
Bob Beckbc97b7a2023-04-18 08:35:15 -0600427
428 // 6.3.3 (a) Update the local CRL cache by obtaining a complete CRL, a
429 // delta CRL, or both, as required.
430 //
431 // This implementation only supports complete CRLs and takes the CRL as
432 // input, it is up to the caller to provide an up to date CRL.
433
434 der::Input tbs_cert_list_tlv;
435 der::Input signature_algorithm_tlv;
436 der::BitString signature_value;
437 if (!ParseCrlCertificateList(der::Input(raw_crl), &tbs_cert_list_tlv,
438 &signature_algorithm_tlv, &signature_value)) {
439 return CRLRevocationStatus::UNKNOWN;
440 }
441
442 ParsedCrlTbsCertList tbs_cert_list;
Bob Beck6beabf32023-11-21 09:43:52 -0700443 if (!ParseCrlTbsCertList(tbs_cert_list_tlv, &tbs_cert_list)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600444 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700445 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600446
447 // 5.1.1.2 signatureAlgorithm
448 //
449 // TODO(https://crbug.com/749276): Check the signature algorithm against
450 // policy.
451 std::optional<SignatureAlgorithm> signature_algorithm =
452 ParseSignatureAlgorithm(signature_algorithm_tlv);
453 if (!signature_algorithm) {
454 return CRLRevocationStatus::UNKNOWN;
455 }
456
457 // This field MUST contain the same algorithm identifier as the
458 // signature field in the sequence tbsCertList (Section 5.1.2.2).
459 std::optional<SignatureAlgorithm> tbs_alg =
460 ParseSignatureAlgorithm(tbs_cert_list.signature_algorithm_tlv);
461 if (!tbs_alg || *signature_algorithm != *tbs_alg) {
462 return CRLRevocationStatus::UNKNOWN;
463 }
464
465 // Check CRL dates. Roughly corresponds to 6.3.3 (a) (1) but does not attempt
466 // to update the CRL if it is out of date.
467 if (!CheckRevocationDateValid(tbs_cert_list.this_update,
468 tbs_cert_list.next_update.has_value()
469 ? &tbs_cert_list.next_update.value()
470 : nullptr,
471 verify_time_epoch_seconds, max_age_seconds)) {
472 return CRLRevocationStatus::UNKNOWN;
473 }
474
475 // 6.3.3 (a) (2) is skipped: This implementation does not support delta CRLs.
476
477 // 6.3.3 (b) Verify the issuer and scope of the complete CRL as follows:
478 // 6.3.3 (b) (1) If the DP includes cRLIssuer, then verify that the issuer
479 // field in the complete CRL matches cRLIssuer in the DP and
480 // that the complete CRL contains an issuing distribution
481 // point extension with the indirectCRL boolean asserted.
482 //
483 // Nothing is done here since distribution points with crlIssuer were skipped
484 // above.
485
486 // 6.3.3 (b) (1) Otherwise, verify that the CRL issuer matches the
487 // certificate issuer.
488 //
489 // Normalization for the name comparison is used although the RFC is not
490 // clear on this. There are several places that explicitly are called out as
491 // requiring identical encodings:
492 //
493 // 4.2.1.13. CRL Distribution Points (cert extension) says the DP cRLIssuer
494 // field MUST be exactly the same as the encoding in issuer field of the
495 // CRL.
496 //
497 // 5.2.5. Issuing Distribution Point (crl extension)
498 // The identical encoding MUST be used in the distributionPoint fields
499 // of the certificate and the CRL.
500 //
501 // 5.3.3. Certificate Issuer (crl entry extension) also says "The encoding of
502 // the DN MUST be identical to the encoding used in the certificate"
503 //
504 // But 6.3.3 (b) (1) just says "matches". Also NIST PKITS includes at least
505 // one test that requires normalization here.
506 // TODO(https://crbug.com/749276): could do exact comparison first and only
507 // fall back to normalizing if that fails.
508 std::string normalized_crl_issuer;
Bob Beck6beabf32023-11-21 09:43:52 -0700509 if (!NormalizeNameTLV(tbs_cert_list.issuer_tlv, &normalized_crl_issuer)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600510 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700511 }
Bob Beck2e119172023-08-14 11:06:38 -0600512 if (der::Input(normalized_crl_issuer) != target_cert->normalized_issuer()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600513 return CRLRevocationStatus::UNKNOWN;
Bob Beck2e119172023-08-14 11:06:38 -0600514 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600515
516 if (tbs_cert_list.crl_extensions_tlv.has_value()) {
517 std::map<der::Input, ParsedExtension> extensions;
Bob Beck6beabf32023-11-21 09:43:52 -0700518 if (!ParseExtensions(*tbs_cert_list.crl_extensions_tlv, &extensions)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600519 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700520 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600521
522 // 6.3.3 (b) (2) If the complete CRL includes an issuing distribution point
523 // (IDP) CRL extension, check the following:
524 ParsedExtension idp_extension;
525 if (ConsumeExtension(der::Input(kIssuingDistributionPointOid), &extensions,
526 &idp_extension)) {
527 std::unique_ptr<GeneralNames> distribution_point_names;
528 ContainedCertsType only_contains_cert_type;
529 if (!ParseIssuingDistributionPoint(idp_extension.value,
530 &distribution_point_names,
531 &only_contains_cert_type)) {
532 return CRLRevocationStatus::UNKNOWN;
533 }
534
535 if (distribution_point_names) {
536 // 6.3.3. (b) (2) (i) If the distribution point name is present in the
537 // IDP CRL extension and the distribution field is
538 // present in the DP, then verify that one of the
539 // names in the IDP matches one of the names in the
540 // DP.
541 // 5.2.5. The identical encoding MUST be used in the distributionPoint
542 // fields of the certificate and the CRL.
543 // TODO(https://crbug.com/749276): Check other name types?
544 if (!cert_dp.distribution_point_fullname ||
545 !ContainsExactMatchingName(
546 cert_dp.distribution_point_fullname
547 ->uniform_resource_identifiers,
548 distribution_point_names->uniform_resource_identifiers)) {
549 return CRLRevocationStatus::UNKNOWN;
550 }
551
552 // 6.3.3. (b) (2) (i) If the distribution point name is present in the
553 // IDP CRL extension and the distribution field is
554 // omitted from the DP, then verify that one of the
555 // names in the IDP matches one of the names in the
556 // cRLIssuer field of the DP.
557 // Indirect CRLs are not supported, if indirectCRL was specified,
558 // ParseIssuingDistributionPoint would already have failed.
559 }
560
561 switch (only_contains_cert_type) {
562 case ContainedCertsType::USER_CERTS:
563 // 6.3.3. (b) (2) (ii) If the onlyContainsUserCerts boolean is
564 // asserted in the IDP CRL extension, verify
565 // that the certificate does not include the
566 // basic constraints extension with the cA
567 // boolean asserted.
568 // 5.2.5. If either onlyContainsUserCerts or onlyContainsCACerts is
569 // set to TRUE, then the scope of the CRL MUST NOT include any
570 // version 1 or version 2 certificates.
571 if ((target_cert->has_basic_constraints() &&
572 target_cert->basic_constraints().is_ca) ||
573 target_cert->tbs().version == CertificateVersion::V1 ||
574 target_cert->tbs().version == CertificateVersion::V2) {
575 return CRLRevocationStatus::UNKNOWN;
576 }
577 break;
578
579 case ContainedCertsType::CA_CERTS:
580 // 6.3.3. (b) (2) (iii) If the onlyContainsCACerts boolean is asserted
581 // in the IDP CRL extension, verify that the
582 // certificate includes the basic constraints
583 // extension with the cA boolean asserted.
584 // The version check is not done here, as the basicConstraints
585 // extension is required, and could not be present unless it is a V3
586 // certificate.
587 if (!target_cert->has_basic_constraints() ||
588 !target_cert->basic_constraints().is_ca) {
589 return CRLRevocationStatus::UNKNOWN;
590 }
591 break;
592
593 case ContainedCertsType::ANY_CERTS:
594 // (iv) Verify that the onlyContainsAttributeCerts
595 // boolean is not asserted.
596 // If onlyContainsAttributeCerts was present,
597 // ParseIssuingDistributionPoint would already have failed.
598 break;
599 }
600 }
601
Bob Beck5c7a2a02023-11-20 17:28:21 -0700602 for (const auto &ext : extensions) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600603 // Fail if any unhandled critical CRL extensions are present.
Bob Beck6beabf32023-11-21 09:43:52 -0700604 if (ext.second.critical) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600605 return CRLRevocationStatus::UNKNOWN;
Bob Beck6beabf32023-11-21 09:43:52 -0700606 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600607 }
608 }
609
610 // 6.3.3 (c-e) skipped: delta CRLs and reason codes are not supported.
611
612 // This implementation only supports direct CRLs where the CRL was signed by
613 // one of the certs in its validated issuer chain. This allows handling some
614 // cases of key rollover without requiring additional CRL issuer cert
615 // discovery & path building.
616 // TODO(https://crbug.com/749276): should this loop start at
617 // |target_cert_index|? There doesn't seem to be anything in the specs that
618 // precludes a CRL signed by a self-issued cert from covering itself. On the
619 // other hand it seems like a pretty weird thing to allow and causes NIST
620 // PKITS 4.5.3 to pass when it seems like it would not be intended to (since
621 // issuingDistributionPoint CRL extension is not handled).
622 for (size_t i = target_cert_index + 1; i < valid_chain.size(); ++i) {
Bob Beck5c7a2a02023-11-20 17:28:21 -0700623 const ParsedCertificate *issuer_cert = valid_chain[i].get();
Bob Beckbc97b7a2023-04-18 08:35:15 -0600624
625 // 6.3.3 (f) Obtain and validate the certification path for the issuer of
626 // the complete CRL. The trust anchor for the certification
627 // path MUST be the same as the trust anchor used to validate
628 // the target certificate.
629 //
630 // As the |issuer_cert| is from the already validated chain, it is already
631 // known to chain to the same trust anchor as the target certificate.
Bob Beck2e119172023-08-14 11:06:38 -0600632 if (der::Input(normalized_crl_issuer) !=
633 issuer_cert->normalized_subject()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600634 continue;
Bob Beck2e119172023-08-14 11:06:38 -0600635 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600636
637 // 6.3.3 (f) If a key usage extension is present in the CRL issuer's
638 // certificate, verify that the cRLSign bit is set.
639 if (issuer_cert->has_key_usage() &&
640 !issuer_cert->key_usage().AssertsBit(KEY_USAGE_BIT_CRL_SIGN)) {
641 continue;
642 }
643
644 // 6.3.3 (g) Validate the signature on the complete CRL using the public
645 // key validated in step (f).
646 if (!VerifySignedData(*signature_algorithm, tbs_cert_list_tlv,
647 signature_value, issuer_cert->tbs().spki_tlv,
648 /*cache=*/nullptr)) {
649 continue;
650 }
651
652 // 6.3.3 (h,i) skipped. This implementation does not support delta CRLs.
653
654 // 6.3.3 (j) If (cert_status is UNREVOKED), then search for the
655 // certificate on the complete CRL. If an entry is found that
656 // matches the certificate issuer and serial number as described
657 // in Section 5.3.3, then set the cert_status variable to the
658 // indicated reason as described in step (i).
659 //
660 // CRL is valid and covers |target_cert|, check if |target_cert| is present
661 // in the revokedCertificates sequence.
662 return GetCRLStatusForCert(target_cert->tbs().serial_number,
663 tbs_cert_list.version,
664 tbs_cert_list.revoked_certificates_tlv);
665
666 // 6.3.3 (k,l) skipped. This implementation does not support reason codes.
667 }
668
669 // Did not find the issuer & signer of |raw_crl| in |valid_chain|.
670 return CRLRevocationStatus::UNKNOWN;
671}
672
Bob Beck5c7a2a02023-11-20 17:28:21 -0700673} // namespace bssl