Coverage Report

Created: 2026-10-19 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/pki/certificate_policies.cc
Line
Count
Source
1
// Copyright 2015 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
17
#include "certificate_policies.h"
18
19
#include <openssl/base.h>
20
#include "cert_error_params.h"
21
#include "cert_errors.h"
22
#include "input.h"
23
#include "parse_values.h"
24
#include "parser.h"
25
26
BSSL_NAMESPACE_BEGIN
27
28
namespace {
29
30
// ---------------------------------------------------------------
31
// Errors
32
// ---------------------------------------------------------------
33
34
DEFINE_CERT_ERROR_ID(kPolicyQualifiersEmptySequence,
35
                     "The policy qualifiers SEQUENCE is empty");
36
DEFINE_CERT_ERROR_ID(kUnknownPolicyQualifierOid,
37
                     "Unknown policy qualifier OID (not CPS or User Notice)");
38
DEFINE_CERT_ERROR_ID(kPoliciesEmptySequence, "Policies is an empty SEQUENCE");
39
DEFINE_CERT_ERROR_ID(kPoliciesDuplicateOid, "Policies contains duplicate OIDs");
40
DEFINE_CERT_ERROR_ID(kPolicyInformationTrailingData,
41
                     "PolicyInformation has trailing data");
42
DEFINE_CERT_ERROR_ID(kFailedParsingPolicyQualifiers,
43
                     "Failed parsing policy qualifiers");
44
DEFINE_CERT_ERROR_ID(kMissingQualifier,
45
                     "PolicyQualifierInfo is missing qualifier");
46
DEFINE_CERT_ERROR_ID(kPolicyQualifierInfoTrailingData,
47
                     "PolicyQualifierInfo has trailing data");
48
49
// Minimally parse policyQualifiers, storing in `policy_qualifiers` if non-null.
50
// If a policy qualifier other than User Notice/CPS is present, parsing
51
// will fail if `restrict_to_known_qualifiers` was set to true.
52
bool ParsePolicyQualifiers(bool restrict_to_known_qualifiers,
53
                           der::Parser *policy_qualifiers_sequence_parser,
54
                           std::vector<PolicyQualifierInfo> *policy_qualifiers,
55
541
                           CertErrors *errors) {
56
541
  BSSL_CHECK(errors);
57
58
  // If it is present, the policyQualifiers sequence should have at least 1
59
  // element.
60
  //
61
  //      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
62
  //                              PolicyQualifierInfo OPTIONAL }
63
541
  if (!policy_qualifiers_sequence_parser->HasMore()) {
64
3
    errors->AddError(kPolicyQualifiersEmptySequence);
65
3
    return false;
66
3
  }
67
1.15k
  while (policy_qualifiers_sequence_parser->HasMore()) {
68
    // PolicyQualifierInfo ::= SEQUENCE {
69
657
    der::Parser policy_information_parser;
70
657
    if (!policy_qualifiers_sequence_parser->ReadSequence(
71
657
            &policy_information_parser)) {
72
5
      return false;
73
5
    }
74
    //      policyQualifierId  PolicyQualifierId,
75
652
    der::Input qualifier_oid;
76
652
    if (!policy_information_parser.ReadTag(CBS_ASN1_OBJECT, &qualifier_oid)) {
77
3
      return false;
78
3
    }
79
649
    if (restrict_to_known_qualifiers &&
80
64
        qualifier_oid != der::Input(kCpsPointerId) &&
81
51
        qualifier_oid != der::Input(kUserNoticeId)) {
82
30
      errors->AddError(kUnknownPolicyQualifierOid,
83
30
                       CreateCertErrorParams1Der("oid", qualifier_oid));
84
30
      return false;
85
30
    }
86
    //      qualifier          ANY DEFINED BY policyQualifierId }
87
619
    der::Input qualifier_tlv;
88
619
    if (!policy_information_parser.ReadRawTLV(&qualifier_tlv)) {
89
2
      errors->AddError(kMissingQualifier);
90
2
      return false;
91
2
    }
92
    // Should not have trailing data after qualifier.
93
617
    if (policy_information_parser.HasMore()) {
94
4
      errors->AddError(kPolicyQualifierInfoTrailingData);
95
4
      return false;
96
4
    }
97
98
613
    if (policy_qualifiers) {
99
0
      policy_qualifiers->push_back({qualifier_oid, qualifier_tlv});
100
0
    }
101
613
  }
102
494
  return true;
103
538
}
104
105
// RFC 5280 section 4.2.1.4.  Certificate Policies:
106
//
107
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
108
//
109
// PolicyInformation ::= SEQUENCE {
110
//      policyIdentifier   CertPolicyId,
111
//      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
112
//                              PolicyQualifierInfo OPTIONAL }
113
//
114
// CertPolicyId ::= OBJECT IDENTIFIER
115
//
116
// PolicyQualifierInfo ::= SEQUENCE {
117
//      policyQualifierId  PolicyQualifierId,
118
//      qualifier          ANY DEFINED BY policyQualifierId }
119
//
120
// PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
121
//
122
// Qualifier ::= CHOICE {
123
//      cPSuri           CPSuri,
124
//      userNotice       UserNotice }
125
//
126
// CPSuri ::= IA5String
127
//
128
// UserNotice ::= SEQUENCE {
129
//      noticeRef        NoticeReference OPTIONAL,
130
//      explicitText     DisplayText OPTIONAL }
131
//
132
// NoticeReference ::= SEQUENCE {
133
//      organization     DisplayText,
134
//      noticeNumbers    SEQUENCE OF INTEGER }
135
//
136
// DisplayText ::= CHOICE {
137
//      ia5String        IA5String      (SIZE (1..200)),
138
//      visibleString    VisibleString  (SIZE (1..200)),
139
//      bmpString        BMPString      (SIZE (1..200)),
140
//      utf8String       UTF8String     (SIZE (1..200)) }
141
bool ParseCertificatePoliciesExtensionImpl(
142
    der::Input extension_value, bool fail_parsing_unknown_qualifier_oids,
143
    std::vector<der::Input> *policy_oids,
144
569
    std::vector<PolicyInformation> *policy_informations, CertErrors *errors) {
145
569
  BSSL_CHECK(policy_oids);
146
569
  BSSL_CHECK(errors);
147
  // certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
148
569
  der::Parser extension_parser(extension_value);
149
569
  der::Parser policies_sequence_parser;
150
569
  if (!extension_parser.ReadSequence(&policies_sequence_parser)) {
151
5
    return false;
152
5
  }
153
  // Should not have trailing data after certificatePolicies sequence.
154
564
  if (extension_parser.HasMore()) {
155
1
    return false;
156
1
  }
157
  // The certificatePolicies sequence should have at least 1 element.
158
563
  if (!policies_sequence_parser.HasMore()) {
159
8
    errors->AddError(kPoliciesEmptySequence);
160
8
    return false;
161
8
  }
162
163
555
  policy_oids->clear();
164
555
  if (policy_informations) {
165
0
    policy_informations->clear();
166
0
  }
167
168
14.3k
  while (policies_sequence_parser.HasMore()) {
169
    // PolicyInformation ::= SEQUENCE {
170
13.8k
    der::Parser policy_information_parser;
171
13.8k
    if (!policies_sequence_parser.ReadSequence(&policy_information_parser)) {
172
7
      return false;
173
7
    }
174
    //      policyIdentifier   CertPolicyId,
175
13.8k
    der::Input policy_oid;
176
13.8k
    if (!policy_information_parser.ReadTag(CBS_ASN1_OBJECT, &policy_oid)) {
177
2
      return false;
178
2
    }
179
180
13.8k
    policy_oids->push_back(policy_oid);
181
182
13.8k
    std::vector<PolicyQualifierInfo> *policy_qualifiers = nullptr;
183
13.8k
    if (policy_informations) {
184
0
      policy_informations->emplace_back();
185
0
      policy_informations->back().policy_oid = policy_oid;
186
0
      policy_qualifiers = &policy_informations->back().policy_qualifiers;
187
0
    }
188
189
13.8k
    if (!policy_information_parser.HasMore()) {
190
13.2k
      continue;
191
13.2k
    }
192
193
    //      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
194
    //                              PolicyQualifierInfo OPTIONAL }
195
544
    der::Parser policy_qualifiers_sequence_parser;
196
544
    if (!policy_information_parser.ReadSequence(
197
544
            &policy_qualifiers_sequence_parser)) {
198
2
      return false;
199
2
    }
200
    // Should not have trailing data after policyQualifiers sequence.
201
542
    if (policy_information_parser.HasMore()) {
202
1
      errors->AddError(kPolicyInformationTrailingData);
203
1
      return false;
204
1
    }
205
206
    // RFC 5280 section 4.2.1.4: When qualifiers are used with the special
207
    // policy anyPolicy, they MUST be limited to the qualifiers identified in
208
    // this section.
209
541
    if (!ParsePolicyQualifiers(fail_parsing_unknown_qualifier_oids ||
210
541
                                   policy_oid == der::Input(kAnyPolicyOid),
211
541
                               &policy_qualifiers_sequence_parser,
212
541
                               policy_qualifiers, errors)) {
213
47
      errors->AddError(kFailedParsingPolicyQualifiers);
214
47
      return false;
215
47
    }
216
541
  }
217
218
  // RFC 5280 section 4.2.1.4: A certificate policy OID MUST NOT appear more
219
  // than once in a certificate policies extension.
220
496
  std::sort(policy_oids->begin(), policy_oids->end());
221
496
  auto dupe_policy_iter =
222
496
      std::adjacent_find(policy_oids->begin(), policy_oids->end());
223
496
  if (dupe_policy_iter != policy_oids->end()) {
224
355
    errors->AddError(kPoliciesDuplicateOid,
225
355
                     CreateCertErrorParams1Der("oid", *dupe_policy_iter));
226
355
    return false;
227
355
  }
228
229
141
  return true;
230
496
}
231
232
}  // namespace
233
234
bool ParseCertificatePoliciesExtension(der::Input extension_value,
235
                                       std::vector<PolicyInformation> *policies,
236
0
                                       CertErrors *errors) {
237
0
  std::vector<der::Input> unused_policy_oids;
238
0
  return ParseCertificatePoliciesExtensionImpl(
239
0
      extension_value, /*fail_parsing_unknown_qualifier_oids=*/false,
240
0
      &unused_policy_oids, policies, errors);
241
0
}
242
243
bool ParseCertificatePoliciesExtensionOids(
244
    der::Input extension_value, bool fail_parsing_unknown_qualifier_oids,
245
569
    std::vector<der::Input> *policy_oids, CertErrors *errors) {
246
569
  return ParseCertificatePoliciesExtensionImpl(
247
569
      extension_value, fail_parsing_unknown_qualifier_oids, policy_oids,
248
569
      nullptr, errors);
249
569
}
250
251
// From RFC 5280:
252
//
253
//   PolicyConstraints ::= SEQUENCE {
254
//        requireExplicitPolicy           [0] SkipCerts OPTIONAL,
255
//        inhibitPolicyMapping            [1] SkipCerts OPTIONAL }
256
//
257
//   SkipCerts ::= INTEGER (0..MAX)
258
bool ParsePolicyConstraints(der::Input policy_constraints_tlv,
259
32
                            ParsedPolicyConstraints *out) {
260
32
  der::Parser parser(policy_constraints_tlv);
261
262
  //   PolicyConstraints ::= SEQUENCE {
263
32
  der::Parser sequence_parser;
264
32
  if (!parser.ReadSequence(&sequence_parser)) {
265
4
    return false;
266
4
  }
267
268
  // RFC 5280 prohibits CAs from issuing PolicyConstraints as an empty sequence:
269
  //
270
  //   Conforming CAs MUST NOT issue certificates where policy constraints
271
  //   is an empty sequence.  That is, either the inhibitPolicyMapping field
272
  //   or the requireExplicitPolicy field MUST be present.  The behavior of
273
  //   clients that encounter an empty policy constraints field is not
274
  //   addressed in this profile.
275
28
  if (!sequence_parser.HasMore()) {
276
3
    return false;
277
3
  }
278
279
25
  std::optional<der::Input> require_value;
280
25
  if (!sequence_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 0,
281
25
                                       &require_value)) {
282
3
    return false;
283
3
  }
