Coverage Report

Created: 2026-03-19 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/v3_cpols.cc
Line
Count
Source
1
// Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
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 <stdio.h>
16
#include <string.h>
17
18
#include <openssl/asn1.h>
19
#include <openssl/asn1t.h>
20
#include <openssl/conf.h>
21
#include <openssl/err.h>
22
#include <openssl/mem.h>
23
#include <openssl/obj.h>
24
#include <openssl/stack.h>
25
#include <openssl/x509.h>
26
27
#include "internal.h"
28
29
30
using namespace bssl;
31
32
// Certificate policies extension support: this one is a bit complex...
33
34
static int i2r_certpol(const X509V3_EXT_METHOD *method, void *ext, BIO *out,
35
                       int indent);
36
static void *r2i_certpol(const X509V3_EXT_METHOD *method, const X509V3_CTX *ctx,
37
                         const char *value);
38
static void print_qualifiers(BIO *out, const STACK_OF(POLICYQUALINFO) *quals,
39
                             int indent);
40
static void print_notice(BIO *out, const USERNOTICE *notice, int indent);
41
static POLICYINFO *policy_section(const X509V3_CTX *ctx,
42
                                  const STACK_OF(CONF_VALUE) *polstrs,
43
                                  int ia5org);
44
static POLICYQUALINFO *notice_section(const X509V3_CTX *ctx,
45
                                      const STACK_OF(CONF_VALUE) *unot,
46
                                      int ia5org);
47
static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums,
48
                    const STACK_OF(CONF_VALUE) *nos);
49
50
const X509V3_EXT_METHOD bssl::v3_cpols = {
51
    NID_certificate_policies,
52
    0,
53
    ASN1_ITEM_ref(CERTIFICATEPOLICIES),
54
    nullptr,
55
    nullptr,
56
    nullptr,
57
    nullptr,
58
    nullptr,
59
    nullptr,
60
    nullptr,
61
    nullptr,
62
    i2r_certpol,
63
    r2i_certpol,
64
    nullptr,
65
};
66
67
ASN1_SEQUENCE(NOTICEREF) = {
68
    ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT),
69
    ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER),
70
} ASN1_SEQUENCE_END(NOTICEREF)
71
72
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NOTICEREF)
73
74
ASN1_SEQUENCE(USERNOTICE) = {
75
    ASN1_OPT(USERNOTICE, noticeref, NOTICEREF),
76
    ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT),
77
} ASN1_SEQUENCE_END(USERNOTICE)
78
79
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(USERNOTICE)
80
81
ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other,
82
                                               ASN1_ANY);
83
84
ASN1_ADB(POLICYQUALINFO) = {
85
    ADB_ENTRY(NID_id_qt_cps,
86
              ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)),
87
    ADB_ENTRY(NID_id_qt_unotice,
88
              ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE)),
89
} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL);
90
91
ASN1_SEQUENCE(POLICYQUALINFO) = {
92
    ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT),
93
    ASN1_ADB_OBJECT(POLICYQUALINFO),
94
} ASN1_SEQUENCE_END(POLICYQUALINFO)
95
96
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICYQUALINFO)
97
98
ASN1_SEQUENCE(POLICYINFO) = {
99
    ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT),
100
    ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO),
101
} ASN1_SEQUENCE_END(POLICYINFO)
102
103
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICYINFO)
104
105
ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) = ASN1_EX_TEMPLATE_TYPE(
106
    ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO)
