Coverage Report

Created: 2025-08-28 06:59

/src/boringssl/pki/crl.cc
Line
Count
Source (jump to first uncovered line)
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
40
[[nodiscard]] bool NormalizeNameTLV(der::Input name_tlv,
41
0
                                    std::string *out_normalized_name) {
42
0
  der::Parser parser(name_tlv);
43
0
  der::Input name_rdn;
44
0
  bssl::CertErrors unused_errors;
45
0
  return parser.ReadTag(CBS_ASN1_SEQUENCE, &name_rdn) &&
46
0
         NormalizeName(name_rdn, out_normalized_name, &unused_errors) &&
47
0
         !parser.HasMore();
48
0
}
49
50
bool ContainsExactMatchingName(std::vector<std::string_view> a,
51
0
                               std::vector<std::string_view> b) {
52
0
  std::sort(a.begin(), a.end());
53
0
  std::sort(b.begin(), b.end());
54
0
  std::vector<std::string_view> names_in_common;
55
0
  std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
56
0
                        std::back_inserter(names_in_common));
57
0
  return !names_in_common.empty();
58
0
}
59
60
}  // namespace
61
62
bool ParseCrlCertificateList(der::Input crl_tlv,
63
                             der::Input *out_tbs_cert_list_tlv,
64
                             der::Input *out_signature_algorithm_tlv,
65
690
                             der::BitString *out_signature_value) {
66
690
  der::Parser parser(crl_tlv);
67
68
  //   CertificateList  ::=  SEQUENCE  {
69
690
  der::Parser certificate_list_parser;
70
690
  if (!parser.ReadSequence(&certificate_list_parser)) {
71
530
    return false;
72
530
  }
73
74
  //        tbsCertList          TBSCertList
75
160
  if (!certificate_list_parser.ReadRawTLV(out_tbs_cert_list_tlv)) {
76
35
    return false;
77
35
  }
78
79
  //        signatureAlgorithm   AlgorithmIdentifier,
80
125
  if (!certificate_list_parser.ReadRawTLV(out_signature_algorithm_tlv)) {
81
17
    return false;
82
17
  }
83
84
  //        signatureValue       BIT STRING  }
85
108
  std::optional<der::BitString> signature_value =
86
108
      certificate_list_parser.ReadBitString();
87
108
  if (!signature_value) {
88
52
    return false;
89
52
  }
90
56
  *out_signature_value = signature_value.value();
91
92
  // There isn't an extension point at the end of CertificateList.
93
56
  if (certificate_list_parser.HasMore()) {
94
13
    return false;
95
13
  }
96
97
  // By definition the input was a single CertificateList, so there shouldn't be
98
  // unconsumed data.
99
43
  if (parser.HasMore()) {
100
22
    return false;
101
22
  }
102
103
21
  return true;
104
43
}
105
106
1.49k
bool ParseCrlTbsCertList(der::Input tbs_tlv, ParsedCrlTbsCertList *out) {
107
1.49k
  der::Parser parser(tbs_tlv);
108
109
  //   TBSCertList  ::=  SEQUENCE  {
110
1.49k
  der::Parser tbs_parser;
111
1.49k
  if (!parser.ReadSequence(&tbs_parser)) {
112
537
    return false;
113
537
  }
114
115
  //         version                 Version OPTIONAL,
116
  //                                      -- if present, MUST be v2
117
958
  std::optional<der::Input> version_der;
118
958
  if (!tbs_parser.ReadOptionalTag(CBS_ASN1_INTEGER, &version_der)) {
119
17
    return false;
120
17
  }
121
941
  if (version_der.has_value()) {
122
228
    uint64_t version64;
123
228
    if (!der::ParseUint64(*version_der, &version64)) {
124
85
      return false;
125
85
    }
126
    // If version is present, it MUST be v2(1).
127
143
    if (version64 != 1) {
128
135
      return false;
129
135
    }
130
8
    out->version = CrlVersion::V2;
131
713
  } else {
132
    // Uh, RFC 5280 doesn't actually say it anywhere, but presumably if version
133
    // is not specified, it is V1.
134
713
    out->version = CrlVersion::V1;
135
713
  }
136
137
  //         signature               AlgorithmIdentifier,
138
721
  if (!tbs_parser.ReadRawTLV(&out->signature_algorithm_tlv)) {
139
21
    return false;
140
21
  }
141
142
  //         issuer                  Name,
143
700
  if (!tbs_parser.ReadRawTLV(&out->issuer_tlv)) {
144
69
    return false;
145
69
  }
146
147
  //         thisUpdate              Time,
148
631
  if (!ReadUTCOrGeneralizedTime(&tbs_parser, &out->this_update)) {
149
387
    return false;
150
387
  }
151
152
  //         nextUpdate              Time OPTIONAL,
153
244
  CBS_ASN1_TAG maybe_next_update_tag;
154
244
  der::Input unused_next_update_input;
155
244
  if (tbs_parser.PeekTagAndValue(&maybe_next_update_tag,
156
244
                                 &unused_next_update_input) &&
157
244
      (maybe_next_update_tag == CBS_ASN1_UTCTIME ||
158
172
       maybe_next_update_tag == CBS_ASN1_GENERALIZEDTIME)) {
159
59
    der::GeneralizedTime next_update_time;
160
59
    if (!ReadUTCOrGeneralizedTime(&tbs_parser, &next_update_time)) {
161
32
      return false;
162
32
    }
163
27
    out->next_update = next_update_time;
164
185
  } else {
165
185
    out->next_update = std::nullopt;
166
185
  }
167
168
  //         revokedCertificates     SEQUENCE OF SEQUENCE  { ... } OPTIONAL,
169
212
  der::Input unused_revoked_certificates;
170
212
  CBS_ASN1_TAG maybe_revoked_certifigates_tag;
171
212
  if (tbs_parser.PeekTagAndValue(&maybe_revoked_certifigates_tag,
172
212
                                 &unused_revoked_certificates) &&
173
212
      maybe_revoked_certifigates_tag == CBS_ASN1_SEQUENCE) {
174
4
    der::Input revoked_certificates_tlv;
175
4
    if (!tbs_parser.ReadRawTLV(&revoked_certificates_tlv)) {
176
0
      return false;
177
0
    }
178
4
    out->revoked_certificates_tlv = revoked_certificates_tlv;
179
208
  } else {
180
208
    out->revoked_certificates_tlv = std::nullopt;
181
208
  }
182
183
  //         crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
184
  //                                       -- if present, version MUST be v2
185
212
  if (!tbs_parser.ReadOptionalTag(
186
212
          CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
187
212
          &out->crl_extensions_tlv)) {
188
39
    return false;
189
39
  }
190
173
  if (out->crl_extensions_tlv.has_value()) {
191
2
    if (out->version != CrlVersion::V2) {
192
1
      return false;
193
1
    }
194
2
  }
195
196
172
  if (tbs_parser.HasMore()) {
197
    // Invalid or extraneous elements.
198
107
    return false;
199
107
  }
200
201
  // By definition the input was a single sequence, so there shouldn't be
202
  // unconsumed data.
203
65
  if (parser.HasMore()) {
204
16
    return false;
205
16
  }
206
207
49
  return true;
208
65
}
209
210
bool ParseIssuingDistributionPoint(
211
    der::Input extension_value,
212
    std::unique_ptr<GeneralNames> *out_distribution_point_names,
213
1.06k
    ContainedCertsType *out_only_contains_cert_type) {
214
1.06k
  der::Parser idp_extension_value_parser(extension_value);
215
  // IssuingDistributionPoint ::= SEQUENCE {
216
1.06k
  der::Parser idp_parser;
217
1.06k
  if (!idp_extension_value_parser.ReadSequence(&idp_parser)) {
218
519
    return false;
219
519
  }
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
548
  if (!idp_parser.HasMore()) {
225
16
    return false;
226
16
  }
227
228
  //  distributionPoint          [0] DistributionPointName OPTIONAL,
229
532
  std::optional<der::Input> distribution_point;
230
532
  if (!idp_parser.ReadOptionalTag(
231
532
          CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
232
532
          &distribution_point)) {
233
25
    return false;
234
25
  }
235
236
507
  if (distribution_point.has_value()) {
237
    //   DistributionPointName ::= CHOICE {
238
399
    der::Parser dp_name_parser(*distribution_point);
239
    //        fullName                [0]     GeneralNames,
240
    //        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
241
399
    std::optional<der::Input> der_full_name;
242
399
    if (!dp_name_parser.ReadOptionalTag(
243
399
            CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0,
244
399
            &der_full_name)) {
245
4
      return false;
246
4
    }
247
395
    if (!der_full_name) {
248
      // Only fullName is supported.
249
4
      return false;
250
4
    }
251
391
    CertErrors errors;
252
391
    *out_distribution_point_names =
253
391
        GeneralNames::CreateFromValue(*der_full_name, &errors);
254
391
    if (!*out_distribution_point_names) {
255
234
      return false;
256
234
    }
257
258
157
    if (dp_name_parser.HasMore()) {
259
      // CHOICE represents a single value.
260
4
      return false;
261
4
    }
262
157
  }
263
264
261
  *out_only_contains_cert_type = ContainedCertsType::ANY_CERTS;
265
266
  //  onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
267
261
  std::optional<der::Input> only_contains_user_certs;
268
261
  if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 1,
269
261
                                  &only_contains_user_certs)) {
270
3
    return false;
271
3
  }
