xref: /aosp_15_r20/external/cronet/third_party/boringssl/src/pki/crl.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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