Coverage Report

Created: 2025-08-28 06:59

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