272
258
  if (only_contains_user_certs.has_value()) {
273
26
    bool bool_value;
274
26
    if (!der::ParseBool(*only_contains_user_certs, &bool_value)) {
275
19
      return false;
276
19
    }
277
7
    if (!bool_value) {
278
1
      return false;  // DER-encoding requires DEFAULT values be omitted.
279
1
    }
280
6
    *out_only_contains_cert_type = ContainedCertsType::USER_CERTS;
281
6
  }
282
283
  //  onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
284
238
  std::optional<der::Input> only_contains_ca_certs;
285
238
  if (!idp_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 2,
286
238
                                  &only_contains_ca_certs)) {
287
1
    return false;
288
1
  }
289
237
  if (only_contains_ca_certs.has_value()) {
290
38
    bool bool_value;
291
38
    if (!der::ParseBool(*only_contains_ca_certs, &bool_value)) {
292
29
      return false;
293
29
    }
294
9
    if (!bool_value) {
295
6
      return false;  // DER-encoding requires DEFAULT values be omitted.
296
6
    }
297
3
    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
1
      return false;
301
1
    }
302
2
    *out_only_contains_cert_type = ContainedCertsType::CA_CERTS;
303
2
  }
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
201
  if (idp_parser.HasMore()) {
311
57
    return false;
312
57
  }
