1 // Copyright 2019 The Chromium Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <algorithm>
16 #include <iterator>
17
18 #include <openssl/base.h>
19 #include <openssl/bytestring.h>
20 #include <openssl/span.h>
21
22 #include "cert_errors.h"
23 #include "crl.h"
24 #include "input.h"
25 #include "parse_values.h"
26 #include "parser.h"
27 #include "revocation_util.h"
28 #include "signature_algorithm.h"
29 #include "verify_name_match.h"
30 #include "verify_signed_data.h"
31
32 BSSL_NAMESPACE_BEGIN
33
34 namespace {
35
36 // id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
37 // In dotted notation: 2.5.29.28
38 inline constexpr uint8_t kIssuingDistributionPointOid[] = {0x55, 0x1d, 0x1c};
39
NormalizeNameTLV(der::Input name_tlv,std::string * out_normalized_name)40 [[nodiscard]] bool NormalizeNameTLV(der::Input name_tlv,
41 std::string *out_normalized_name) {
42 der::Parser parser(name_tlv);
43 der::Input name_rdn;
44 bssl::CertErrors unused_errors;
45 return parser.ReadTag(CBS_ASN1_SEQUENCE, &name_rdn) &&
46 NormalizeName(name_rdn, out_normalized_name, &unused_errors) &&
47 !parser.HasMore();
48 }
49
ContainsExactMatchingName(std::vector<std::string_view> a,std::vector<std::string_view> b)50 bool ContainsExactMatchingName(std::vector<std::string_view> a,
51 std::vector<std::string_view> b) {
52 std::sort(a.begin(), a.end());
53 std::sort(b.begin(), b.end());
54 std::vector<std::string_view> names_in_common;
55 std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
56 std::back_inserter(names_in_common));
57 return !names_in_common.empty();
58 }
59
60 } // namespace
61
ParseCrlCertificateList(der::Input crl_tlv,der::Input * out_tbs_cert_list_tlv,der::Input * out_signature_algorithm_tlv,der::BitString * out_signature_value)62 bool ParseCrlCertificateList(der::Input crl_tlv,
63 der::Input *out_tbs_cert_list_tlv,
64 der::Input *out_signature_algorithm_tlv,
65 der::BitString *out_signature_value) {
66 der::Parser parser(crl_tlv);
67
68 // CertificateList ::= SEQUENCE {
69 der::Parser certificate_list_parser;
70 if (!parser.ReadSequence(&certificate_list_parser)) {
71 return false;
72 }
73
74 // tbsCertList TBSCertList
75 if (!certificate_list_parser.ReadRawTLV(out_tbs_cert_list_tlv)) {
76 return false;
77 }
78
79 // signatureAlgorithm AlgorithmIdentifier,
80 if (!certificate_list_parser.ReadRawTLV(out_signature_algorithm_tlv)) {
81 return false;
82 }
83
84 // signatureValue BIT STRING }
85 std::optional<der::BitString> signature_value =
86 certificate_list_parser.ReadBitString();
87 if (!signature_value) {
88 return false;
89 }
90 *out_signature_value = signature_value.value();
91
92 // There isn't an extension point at the end of CertificateList.
93 if (certificate_list_parser.HasMore()) {
94 return false;
95 }
96
97 // By definition the input was a single CertificateList, so there shouldn't be
98 // unconsumed data.
99 if (parser.HasMore()) {
100 return false;
101 }
102
103 return true;
104 }
105
ParseCrlTbsCertList(der::Input tbs_tlv,ParsedCrlTbsCertList * out)106 bool ParseCrlTbsCertList(der::Input tbs_tlv, ParsedCrlTbsCertList *out) {
107 der::Parser parser(tbs_tlv);
108
109 // TBSCertList ::= SEQUENCE {
110 der::Parser tbs_parser;
111 if (!parser.ReadSequence(&tbs_parser)) {
112 return false;
113 }
114
115 // version Version OPTIONAL,
116 // -- if present, MUST be v2
117 std::optional<der::Input> version_der;
118 if (!tbs_parser.ReadOptionalTag(CBS_ASN1_INTEGER, &version_der)) {
119 return false;
120 }
121 if (version_der.has_value()) {
122 uint64_t version64;
123 if (!der::ParseUint64(*version_der, &version64)) {
124 return false;
125 }
126 // If version is present, it MUST be v2(1).
127 if (version64 != 1) {
128 return false;
129 }
130 out->version = CrlVersion::V2;
131 } else {
132 // Uh, RFC 5280 doesn't actually say it anywhere, but presumably if version
133 // is not specified, it is V1.
134 out->version = CrlVersion::V1;
135 }
136
137 // signature AlgorithmIdentifier,
138 if (!tbs_parser.ReadRawTLV(&out->signature_algorithm_tlv)) {
139 return false;
140 }
141
142 // issuer Name,
143 if (!tbs_parser.ReadRawTLV(&out->issuer_tlv)) {
144 return false;
145 }
146
147 // thisUpdate Time,
148 if (!ReadUTCOrGeneralizedTime(&tbs_parser, &out->this_update)) {
149 return false;
150 }
151
152 // nextUpdate Time OPTIONAL,
153 CBS_ASN1_TAG maybe_next_update_tag;
154 der::Input unused_next_update_input;
155 if (tbs_parser.PeekTagAndValue(&maybe_next_update_tag,
156 &unused_next_update_input) &&
157 (maybe_next_update_tag == CBS_ASN1_UTCTIME ||
158 maybe_next_update_tag == CBS_ASN1_GENERALIZEDTIME)) {
159 der::GeneralizedTime next_update_time;
160 if (!ReadUTCOrGeneralizedTime(&tbs_parser, &next_update_time)) {
161 return false;
162 }
163 out->next_update = next_update_time;
164 } else {
165 out->next_update = std::nullopt;
166 }
167
168 // revokedCertificates SEQUENCE OF SEQUENCE { ... } OPTIONAL,
169 der::Input unused_revoked_certificates;
170 CBS_ASN1_TAG maybe_revoked_certifigates_tag;
171 if (tbs_parser.PeekTagAndValue(&maybe_revoked_certifigates_tag,
172 &unused_revoked_certificates) &&
173 maybe_revoked_certifigates_tag == CBS_ASN1_SEQUENCE) {
174 der::Input revoked_certificates_tlv;
175 if (!tbs_parser.ReadRawTLV(&revoked_certificates_tlv)) {
176 return false;
177 }
178 out->revoked_certificates_tlv = revoked_certificates_tlv;
179 } else {
180 out->revoked_certificates_tlv = std::nullopt;
181 }
182
183 // crlExtensions [0] EXPLICIT Extensions OPTIONAL
184 // -- if present, version MUST be v2
185 if (!tbs_parser.ReadOptionalTag(
186 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
187 &out->crl_extensions_tlv)) {
188 return false;
189 }
190 if (out->crl_extensions_tlv.has_value()) {
191 if (out->version != CrlVersion::V2) {
192 return false;
193 }
194 }
195
196 if (tbs_parser.HasMore()) {
197 // Invalid or extraneous elements.
198 return false;
199 }
200
201 // By definition the input was a single sequence, so there shouldn't be
202 // unconsumed data.
203 if (parser.HasMore()) {
204 return false;
205 }
206
207 return true;
208 }
209
ParseIssuingDistributionPoint(der::Input extension_value,std::unique_ptr<GeneralNames> * out_distribution_point_names,ContainedCertsType * out_only_contains_cert_type)210 bool ParseIssuingDistributionPoint(
211 der::Input extension_value,
212 std::unique_ptr<GeneralNames> *out_distribution_point_names,
213 ContainedCertsType *out_only_contains_cert_type) {
214 der::Parser idp_extension_value_parser(extension_value);
215 // IssuingDistributionPoint ::= SEQUENCE {
216 der::Parser idp_parser;
217 if (!idp_extension_value_parser.ReadSequence(&idp_parser)) {
218 return false;
219 }
220
221 // 5.2.5. Conforming CRLs issuers MUST NOT issue CRLs where the DER
222 // encoding of the issuing distribution point extension is an empty
223 // sequence.
224 if (!idp_parser.HasMore()) {
225 return false;
226 }
227
228 // distributionPoint [0] DistributionPointName OPTIONAL,
229 std::optional<der::Input> distribution_point;
230 if (!idp_parser.ReadOptionalTag(
231 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
232 &distribution_point)) {
233 return false;
234 }
235
236 if (distribution_point.has_value()) {
237 // DistributionPointName ::= CHOICE {
238 der::Parser dp_name_parser(*distribution_point);
239 // fullName [0] GeneralNames,
240 // nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
241 std::optional<der::Input> der_full_name;
242 if (!dp_name_parser.ReadOptionalTag(
243 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
244 &der_full_name)) {
245 return false;
246 }
247 if (!der_full_name) {
248 // Only fullName is supported.
249 return false;
250 }
251 CertErrors errors;
252 *out_distribution_point_names =
253 GeneralNames::CreateFromValue(*der_full_name, &errors);
254 if (!*out_distribution_point_names) {
255 return false;
256 }
257
258 if (dp_name_parser.HasMore()) {
259 // CHOICE represents a single value.
260 return false;
261 }
262 }
263
264 *out_only_contains_cert_type = ContainedCertsType::ANY_CERTS;
265
266 // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
267 std::optional<der::Input> only_contains_user_certs;
268 if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 1,
269 &only_contains_user_certs)) {
270 return false;
271 }
272 if (only_contains_user_certs.has_value()) {
273 bool bool_value;
274 if (!der::ParseBool(*only_contains_user_certs, &bool_value)) {
275 return false;
276 }
277 if (!bool_value) {
278 return false; // DER-encoding requires DEFAULT values be omitted.
279 }
280 *out_only_contains_cert_type = ContainedCertsType::USER_CERTS;
281 }
282
283 // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
284 std::optional<der::Input> only_contains_ca_certs;
285 if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 2,
286 &only_contains_ca_certs)) {
287 return false;
288 }
289 if (only_contains_ca_certs.has_value()) {
290 bool bool_value;
291 if (!der::ParseBool(*only_contains_ca_certs, &bool_value)) {
292 return false;
293 }
294 if (!bool_value) {
295 return false; // DER-encoding requires DEFAULT values be omitted.
296 }
297 if (*out_only_contains_cert_type != ContainedCertsType::ANY_CERTS) {
298 // 5.2.5. at most one of onlyContainsUserCerts, onlyContainsCACerts,
299 // and onlyContainsAttributeCerts may be set to TRUE.
300 return false;
301 }
302 *out_only_contains_cert_type = ContainedCertsType::CA_CERTS;
303 }
304
305 // onlySomeReasons [3] ReasonFlags OPTIONAL,
306 // indirectCRL [4] BOOLEAN DEFAULT FALSE,
307 // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
308 // onlySomeReasons, indirectCRL, and onlyContainsAttributeCerts are not
309 // supported, fail parsing if they are present.
310 if (idp_parser.HasMore()) {
311 return false;
312 }
313
314 return true;
315 }
316
GetCRLStatusForCert(der::Input cert_serial,CrlVersion crl_version,const std::optional<der::Input> & revoked_certificates_tlv)317 CRLRevocationStatus GetCRLStatusForCert(
318 der::Input cert_serial, CrlVersion crl_version,
319 const std::optional<der::Input> &revoked_certificates_tlv) {
320 if (!revoked_certificates_tlv.has_value()) {
321 // RFC 5280 Section 5.1.2.6: "When there are no revoked certificates, the
322 // revoked certificates list MUST be absent."
323 // No covered certificates are revoked, therefore the cert is good.
324 return CRLRevocationStatus::GOOD;
325 }
326
327 der::Parser parser(*revoked_certificates_tlv);
328
329 // revokedCertificates SEQUENCE OF SEQUENCE {
330 der::Parser revoked_certificates_parser;
331 if (!parser.ReadSequence(&revoked_certificates_parser)) {
332 return CRLRevocationStatus::UNKNOWN;
333 }
334
335 // RFC 5280 Section 5.1.2.6: "When there are no revoked certificates, the
336 // revoked certificates list MUST be absent."
337 if (!revoked_certificates_parser.HasMore()) {
338 return CRLRevocationStatus::UNKNOWN;
339 }
340
341 // By definition the input was a single Extensions sequence, so there
342 // shouldn't be unconsumed data.
343 if (parser.HasMore()) {
344 return CRLRevocationStatus::UNKNOWN;
345 }
346
347 bool found_matching_serial = false;
348
349 while (revoked_certificates_parser.HasMore()) {
350 // revokedCertificates SEQUENCE OF SEQUENCE {
351 der::Parser crl_entry_parser;
352 if (!revoked_certificates_parser.ReadSequence(&crl_entry_parser)) {
353 return CRLRevocationStatus::UNKNOWN;
354 }
355
356 der::Input revoked_cert_serial_number;
357 // userCertificate CertificateSerialNumber,
358 if (!crl_entry_parser.ReadTag(CBS_ASN1_INTEGER,
359 &revoked_cert_serial_number)) {
360 return CRLRevocationStatus::UNKNOWN;
361 }
362
363 // revocationDate Time,
364 der::GeneralizedTime unused_revocation_date;
365 if (!ReadUTCOrGeneralizedTime(&crl_entry_parser, &unused_revocation_date)) {
366 return CRLRevocationStatus::UNKNOWN;
367 }
368
369 // crlEntryExtensions Extensions OPTIONAL
370 if (crl_entry_parser.HasMore()) {
371 // -- if present, version MUST be v2
372 if (crl_version != CrlVersion::V2) {
373 return CRLRevocationStatus::UNKNOWN;
374 }
375
376 der::Input crl_entry_extensions_tlv;
377 if (!crl_entry_parser.ReadRawTLV(&crl_entry_extensions_tlv)) {
378 return CRLRevocationStatus::UNKNOWN;
379 }
380
381 std::map<der::Input, ParsedExtension> extensions;
382 if (!ParseExtensions(crl_entry_extensions_tlv, &extensions)) {
383 return CRLRevocationStatus::UNKNOWN;
384 }
385
386 // RFC 5280 Section 5.3: "If a CRL contains a critical CRL entry
387 // extension that the application cannot process, then the application
388 // MUST NOT use that CRL to determine the status of any certificates."
389 for (const auto &ext : extensions) {
390 if (ext.second.critical) {
391 return CRLRevocationStatus::UNKNOWN;
392 }
393 }
394 }
395
396 if (crl_entry_parser.HasMore()) {
397 return CRLRevocationStatus::UNKNOWN;
398 }
399
400 if (revoked_cert_serial_number == cert_serial) {
401 // Cert is revoked, but can't return yet since there might be critical
402 // extensions on later entries that would prevent use of this CRL.
403 found_matching_serial = true;
404 }
405 }
406
407 if (found_matching_serial) {
408 return CRLRevocationStatus::REVOKED;
409 }
410
411 // |cert| is not present in the revokedCertificates list.
412 return CRLRevocationStatus::GOOD;
413 }
414
415 ParsedCrlTbsCertList::ParsedCrlTbsCertList() = default;
416 ParsedCrlTbsCertList::~ParsedCrlTbsCertList() = default;
417
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)418 CRLRevocationStatus CheckCRL(std::string_view raw_crl,
419 const ParsedCertificateList &valid_chain,
420 size_t target_cert_index,
421 const ParsedDistributionPoint &cert_dp,
422 int64_t verify_time_epoch_seconds,
423 std::optional<int64_t> max_age_seconds) {
424 BSSL_CHECK(target_cert_index < valid_chain.size());
425
426 if (cert_dp.reasons) {
427 // Reason codes are not supported. If the distribution point contains a
428 // subset of reasons then skip it. We aren't interested in subsets of CRLs
429 // and the RFC states that there MUST be a CRL that covers all reasons.
430 return CRLRevocationStatus::UNKNOWN;
431 }
432 if (cert_dp.crl_issuer) {
433 // Indirect CRLs are not supported.
434 return CRLRevocationStatus::UNKNOWN;
435 }
436
437 const ParsedCertificate *target_cert = valid_chain[target_cert_index].get();
438
439 // 6.3.3 (a) Update the local CRL cache by obtaining a complete CRL, a
440 // delta CRL, or both, as required.
441 //
442 // This implementation only supports complete CRLs and takes the CRL as
443 // input, it is up to the caller to provide an up to date CRL.
444
445 der::Input tbs_cert_list_tlv;
446 der::Input signature_algorithm_tlv;
447 der::BitString signature_value;
448 if (!ParseCrlCertificateList(StringAsBytes(raw_crl), &tbs_cert_list_tlv,
449 &signature_algorithm_tlv, &signature_value)) {
450 return CRLRevocationStatus::UNKNOWN;
451 }
452
453 ParsedCrlTbsCertList tbs_cert_list;
454 if (!ParseCrlTbsCertList(tbs_cert_list_tlv, &tbs_cert_list)) {
455 return CRLRevocationStatus::UNKNOWN;
456 }
457
458 // 5.1.1.2 signatureAlgorithm
459 //
460 // TODO(https://crbug.com/749276): Check the signature algorithm against
461 // policy.
462 std::optional<SignatureAlgorithm> signature_algorithm =
463 ParseSignatureAlgorithm(signature_algorithm_tlv);
464 if (!signature_algorithm) {
465 return CRLRevocationStatus::UNKNOWN;
466 }
467
468 // This field MUST contain the same algorithm identifier as the
469 // signature field in the sequence tbsCertList (Section 5.1.2.2).
470 std::optional<SignatureAlgorithm> tbs_alg =
471 ParseSignatureAlgorithm(tbs_cert_list.signature_algorithm_tlv);
472 if (!tbs_alg || *signature_algorithm != *tbs_alg) {
473 return CRLRevocationStatus::UNKNOWN;
474 }
475
476 // Check CRL dates. Roughly corresponds to 6.3.3 (a) (1) but does not attempt
477 // to update the CRL if it is out of date.
478 if (!CheckRevocationDateValid(tbs_cert_list.this_update,
479 tbs_cert_list.next_update.has_value()
480 ? &tbs_cert_list.next_update.value()
481 : nullptr,
482 verify_time_epoch_seconds, max_age_seconds)) {
483 return CRLRevocationStatus::UNKNOWN;
484 }
485
486 // 6.3.3 (a) (2) is skipped: This implementation does not support delta CRLs.
487
488 // 6.3.3 (b) Verify the issuer and scope of the complete CRL as follows:
489 // 6.3.3 (b) (1) If the DP includes cRLIssuer, then verify that the issuer
490 // field in the complete CRL matches cRLIssuer in the DP and
491 // that the complete CRL contains an issuing distribution
492 // point extension with the indirectCRL boolean asserted.
493 //
494 // Nothing is done here since distribution points with crlIssuer were skipped
495 // above.
496
497 // 6.3.3 (b) (1) Otherwise, verify that the CRL issuer matches the
498 // certificate issuer.
499 //
500 // Normalization for the name comparison is used although the RFC is not
501 // clear on this. There are several places that explicitly are called out as
502 // requiring identical encodings:
503 //
504 // 4.2.1.13. CRL Distribution Points (cert extension) says the DP cRLIssuer
505 // field MUST be exactly the same as the encoding in issuer field of the
506 // CRL.
507 //
508 // 5.2.5. Issuing Distribution Point (crl extension)
509 // The identical encoding MUST be used in the distributionPoint fields
510 // of the certificate and the CRL.
511 //
512 // 5.3.3. Certificate Issuer (crl entry extension) also says "The encoding of
513 // the DN MUST be identical to the encoding used in the certificate"
514 //
515 // But 6.3.3 (b) (1) just says "matches". Also NIST PKITS includes at least
516 // one test that requires normalization here.
517 // TODO(https://crbug.com/749276): could do exact comparison first and only
518 // fall back to normalizing if that fails.
519 std::string normalized_crl_issuer;
520 if (!NormalizeNameTLV(tbs_cert_list.issuer_tlv, &normalized_crl_issuer)) {
521 return CRLRevocationStatus::UNKNOWN;
522 }
523 if (der::Input(StringAsBytes(normalized_crl_issuer)) !=
524 target_cert->normalized_issuer()) {
525 return CRLRevocationStatus::UNKNOWN;
526 }
527
528 if (tbs_cert_list.crl_extensions_tlv.has_value()) {
529 std::map<der::Input, ParsedExtension> extensions;
530 if (!ParseExtensions(*tbs_cert_list.crl_extensions_tlv, &extensions)) {
531 return CRLRevocationStatus::UNKNOWN;
532 }
533
534 // 6.3.3 (b) (2) If the complete CRL includes an issuing distribution point
535 // (IDP) CRL extension, check the following:
536 ParsedExtension idp_extension;
537 if (ConsumeExtension(der::Input(kIssuingDistributionPointOid), &extensions,
538 &idp_extension)) {
539 std::unique_ptr<GeneralNames> distribution_point_names;
540 ContainedCertsType only_contains_cert_type;
541 if (!ParseIssuingDistributionPoint(idp_extension.value,
542 &distribution_point_names,
543 &only_contains_cert_type)) {
544 return CRLRevocationStatus::UNKNOWN;
545 }
546
547 if (distribution_point_names) {
548 // 6.3.3. (b) (2) (i) If the distribution point name is present in the
549 // IDP CRL extension and the distribution field is
550 // present in the DP, then verify that one of the
551 // names in the IDP matches one of the names in the
552 // DP.
553 // 5.2.5. The identical encoding MUST be used in the distributionPoint
554 // fields of the certificate and the CRL.
555 // TODO(https://crbug.com/749276): Check other name types?
556 if (!cert_dp.distribution_point_fullname ||
557 !ContainsExactMatchingName(
558 cert_dp.distribution_point_fullname
559 ->uniform_resource_identifiers,
560 distribution_point_names->uniform_resource_identifiers)) {
561 return CRLRevocationStatus::UNKNOWN;
562 }
563
564 // 6.3.3. (b) (2) (i) If the distribution point name is present in the
565 // IDP CRL extension and the distribution field is
566 // omitted from the DP, then verify that one of the
567 // names in the IDP matches one of the names in the
568 // cRLIssuer field of the DP.
569 // Indirect CRLs are not supported, if indirectCRL was specified,
570 // ParseIssuingDistributionPoint would already have failed.
571 }
572
573 switch (only_contains_cert_type) {
574 case ContainedCertsType::USER_CERTS:
575 // 6.3.3. (b) (2) (ii) If the onlyContainsUserCerts boolean is
576 // asserted in the IDP CRL extension, verify
577 // that the certificate does not include the
578 // basic constraints extension with the cA
579 // boolean asserted.
580 // 5.2.5. If either onlyContainsUserCerts or onlyContainsCACerts is
581 // set to TRUE, then the scope of the CRL MUST NOT include any
582 // version 1 or version 2 certificates.
583 if ((target_cert->has_basic_constraints() &&
584 target_cert->basic_constraints().is_ca) ||
585 target_cert->tbs().version == CertificateVersion::V1 ||
586 target_cert->tbs().version == CertificateVersion::V2) {
587 return CRLRevocationStatus::UNKNOWN;
588 }
589 break;
590
591 case ContainedCertsType::CA_CERTS:
592 // 6.3.3. (b) (2) (iii) If the onlyContainsCACerts boolean is asserted
593 // in the IDP CRL extension, verify that the
594 // certificate includes the basic constraints
595 // extension with the cA boolean asserted.
596 // The version check is not done here, as the basicConstraints
597 // extension is required, and could not be present unless it is a V3
598 // certificate.
599 if (!target_cert->has_basic_constraints() ||
600 !target_cert->basic_constraints().is_ca) {
601 return CRLRevocationStatus::UNKNOWN;
602 }
603 break;
604
605 case ContainedCertsType::ANY_CERTS:
606 // (iv) Verify that the onlyContainsAttributeCerts
607 // boolean is not asserted.
608 // If onlyContainsAttributeCerts was present,
609 // ParseIssuingDistributionPoint would already have failed.
610 break;
611 }
612 }
613
614 for (const auto &ext : extensions) {
615 // Fail if any unhandled critical CRL extensions are present.
616 if (ext.second.critical) {
617 return CRLRevocationStatus::UNKNOWN;
618 }
619 }
620 }
621
622 // 6.3.3 (c-e) skipped: delta CRLs and reason codes are not supported.
623
624 // This implementation only supports direct CRLs where the CRL was signed by
625 // one of the certs in its validated issuer chain. This allows handling some
626 // cases of key rollover without requiring additional CRL issuer cert
627 // discovery & path building.
628 // TODO(https://crbug.com/749276): should this loop start at
629 // |target_cert_index|? There doesn't seem to be anything in the specs that
630 // precludes a CRL signed by a self-issued cert from covering itself. On the
631 // other hand it seems like a pretty weird thing to allow and causes NIST
632 // PKITS 4.5.3 to pass when it seems like it would not be intended to (since
633 // issuingDistributionPoint CRL extension is not handled).
634 for (size_t i = target_cert_index + 1; i < valid_chain.size(); ++i) {
635 const ParsedCertificate *issuer_cert = valid_chain[i].get();
636
637 // 6.3.3 (f) Obtain and validate the certification path for the issuer of
638 // the complete CRL. The trust anchor for the certification
639 // path MUST be the same as the trust anchor used to validate
640 // the target certificate.
641 //
642 // As the |issuer_cert| is from the already validated chain, it is already
643 // known to chain to the same trust anchor as the target certificate.
644 if (der::Input(StringAsBytes(normalized_crl_issuer)) !=
645 issuer_cert->normalized_subject()) {
646 continue;
647 }
648
649 // 6.3.3 (f) If a key usage extension is present in the CRL issuer's
650 // certificate, verify that the cRLSign bit is set.
651 if (issuer_cert->has_key_usage() &&
652 !issuer_cert->key_usage().AssertsBit(KEY_USAGE_BIT_CRL_SIGN)) {
653 continue;
654 }
655
656 // 6.3.3 (g) Validate the signature on the complete CRL using the public
657 // key validated in step (f).
658 if (!VerifySignedData(*signature_algorithm, tbs_cert_list_tlv,
659 signature_value, issuer_cert->tbs().spki_tlv,
660 /*cache=*/nullptr)) {
661 continue;
662 }
663
664 // 6.3.3 (h,i) skipped. This implementation does not support delta CRLs.
665
666 // 6.3.3 (j) If (cert_status is UNREVOKED), then search for the
667 // certificate on the complete CRL. If an entry is found that
668 // matches the certificate issuer and serial number as described
669 // in Section 5.3.3, then set the cert_status variable to the
670 // indicated reason as described in step (i).
671 //
672 // CRL is valid and covers |target_cert|, check if |target_cert| is present
673 // in the revokedCertificates sequence.
674 return GetCRLStatusForCert(target_cert->tbs().serial_number,
675 tbs_cert_list.version,
676 tbs_cert_list.revoked_certificates_tlv);
677
678 // 6.3.3 (k,l) skipped. This implementation does not support reason codes.
679 }
680
681 // Did not find the issuer & signer of |raw_crl| in |valid_chain|.
682 return CRLRevocationStatus::UNKNOWN;
683 }
684
685 BSSL_NAMESPACE_END
686