107
ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES)
108
109
IMPLEMENT_ASN1_FUNCTIONS_const(CERTIFICATEPOLICIES)
110
111
static void *r2i_certpol(const X509V3_EXT_METHOD *method, const X509V3_CTX *ctx,
112
572
                         const char *value) {
113
572
  STACK_OF(POLICYINFO) *pols = sk_POLICYINFO_new_null();
114
572
  if (pols == nullptr) {
115
0
    return nullptr;
116
0
  }
117
572
  STACK_OF(CONF_VALUE) *vals = X509V3_parse_list(value);
118
119
572
  {
120
572
    if (vals == nullptr) {
121
33
      OPENSSL_PUT_ERROR(X509V3, ERR_R_X509V3_LIB);
122
33
      goto err;
123
33
    }
124
539
    int ia5org = 0;
125
3.98k
    for (size_t i = 0; i < sk_CONF_VALUE_num(vals); i++) {
126
3.81k
      const CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i);
127
3.81k
      if (cnf->value || !cnf->name) {
128
9
        OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER);
129
9
        X509V3_conf_err(cnf);
130
9
        goto err;
131
9
      }
132
3.80k
      POLICYINFO *pol;
133
3.80k
      const char *pstr = cnf->name;
134
3.80k
      if (!strcmp(pstr, "ia5org")) {
135
212
        ia5org = 1;
136
212
        continue;
137
3.59k
      } else if (*pstr == '@') {
138
2.84k
        const STACK_OF(CONF_VALUE) *polsect = X509V3_get_section(ctx, pstr + 1);
139
2.84k
        if (!polsect) {
140
5
          OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION);
141
142
5
          X509V3_conf_err(cnf);
143
5
          goto err;
144
5
        }
145
2.84k
        pol = policy_section(ctx, polsect, ia5org);
146
2.84k
        if (!pol) {
147
283
          goto err;
148
283
        }
149
2.84k
      } else {
150
749
        ASN1_OBJECT *pobj = OBJ_txt2obj(cnf->name, 0);
151
749
        if (pobj == nullptr) {
152
73
          OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
153
73
          X509V3_conf_err(cnf);
154
73
          goto err;
155
73
        }
156
676
        pol = POLICYINFO_new();
157
676
        if (pol == nullptr) {
158
0
          ASN1_OBJECT_free(pobj);
159
0
          goto err;
160
0
        }
161
676
        pol->policyid = pobj;
162
676
      }
163
3.23k
      if (!sk_POLICYINFO_push(pols, pol)) {
164
0
        POLICYINFO_free(pol);
165
0
        goto err;
166
0
      }
167
3.23k
    }
168
169
    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
169
169
    return pols;
170
539
  }
171
172
403
err:
173
403
  sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
174
403
  sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
175
403
  return nullptr;
176
539
}
177
178
static POLICYINFO *policy_section(const X509V3_CTX *ctx,
179
                                  const STACK_OF(CONF_VALUE) *polstrs,
180
2.84k
                                  int ia5org) {
181
2.84k
  POLICYINFO *pol;
182
2.84k
  POLICYQUALINFO *qual;
183
2.84k
  if (!(pol = POLICYINFO_new())) {
184
0
    goto err;
185
0
  }
186
7.40k
  for (size_t i = 0; i < sk_CONF_VALUE_num(polstrs); i++) {
187
4.84k
    const CONF_VALUE *cnf = sk_CONF_VALUE_value(polstrs, i);
188
4.84k
    if (!strcmp(cnf->name, "policyIdentifier")) {
189
307
      ASN1_OBJECT *pobj;
190
307
      if (!(pobj = OBJ_txt2obj(cnf->value, 0))) {
191
1
        OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
192
1
        X509V3_conf_err(cnf);
193
1
        goto err;
194
1
      }
195
306
      pol->policyid = pobj;
196
197
4.53k
    } else if (x509v3_conf_name_matches(cnf->name, "CPS")) {
198
1.55k
      if (!pol->qualifiers) {
199
547
        pol->qualifiers = sk_POLICYQUALINFO_new_null();
200
547
      }
201
1.55k
      if (!(qual = POLICYQUALINFO_new())) {
202
0
        goto err;
203
0
      }
204
1.55k
      if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) {
205
0
        goto err;
206
0
      }
207
1.55k
      qual->pqualid = OBJ_nid2obj(NID_id_qt_cps);
208
1.55k
      if (qual->pqualid == nullptr) {
209
0
        OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR);
210
0
        goto err;
211
0
      }
212
1.55k
      qual->d.cpsuri = ASN1_IA5STRING_new();
213
1.55k
      if (qual->d.cpsuri == nullptr) {
214
0
        goto err;
215
0
      }
216
1.55k
      if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value, strlen(cnf->value))) {
217
0
        goto err;
218
0
      }
219
2.98k
    } else if (x509v3_conf_name_matches(cnf->name, "userNotice")) {
220
2.90k
      if (*cnf->value != '@') {
221
10
        OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXPECTED_A_SECTION_NAME);
222
10
        X509V3_conf_err(cnf);
223
10
        goto err;
224
10
      }
225
2.89k
      const STACK_OF(CONF_VALUE) *unot =
226
2.89k
          X509V3_get_section(ctx, cnf->value + 1);
227
2.89k
      if (!unot) {
228
1
        OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION);
229
1
        X509V3_conf_err(cnf);
230
1
        goto err;
231
1
      }
232
2.89k
      qual = notice_section(ctx, unot, ia5org);