313
314
144
  return true;
315
201
}
316
317
CRLRevocationStatus GetCRLStatusForCert(
318
    der::Input cert_serial, CrlVersion crl_version,
319
1.49k
    const std::optional<der::Input> &revoked_certificates_tlv) {
320
1.49k
  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
0
    return CRLRevocationStatus::GOOD;
325
0
  }
326
327
1.49k
  der::Parser parser(*revoked_certificates_tlv);
328
329
  //         revokedCertificates     SEQUENCE OF SEQUENCE  {
330
1.49k
  der::Parser revoked_certificates_parser;
331
1.49k
  if (!parser.ReadSequence(&revoked_certificates_parser)) {
332
515
    return CRLRevocationStatus::UNKNOWN;
333
515
  }
334
335
  // RFC 5280 Section 5.1.2.6: "When there are no revoked certificates, the
336
  // revoked certificates list MUST be absent."
337
975
  if (!revoked_certificates_parser.HasMore()) {
338
18
    return CRLRevocationStatus::UNKNOWN;
339
18
  }
340
341
  // By definition the input was a single Extensions sequence, so there
342
  // shouldn't be unconsumed data.
343
957
  if (parser.HasMore()) {
344
52
    return CRLRevocationStatus::UNKNOWN;
345
52
  }
346
347
905
  bool found_matching_serial = false;