284
285
22
  if (require_value) {
286
16
    uint8_t require_explicit_policy;
287
16
    if (!ParseUint8(require_value.value(), &require_explicit_policy)) {
288
      // TODO(eroman): Surface reason for failure if length was longer than
289
      // uint8.
290
7
      return false;
291
7
    }
292
9
    out->require_explicit_policy = require_explicit_policy;
293
9
  }
294
295
15
  std::optional<der::Input> inhibit_value;
296
15
  if (!sequence_parser.ReadOptionalTag(CBS_ASN1_CONTEXT_SPECIFIC | 1,
297
15
                                       &inhibit_value)) {
298
1
    return false;
299
1
  }
300
301
14
  if (inhibit_value) {
302
12
    uint8_t inhibit_policy_mapping;
303
12
    if (!ParseUint8(inhibit_value.value(), &inhibit_policy_mapping)) {
304
      // TODO(eroman): Surface reason for failure if length was longer than
305
      // uint8.
306
7
      return false;
307
7
    }
308
5
    out->inhibit_policy_mapping = inhibit_policy_mapping;
309
5
  }
310
311
  // There should be no remaining data.
312
7
  if (sequence_parser.HasMore() || parser.HasMore()) {
313
6
    return false;
314
6
  }
315
316
1
  return true;