233
2.89k
      if (!qual) {
234
196
        goto err;
235
196
      }
236
2.69k
      if (!pol->qualifiers) {
237
1.56k
        pol->qualifiers = sk_POLICYQUALINFO_new_null();
238
1.56k
      }
239
2.69k
      if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) {
240
0
        goto err;
241
0
      }
242
2.69k
    } else {
243
75
      OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION);
244
245
75
      X509V3_conf_err(cnf);
246
75
      goto err;
247
75
    }
248
4.84k
  }
249
2.56k
  if (!pol->policyid) {
250
0
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_POLICY_IDENTIFIER);
251
0
    goto err;
252
0
  }
253
254
2.56k
  return pol;
255
256
283
err:
257
283
  POLICYINFO_free(pol);
258
283
  return nullptr;
259
2.56k
}
260
261
static POLICYQUALINFO *notice_section(const X509V3_CTX *ctx,
262
                                      const STACK_OF(CONF_VALUE) *unot,
263
2.89k
                                      int ia5org) {
264
2.89k
  USERNOTICE *notice;
265
2.89k
  POLICYQUALINFO *qual;
266
2.89k
  if (!(qual = POLICYQUALINFO_new())) {
267
0
    goto err;
268
0
  }
269
2.89k
  qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice);
270
2.89k
  if (qual->pqualid == nullptr) {
271
0
    OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR);
272
0
    goto err;
273
0
  }
274
2.89k
  if (!(notice = USERNOTICE_new())) {
275
0
    goto err;
276
0
  }
277
2.89k
  qual->d.usernotice = notice;
278
5.05k
  for (size_t i = 0; i < sk_CONF_VALUE_num(unot); i++) {
279
2.35k
    const CONF_VALUE *cnf = sk_CONF_VALUE_value(unot, i);
280
2.35k
    if (!strcmp(cnf->name, "explicitText")) {
281
220
      notice->exptext = ASN1_VISIBLESTRING_new();
282
220
      if (notice->exptext == nullptr) {
283
0
        goto err;
284
0
      }
285
220
      if (!ASN1_STRING_set(notice->exptext, cnf->value, strlen(cnf->value))) {
286
0
        goto err;
287
0
      }
288
2.13k
    } else if (!strcmp(cnf->name, "organization")) {
289
1.20k
      NOTICEREF *nref;
290
1.20k
      if (!notice->noticeref) {
291
1.00k
        if (!(nref = NOTICEREF_new())) {
292
0
          goto err;
293
0
        }
294
1.00k
        notice->noticeref = nref;
295
1.00k
      } else {
296
194
        nref = notice->noticeref;
297
194
      }
298
1.20k
      if (ia5org) {
299
194
        nref->organization->type = V_ASN1_IA5STRING;
300
1.00k
      } else {
301
1.00k
        nref->organization->type = V_ASN1_VISIBLESTRING;
302
1.00k
      }
303
1.20k
      if (!ASN1_STRING_set(nref->organization, cnf->value,
304
1.20k
                           strlen(cnf->value))) {
305
0
        goto err;
306
0
      }
307
1.20k
    } else if (!strcmp(cnf->name, "noticeNumbers")) {
308
741
      NOTICEREF *nref;
309
741
      STACK_OF(CONF_VALUE) *nos;
310
741
      if (!notice->noticeref) {
311
547
        if (!(nref = NOTICEREF_new())) {
312
0
          goto err;
313
0
        }
314
547
        notice->noticeref = nref;
315
547
      } else {
316
194
        nref = notice->noticeref;
317
194
      }
318
741
      nos = X509V3_parse_list(cnf->value);
319
741
      if (!nos || !sk_CONF_VALUE_num(nos)) {
320
2
        OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBERS);
321
2
        X509V3_conf_err(cnf);
322
2
        sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
323
2
        goto err;
324
2
      }
325
739
      int ret = nref_nos(nref->noticenos, nos);
326
739
      sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
327
739
      if (!ret) {
328
2
        goto err;
329
2
      }
330
739
    } else {
331
192
      OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION);
332
192
      X509V3_conf_err(cnf);
333
192
      goto err;
334
192
    }
335
2.35k
  }
336
337
2.69k
  if (notice->noticeref &&
338
1.54k
      (!notice->noticeref->noticenos || !notice->noticeref->organization)) {
339
0
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
340
0
    goto err;
341
0
  }
342
343
2.69k
  return qual;
344
345
196
err:
346
196
  POLICYQUALINFO_free(qual);