348
349
8.64k
  while (revoked_certificates_parser.HasMore()) {
350
    //         revokedCertificates     SEQUENCE OF SEQUENCE  {
351
8.45k
    der::Parser crl_entry_parser;
352
8.45k
    if (!revoked_certificates_parser.ReadSequence(&crl_entry_parser)) {
353
89
      return CRLRevocationStatus::UNKNOWN;
354
89
    }
355
356
8.36k
    der::Input revoked_cert_serial_number;
357
    //              userCertificate         CertificateSerialNumber,
358
8.36k
    if (!crl_entry_parser.ReadTag(CBS_ASN1_INTEGER,
359
8.36k
                                  &revoked_cert_serial_number)) {
360
17
      return CRLRevocationStatus::UNKNOWN;
361
17
    }
362
363
    //              revocationDate          Time,
364
8.34k
    der::GeneralizedTime unused_revocation_date;
365
8.34k
    if (!ReadUTCOrGeneralizedTime(&crl_entry_parser, &unused_revocation_date)) {
366
434
      return CRLRevocationStatus::UNKNOWN;
367
434
    }
368
369
    //              crlEntryExtensions      Extensions OPTIONAL
370
7.91k
    if (crl_entry_parser.HasMore()) {
371
      //                                       -- if present, version MUST be v2
372
1.47k
      if (crl_version != CrlVersion::V2) {
373
1
        return CRLRevocationStatus::UNKNOWN;
374
1
      }
375
376
1.47k
      der::Input crl_entry_extensions_tlv;
377
1.47k
      if (!crl_entry_parser.ReadRawTLV(&crl_entry_extensions_tlv)) {
378
3
        return CRLRevocationStatus::UNKNOWN;
379
3
      }
380
381
1.47k
      std::map<der::Input, ParsedExtension> extensions;
382
1.47k
      if (!ParseExtensions(crl_entry_extensions_tlv, &extensions)) {
383
148
        return CRLRevocationStatus::UNKNOWN;
384
148
      }
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
10.5k
      for (const auto &ext : extensions) {
390
10.5k
        if (ext.second.critical) {
391
3
          return CRLRevocationStatus::UNKNOWN;
392
3
        }
393
10.5k
      }
394
1.32k
    }
395
396
7.75k
    if (crl_entry_parser.HasMore()) {
397
13
      return CRLRevocationStatus::UNKNOWN;
398
13
    }
399
400
7.74k
    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
446
      found_matching_serial = true;
404
446
    }
405
7.74k
  }
406
407
197
  if (found_matching_serial) {
408
35
    return CRLRevocationStatus::REVOKED;
409
35
  }
410
411
  // |cert| is not present in the revokedCertificates list.
412
162
  return CRLRevocationStatus::GOOD;
413
197
}
414
415
1.49k
ParsedCrlTbsCertList::ParsedCrlTbsCertList() = default;
416
1.49k
ParsedCrlTbsCertList::~ParsedCrlTbsCertList() = default;
417
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
0
                             std::optional<int64_t> max_age_seconds) {
424
0
  BSSL_CHECK(target_cert_index < valid_chain.size());
425
426
0
  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
0
    return CRLRevocationStatus::UNKNOWN;
431
0
  }
432
0
  if (cert_dp.crl_issuer) {
433
    // Indirect CRLs are not supported.
434
0
    return CRLRevocationStatus::UNKNOWN;
435
0
  }
436
437
0
  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
0
  der::Input tbs_cert_list_tlv;
446
0
  der::Input signature_algorithm_tlv;
447
0
  der::BitString signature_value;
448
0
  if (!ParseCrlCertificateList(StringAsBytes(raw_crl), &tbs_cert_list_tlv,
449
0
                               &signature_algorithm_tlv, &signature_value)) {
450
0
    return CRLRevocationStatus::UNKNOWN;
451
0
  }
452
453
0
  ParsedCrlTbsCertList tbs_cert_list;
454
0
  if (!ParseCrlTbsCertList(tbs_cert_list_tlv, &tbs_cert_list)) {
455
0
    return CRLRevocationStatus::UNKNOWN;
456
0
  }
457
458
  // 5.1.1.2  signatureAlgorithm
459
  //
460
  // TODO(https://crbug.com/749276): Check the signature algorithm against
461
  // policy.
462
0
  std::optional<SignatureAlgorithm> signature_algorithm =
463
0
      ParseSignatureAlgorithm(signature_algorithm_tlv);
464
0
  if (!signature_algorithm) {
465
0
    return CRLRevocationStatus::UNKNOWN;
466
0
  }
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
0
  std::optional<SignatureAlgorithm> tbs_alg =
471
0
      ParseSignatureAlgorithm(tbs_cert_list.signature_algorithm_tlv);
472
0
  if (!tbs_alg || *signature_algorithm != *tbs_alg) {
473
0
    return CRLRevocationStatus::UNKNOWN;
474
0
  }
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
0
  if (!CheckRevocationDateValid(tbs_cert_list.this_update,
479
0
                                tbs_cert_list.next_update.has_value()
480
0
                                    ? &tbs_cert_list.next_update.value()
481
0
                                    : nullptr,
482
0
                                verify_time_epoch_seconds, max_age_seconds)) {
483
0
    return CRLRevocationStatus::UNKNOWN;
484
0
  }
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
0
  std::string normalized_crl_issuer;
