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 #include <algorithm>
6 #include <iterator>
7
8 #include <openssl/base.h>
9 #include <openssl/bytestring.h>
10
11 #include "cert_errors.h"
12 #include "crl.h"
13 #include "input.h"
14 #include "parse_values.h"
15 #include "parser.h"
16 #include "revocation_util.h"
17 #include "signature_algorithm.h"
18 #include "verify_name_match.h"
19 #include "verify_signed_data.h"
20
21 namespace bssl {
22
23 namespace {
24
25 // id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
26 // In dotted notation: 2.5.29.28
27 inline constexpr uint8_t kIssuingDistributionPointOid[] = {0x55, 0x1d, 0x1c};
28
NormalizeNameTLV(der::Input name_tlv,std::string * out_normalized_name)29 [[nodiscard]] bool NormalizeNameTLV(der::Input name_tlv,
30 std::string *out_normalized_name) {
31 der::Parser parser(name_tlv);
32 der::Input name_rdn;
33 bssl::CertErrors unused_errors;
34 return parser.ReadTag(CBS_ASN1_SEQUENCE, &name_rdn) &&
35 NormalizeName(name_rdn, out_normalized_name, &unused_errors) &&
36 !parser.HasMore();
37 }
38
ContainsExactMatchingName(std::vector<std::string_view> a,std::vector<std::string_view> b)39 bool 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
ParseCrlCertificateList(der::Input crl_tlv,der::Input * out_tbs_cert_list_tlv,der::Input * out_signature_algorithm_tlv,der::BitString * out_signature_value)51 bool ParseCrlCertificateList(der::Input crl_tlv,
52 der::Input *out_tbs_cert_list_tlv,
53 der::Input *out_signature_algorithm_tlv,
54 der::BitString *out_signature_value) {
55 der::Parser parser(crl_tlv);
56
57 // CertificateList ::= SEQUENCE {
58 der::Parser certificate_list_parser;
59 if (!parser.ReadSequence(&certificate_list_parser)) {
60 return false;
61 }
62
63 // tbsCertList TBSCertList
64 if (!certificate_list_parser.ReadRawTLV(out_tbs_cert_list_tlv)) {
65 return false;
66 }
67
68 // signatureAlgorithm AlgorithmIdentifier,
69 if (!certificate_list_parser.ReadRawTLV(out_signature_algorithm_tlv)) {
70 return false;
71 }
72
73 // signatureValue BIT STRING }
74 std::optional<der::BitString> signature_value =
75 certificate_list_parser.ReadBitString();
76 if (!signature_value) {
77 return false;
78 }
79 *out_signature_value = signature_value.value();
80
81 // There isn't an extension point at the end of CertificateList.
82 if (certificate_list_parser.HasMore()) {
83 return false;
84 }
85
86 // By definition the input was a single CertificateList, so there shouldn't be
87 // unconsumed data.
88 if (parser.HasMore()) {
89 return false;
90 }
91
92 return true;
93 }
94
ParseCrlTbsCertList(der::Input tbs_tlv,ParsedCrlTbsCertList * out)95 bool ParseCrlTbsCertList(der::Input tbs_tlv, ParsedCrlTbsCertList *out) {
96 der::Parser parser(tbs_tlv);
97
98 // TBSCertList ::= SEQUENCE {
99 der::Parser tbs_parser;
100 if (!parser.ReadSequence(&tbs_parser)) {
101 return false;
102 }
103
104 // version Version OPTIONAL,
105 // -- if present, MUST be v2
106 std::optional<der::Input> version_der;
107 if (!tbs_parser.ReadOptionalTag(CBS_ASN1_INTEGER, &version_der)) {
108 return false;
109 }
110 if (version_der.has_value()) {
111 uint64_t version64;
112 if (!der::ParseUint64(*version_der, &version64)) {
113 return false;
114 }
115 // If version is present, it MUST be v2(1).
116 if (version64 != 1) {
117 return false;
118 }
119 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,
127 if (!tbs_parser.ReadRawTLV(&out->signature_algorithm_tlv)) {
128 return false;
129 }
130
131 // issuer Name,
132 if (!tbs_parser.ReadRawTLV(&out->issuer_tlv)) {
133 return false;
134 }
135
136 // thisUpdate Time,
137 if (!ReadUTCOrGeneralizedTime(&tbs_parser, &out->this_update)) {
138 return false;
139 }
140
141 // nextUpdate Time OPTIONAL,
142 CBS_ASN1_TAG maybe_next_update_tag;
143 der::Input unused_next_update_input;
144 if (tbs_parser.PeekTagAndValue(&maybe_next_update_tag,
145 &unused_next_update_input) &&
146 (maybe_next_update_tag == CBS_ASN1_UTCTIME ||
147 maybe_next_update_tag == CBS_ASN1_GENERALIZEDTIME)) {
148 der::GeneralizedTime next_update_time;
149 if (!ReadUTCOrGeneralizedTime(&tbs_parser, &next_update_time)) {
150 return false;
151 }
152 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;
159 CBS_ASN1_TAG maybe_revoked_certifigates_tag;
160 if (tbs_parser.PeekTagAndValue(&maybe_revoked_certifigates_tag,
161 &unused_revoked_certificates) &&
162 maybe_revoked_certifigates_tag == CBS_ASN1_SEQUENCE) {
163 der::Input revoked_certificates_tlv;
164 if (!tbs_parser.ReadRawTLV(&revoked_certificates_tlv)) {
165 return false;
166 }
167 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
174 if (!tbs_parser.ReadOptionalTag(
175 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
176 &out->crl_extensions_tlv)) {
177 return false;
178 }
179 if (out->crl_extensions_tlv.has_value()) {
180 if (out->version != CrlVersion::V2) {
181 return false;
182 }
183 }
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.
192 if (parser.HasMore()) {
193 return false;
194 }
195
196 return true;
197 }
198
ParseIssuingDistributionPoint(der::Input extension_value,std::unique_ptr<GeneralNames> * out_distribution_point_names,ContainedCertsType * out_only_contains_cert_type)199 bool ParseIssuingDistributionPoint(
200 der::Input extension_value,
201 std::unique_ptr<GeneralNames> *out_distribution_point_names,
202 ContainedCertsType *out_only_contains_cert_type) {
203 der::Parser idp_extension_value_parser(extension_value);
204 // IssuingDistributionPoint ::= SEQUENCE {
205 der::Parser idp_parser;
206 if (!idp_extension_value_parser.ReadSequence(&idp_parser)) {
207 return false;
208 }
209
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.
213 if (!idp_parser.HasMore()) {
214 return false;
215 }
216
217 // distributionPoint [0] DistributionPointName OPTIONAL,
218 std::optional<der::Input> distribution_point;
219 if (!idp_parser.ReadOptionalTag(
220 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
221 &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(
232 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
233 &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);
243 if (!*out_distribution_point_names) {
244 return false;
245 }
246
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;
257 if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 1,
258 &only_contains_user_certs)) {
259 return false;
260 }
261 if (only_contains_user_certs.has_value()) {
262 bool bool_value;
263 if (!der::ParseBool(*only_contains_user_certs, &bool_value)) {
264 return false;
265 }
266 if (!bool_value) {
267 return false; // DER-encoding requires DEFAULT values be omitted.
268 }
269 *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;
274 if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 2,
275 &only_contains_ca_certs)) {
276 return false;
277 }
278 if (only_contains_ca_certs.has_value()) {
279 bool bool_value;
280 if (!der::ParseBool(*only_contains_ca_certs, &bool_value)) {
281 return false;
282 }
283 if (!bool_value) {
284 return false; // DER-encoding requires DEFAULT values be omitted.
285 }
286 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.
299 if (idp_parser.HasMore()) {
300 return false;
301 }
302
303 return true;
304 }
305
GetCRLStatusForCert(der::Input cert_serial,CrlVersion crl_version,const std::optional<der::Input> & revoked_certificates_tlv)306 CRLRevocationStatus GetCRLStatusForCert(
307 der::Input cert_serial, CrlVersion crl_version,
308 const std::optional<der::Input> &revoked_certificates_tlv) {
309 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;
320 if (!parser.ReadSequence(&revoked_certificates_parser)) {
321 return CRLRevocationStatus::UNKNOWN;
322 }
323
324 // RFC 5280 Section 5.1.2.6: "When there are no revoked certificates, the
325 // revoked certificates list MUST be absent."
326 if (!revoked_certificates_parser.HasMore()) {
327 return CRLRevocationStatus::UNKNOWN;
328 }
329
330 // By definition the input was a single Extensions sequence, so there
331 // shouldn't be unconsumed data.
332 if (parser.HasMore()) {
333 return CRLRevocationStatus::UNKNOWN;
334 }
335
336 bool found_matching_serial = false;
337
338 while (revoked_certificates_parser.HasMore()) {
339 // revokedCertificates SEQUENCE OF SEQUENCE {
340 der::Parser crl_entry_parser;
341 if (!revoked_certificates_parser.ReadSequence(&crl_entry_parser)) {
342 return CRLRevocationStatus::UNKNOWN;
343 }
344
345 der::Input revoked_cert_serial_number;
346 // userCertificate CertificateSerialNumber,
347 if (!crl_entry_parser.ReadTag(CBS_ASN1_INTEGER,
348 &revoked_cert_serial_number)) {
349 return CRLRevocationStatus::UNKNOWN;
350 }
351
352 // revocationDate Time,
353 der::GeneralizedTime unused_revocation_date;
354 if (!ReadUTCOrGeneralizedTime(&crl_entry_parser, &unused_revocation_date)) {
355 return CRLRevocationStatus::UNKNOWN;
356 }
357
358 // crlEntryExtensions Extensions OPTIONAL
359 if (crl_entry_parser.HasMore()) {
360 // -- if present, version MUST be v2
361 if (crl_version != CrlVersion::V2) {
362 return CRLRevocationStatus::UNKNOWN;
363 }
364
365 der::Input crl_entry_extensions_tlv;
366 if (!crl_entry_parser.ReadRawTLV(&crl_entry_extensions_tlv)) {
367 return CRLRevocationStatus::UNKNOWN;
368 }
369
370 std::map<der::Input, ParsedExtension> extensions;
371 if (!ParseExtensions(crl_entry_extensions_tlv, &extensions)) {
372 return CRLRevocationStatus::UNKNOWN;
373 }
374
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."
378 for (const auto &ext : extensions) {
379 if (ext.second.critical) {
380 return CRLRevocationStatus::UNKNOWN;
381 }
382 }
383 }
384
385 if (crl_entry_parser.HasMore()) {
386 return CRLRevocationStatus::UNKNOWN;
387 }
388
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
396 if (found_matching_serial) {
397 return CRLRevocationStatus::REVOKED;
398 }
399
400 // |cert| is not present in the revokedCertificates list.
401 return CRLRevocationStatus::GOOD;
402 }
403
404 ParsedCrlTbsCertList::ParsedCrlTbsCertList() = default;
405 ParsedCrlTbsCertList::~ParsedCrlTbsCertList() = default;
406
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)407 CRLRevocationStatus CheckCRL(std::string_view raw_crl,
408 const ParsedCertificateList &valid_chain,
409 size_t target_cert_index,
410 const ParsedDistributionPoint &cert_dp,
411 int64_t verify_time_epoch_seconds,
412 std::optional<int64_t> max_age_seconds) {
413 BSSL_CHECK(target_cert_index < valid_chain.size());
414
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
426 const ParsedCertificate *target_cert = valid_chain[target_cert_index].get();
427
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;
443 if (!ParseCrlTbsCertList(tbs_cert_list_tlv, &tbs_cert_list)) {
444 return CRLRevocationStatus::UNKNOWN;
445 }
446
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;
509 if (!NormalizeNameTLV(tbs_cert_list.issuer_tlv, &normalized_crl_issuer)) {
510 return CRLRevocationStatus::UNKNOWN;
511 }
512 if (der::Input(normalized_crl_issuer) != target_cert->normalized_issuer()) {
513 return CRLRevocationStatus::UNKNOWN;
514 }
515
516 if (tbs_cert_list.crl_extensions_tlv.has_value()) {
517 std::map<der::Input, ParsedExtension> extensions;
518 if (!ParseExtensions(*tbs_cert_list.crl_extensions_tlv, &extensions)) {
519 return CRLRevocationStatus::UNKNOWN;
520 }
521
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
602 for (const auto &ext : extensions) {
603 // Fail if any unhandled critical CRL extensions are present.
604 if (ext.second.critical) {
605 return CRLRevocationStatus::UNKNOWN;
606 }
607 }
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) {
623 const ParsedCertificate *issuer_cert = valid_chain[i].get();
624
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.
632 if (der::Input(normalized_crl_issuer) !=
633 issuer_cert->normalized_subject()) {
634 continue;
635 }
636
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
673 } // namespace bssl
674