317
7
}
318
319
// From RFC 5280:
320
//
321
//   InhibitAnyPolicy ::= SkipCerts
322
//
323
//   SkipCerts ::= INTEGER (0..MAX)
324
std::optional<uint8_t> ParseInhibitAnyPolicy(
325
59
    der::Input inhibit_any_policy_tlv) {
326
59
  der::Parser parser(inhibit_any_policy_tlv);
327
59
  std::optional<uint8_t> num_certs = std::make_optional<uint8_t>();
328
329
  // TODO(eroman): Surface reason for failure if length was longer than uint8.
330
59
  if (!parser.ReadUint8(&num_certs.value())) {
331
55
    return std::nullopt;
332
55
  }
333
334
  // There should be no remaining data.
335
4
  if (parser.HasMore()) {
336
2
    return std::nullopt;
337
2
  }
338
339
2
  return num_certs;
340
4
}
341
342
// From RFC 5280:
343
//
344
//   PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
345
//        issuerDomainPolicy      CertPolicyId,
346
//        subjectDomainPolicy     CertPolicyId }
347
bool ParsePolicyMappings(der::Input policy_mappings_tlv,
348
20
                         std::vector<ParsedPolicyMapping> *mappings) {
349
20
  mappings->clear();
350
351
20
  der::Parser parser(policy_mappings_tlv);
352
353
  //   PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
354
20
  der::Parser sequence_parser;
355
20
  if (!parser.ReadSequence(&sequence_parser)) {
356
3
    return false;
357
3
  }
358
359
  // Must be at least 1 mapping.
360
17
  if (!sequence_parser.HasMore()) {
361
5
    return false;
362
5
  }
363
364
60
  while (sequence_parser.HasMore()) {
365
57
    der::Parser mapping_parser;
366
57
    if (!sequence_parser.ReadSequence(&mapping_parser)) {
367
4
      return false;
368
4
    }
369
370
53
    ParsedPolicyMapping mapping;
371
53
    if (!mapping_parser.ReadTag(CBS_ASN1_OBJECT,
372
53
                                &mapping.issuer_domain_policy)) {
373
2
      return false;
374
2
    }
375
51
    if (!mapping_parser.ReadTag(CBS_ASN1_OBJECT,
376
51
                                &mapping.subject_domain_policy)) {
377
2
      return false;
378
2
    }
379
380
    // There shouldn't be extra unconsumed data.
381
49
    if (mapping_parser.HasMore()) {
382
1
      return false;
383
1
    }
384
385
48
    mappings->push_back(mapping);
386
48
  }
387
388
  // There shouldn't be extra unconsumed data.
389
3
  if (parser.HasMore()) {
390
2
    return false;
391
2
  }
392
393
1
  return true;
394
3
}
395
396
BSSL_NAMESPACE_END