347
196
  return nullptr;
348
2.69k
}
349
350
static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums,
351
739
                    const STACK_OF(CONF_VALUE) *nos) {
352
1.82k
  for (size_t i = 0; i < sk_CONF_VALUE_num(nos); i++) {
353
1.08k
    const CONF_VALUE *cnf = sk_CONF_VALUE_value(nos, i);
354
1.08k
    ASN1_INTEGER *aint = s2i_ASN1_INTEGER(nullptr, cnf->name);
355
1.08k
    if (aint == nullptr) {
356
2
      OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBER);
357
2
      return 0;
358
2
    }
359
1.08k
    if (!sk_ASN1_INTEGER_push(nnums, aint)) {
360
0
      ASN1_INTEGER_free(aint);
361
0
      return 0;
362
0
    }
363
1.08k
  }
364
737
  return 1;
365
739
}
366
367
static int i2r_certpol(const X509V3_EXT_METHOD *method, void *ext, BIO *out,
368
126
                       int indent) {
369
126
  const STACK_OF(POLICYINFO) *pol =
370
126
      reinterpret_cast<const STACK_OF(POLICYINFO) *>(ext);
371
  // First print out the policy OIDs
372
306
  for (size_t i = 0; i < sk_POLICYINFO_num(pol); i++) {
373
180
    const POLICYINFO *pinfo = sk_POLICYINFO_value(pol, i);
374
180
    BIO_printf(out, "%*sPolicy: ", indent, "");
375
180
    i2a_ASN1_OBJECT(out, pinfo->policyid);
376
180
    BIO_puts(out, "\n");
377
180
    if (pinfo->qualifiers) {
378
99
      print_qualifiers(out, pinfo->qualifiers, indent + 2);
379
99
    }
380
180
  }
381
126
  return 1;
382
126
}
383
384
static void print_qualifiers(BIO *out, const STACK_OF(POLICYQUALINFO) *quals,
385
99
                             int indent) {
386
626
  for (size_t i = 0; i < sk_POLICYQUALINFO_num(quals); i++) {
387
527
    const POLICYQUALINFO *qualinfo = sk_POLICYQUALINFO_value(quals, i);
388
527
    switch (OBJ_obj2nid(qualinfo->pqualid)) {
389
31
      case NID_id_qt_cps:
390
31
        BIO_printf(out, "%*sCPS: %.*s\n", indent, "",
391
31
                   qualinfo->d.cpsuri->length, qualinfo->d.cpsuri->data);
392
31
        break;
393
394
20
      case NID_id_qt_unotice:
395
20
        BIO_printf(out, "%*sUser Notice:\n", indent, "");
396
20
        print_notice(out, qualinfo->d.usernotice, indent + 2);
397
20
        break;
398
399
476
      default:
400
476
        BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, "");
401
402
476
        i2a_ASN1_OBJECT(out, qualinfo->pqualid);
403
476
        BIO_puts(out, "\n");
404
476
        break;
405
527
    }
406
527
  }
407
99
}
408
409
20
static void print_notice(BIO *out, const USERNOTICE *notice, int indent) {
410
20
  if (notice->noticeref) {
411
6
    NOTICEREF *ref;
412
6
    ref = notice->noticeref;
413
6
    BIO_printf(out, "%*sOrganization: %.*s\n", indent, "",
414
6
               ref->organization->length, ref->organization->data);
415
6
    BIO_printf(out, "%*sNumber%s: ", indent, "",
416
6
               sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "");
417
12
    for (size_t i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
418
6
      ASN1_INTEGER *num;
419
6
      char *tmp;
420
6
      num = sk_ASN1_INTEGER_value(ref->noticenos, i);
421
6
      if (i) {
422
1
        BIO_puts(out, ", ");
423
1
      }
424
6
      if (num == nullptr) {
425
0
        BIO_puts(out, "(null)");
426
6
      } else {
427
6
        tmp = i2s_ASN1_INTEGER(nullptr, num);
428
6
        if (tmp == nullptr) {
429
0
          return;
430
0
        }
431
6
        BIO_puts(out, tmp);
432
6
        OPENSSL_free(tmp);
433
6
      }
434
6
    }
435
6
    BIO_puts(out, "\n");
436
6
  }
437
20
  if (notice->exptext) {
438
19
    BIO_printf(out, "%*sExplicit Text: %.*s\n", indent, "",
439
19
               notice->exptext->length, notice->exptext->data);
440
19
  }
441
20
}