520
0
  if (!NormalizeNameTLV(tbs_cert_list.issuer_tlv, &normalized_crl_issuer)) {
521
0
    return CRLRevocationStatus::UNKNOWN;
522
0
  }
523
0
  if (der::Input(StringAsBytes(normalized_crl_issuer)) !=
524
0
      target_cert->normalized_issuer()) {
525
0
    return CRLRevocationStatus::UNKNOWN;
526
0
  }
527
528
0
  if (tbs_cert_list.crl_extensions_tlv.has_value()) {
529
0
    std::map<der::Input, ParsedExtension> extensions;
530
0
    if (!ParseExtensions(*tbs_cert_list.crl_extensions_tlv, &extensions)) {
531
0
      return CRLRevocationStatus::UNKNOWN;
532
0
    }
533
534
    // 6.3.3 (b) (2) If the complete CRL includes an issuing distribution point
535
    //               (IDP) CRL extension, check the following:
536
0
    ParsedExtension idp_extension;
537
0
    if (ConsumeExtension(der::Input(kIssuingDistributionPointOid), &extensions,
538
0
                         &idp_extension)) {
539
0
      std::unique_ptr<GeneralNames> distribution_point_names;
540
0
      ContainedCertsType only_contains_cert_type;
541
0
      if (!ParseIssuingDistributionPoint(idp_extension.value,
542
0
                                         &distribution_point_names,
543
0
                                         &only_contains_cert_type)) {
544
0
        return CRLRevocationStatus::UNKNOWN;
545
0
      }
546
547
0
      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
0
        if (!cert_dp.distribution_point_fullname ||
557
0
            !ContainsExactMatchingName(
558
0
                cert_dp.distribution_point_fullname
559
0
                    ->uniform_resource_identifiers,
560
0
                distribution_point_names->uniform_resource_identifiers)) {
561
0
          return CRLRevocationStatus::UNKNOWN;
562
0
        }
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
0
      }
572
573
0
      switch (only_contains_cert_type) {
574
0
        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
0
          if ((target_cert->has_basic_constraints() &&
584
0
               target_cert->basic_constraints().is_ca) ||
585
0
              target_cert->tbs().version == CertificateVersion::V1 ||
586
0
              target_cert->tbs().version == CertificateVersion::V2) {
587
0
            return CRLRevocationStatus::UNKNOWN;
588
0
          }
589
0
          break;
590
591
0
        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
0
          if (!target_cert->has_basic_constraints() ||
600
0
              !target_cert->basic_constraints().is_ca) {
601
0
            return CRLRevocationStatus::UNKNOWN;
602
0
          }
603
0
          break;
604
605
0
        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
0
          break;
611
0
      }
612
0
    }
613
614
0
    for (const auto &ext : extensions) {
615
      // Fail if any unhandled critical CRL extensions are present.
616
0
      if (ext.second.critical) {
617
0
        return CRLRevocationStatus::UNKNOWN;
618
0
      }
619
0
    }
620
0
  }
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
0
  for (size_t i = target_cert_index + 1; i < valid_chain.size(); ++i) {
635
0
    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
0
    if (der::Input(StringAsBytes(normalized_crl_issuer)) !=
645
0
        issuer_cert->normalized_subject()) {
646
0
      continue;
647
0
    }
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
0
    if (issuer_cert->has_key_usage() &&
652
0
        !issuer_cert->key_usage().AssertsBit(KEY_USAGE_BIT_CRL_SIGN)) {
653
0
      continue;
654
0
    }
655
656
    // 6.3.3 (g) Validate the signature on the complete CRL using the public
657
    //           key validated in step (f).
658
0
    if (!VerifySignedData(*signature_algorithm, tbs_cert_list_tlv,
659
0
                          signature_value, issuer_cert->tbs().spki_tlv,
660
0
                          /*cache=*/nullptr)) {
661
0
      continue;
662
0
    }
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
0
    return GetCRLStatusForCert(target_cert->tbs().serial_number,
675
0
                               tbs_cert_list.version,
676
0
                               tbs_cert_list.revoked_certificates_tlv);
677
678
    // 6.3.3 (k,l) skipped. This implementation does not support reason codes.
679
0
  }
680
681
  // Did not find the issuer & signer of |raw_crl| in |valid_chain|.
682
0
  return CRLRevocationStatus::UNKNOWN;
683
0
}
684
685
BSSL_NAMESPACE_END