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