Coverage Report

Created: 2026-02-14 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/v3_conf.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
// extension creation utilities
16
17
#include <ctype.h>
18
#include <limits.h>
19
#include <stdio.h>
20
#include <string.h>
21
22
#include <openssl/conf.h>
23
#include <openssl/err.h>
24
#include <openssl/mem.h>
25
#include <openssl/obj.h>
26
#include <openssl/x509.h>
27
28
#include "../internal.h"
29
#include "internal.h"
30
31
32
using namespace bssl;
33
34
static int v3_check_critical(const char **value);
35
static int v3_check_generic(const char **value);
36
static X509_EXTENSION *do_ext_nconf(const CONF *conf, const X509V3_CTX *ctx,
37
                                    int ext_nid, int crit, const char *value);
38
static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value,
39
                                            int crit, int type,
40
                                            const X509V3_CTX *ctx);
41
static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid,
42
                                  int crit, void *ext_struc);
43
static unsigned char *generic_asn1(const char *value, const X509V3_CTX *ctx,
44
                                   size_t *ext_len);
45
46
X509_EXTENSION *X509V3_EXT_nconf(const CONF *conf, const X509V3_CTX *ctx,
47
23.0k
                                 const char *name, const char *value) {
48
  // If omitted, fill in an empty |X509V3_CTX|.
49
23.0k
  X509V3_CTX ctx_tmp;
50
23.0k
  if (ctx == nullptr) {
51
11.6k
    X509V3_set_ctx(&ctx_tmp, nullptr, nullptr, nullptr, nullptr, 0);
52
11.6k
    X509V3_set_nconf(&ctx_tmp, conf);
53
11.6k
    ctx = &ctx_tmp;
54
11.6k
  }
55
56
23.0k
  int crit = v3_check_critical(&value);
57
23.0k
  int ext_type = v3_check_generic(&value);
58
23.0k
  if (ext_type != 0) {
59
12.7k
    return v3_generic_extension(name, value, crit, ext_type, ctx);
60
12.7k
  }
61
10.3k
  X509_EXTENSION *ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value);
62
10.3k
  if (!ret) {
63
7.89k
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_IN_EXTENSION);
64
7.89k
    ERR_add_error_data(4, "name=", name, ", value=", value);
65
7.89k
  }
66
10.3k
  return ret;
67
23.0k
}
68
69
X509_EXTENSION *X509V3_EXT_nconf_nid(const CONF *conf, const X509V3_CTX *ctx,
70
0
                                     int ext_nid, const char *value) {
71
  // If omitted, fill in an empty |X509V3_CTX|.
72
0
  X509V3_CTX ctx_tmp;
73
0
  if (ctx == nullptr) {
74
0
    X509V3_set_ctx(&ctx_tmp, nullptr, nullptr, nullptr, nullptr, 0);
75
0
    X509V3_set_nconf(&ctx_tmp, conf);
76
0
    ctx = &ctx_tmp;
77
0
  }
78
79
0
  int crit = v3_check_critical(&value);
80
0
  int ext_type = v3_check_generic(&value);
81
0
  if (ext_type != 0) {
82
0
    return v3_generic_extension(OBJ_nid2sn(ext_nid), value, crit, ext_type,
83
0
                                ctx);
84
0
  }
85
0
  return do_ext_nconf(conf, ctx, ext_nid, crit, value);
86
0
}
87
88
// CONF *conf:  Config file
89
// char *value:  Value
90
static X509_EXTENSION *do_ext_nconf(const CONF *conf, const X509V3_CTX *ctx,
91
10.3k
                                    int ext_nid, int crit, const char *value) {
92
10.3k
  const X509V3_EXT_METHOD *method;
93
10.3k
  X509_EXTENSION *ext;
94
10.3k
  const STACK_OF(CONF_VALUE) *nval;
95
10.3k
  STACK_OF(CONF_VALUE) *nval_owned = nullptr;
96
10.3k
  void *ext_struc;
97
10.3k
  if (ext_nid == NID_undef) {
98
1.33k
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME);
99
1.33k
    return nullptr;
100
1.33k
  }
101
8.99k
  if (!(method = X509V3_EXT_get_nid(ext_nid))) {
102
200
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION);
103
200
    return nullptr;
104
200
  }
105
  // Now get internal extension representation based on type
106
8.79k
  if (method->v2i) {
107
7.69k
    if (*value == '@') {
108
      // TODO(davidben): This is the only place where |X509V3_EXT_nconf|'s
109
      // |conf| parameter is used. All other codepaths use the copy inside
110
      // |ctx|. Should this be switched and then the parameter ignored?
111
5
      if (conf == nullptr) {
112
0
        OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_CONFIG_DATABASE);
113
0
        return nullptr;
114
0
      }
115
5
      nval = NCONF_get_section(conf, value + 1);
116
7.69k
    } else {
117
7.69k
      nval_owned = X509V3_parse_list(value);
118
7.69k
      nval = nval_owned;
119
7.69k
    }
120
7.69k
    if (nval == nullptr || sk_CONF_VALUE_num(nval) <= 0) {
121
217
      OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_EXTENSION_STRING);
122
217
      ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value);
123
217
      sk_CONF_VALUE_pop_free(nval_owned, X509V3_conf_free);
124
217
      return nullptr;
125
217
    }
126
7.48k
    ext_struc = method->v2i(method, ctx, nval);
127
7.48k
    sk_CONF_VALUE_pop_free(nval_owned, X509V3_conf_free);
128
7.48k
    if (!ext_struc) {
129
5.15k
      return nullptr;
130
5.15k
    }
131
7.48k
  } else if (method->s2i) {
132
203
    if (!(ext_struc = method->s2i(method, ctx, value))) {
133
42
      return nullptr;
134
42
    }
135
895
  } else if (method->r2i) {
136
    // TODO(davidben): Should this check be removed? This matches OpenSSL, but
137
    // r2i-based extensions do not necessarily require a config database. The
138
    // two built-in extensions only use it some of the time, and already handle
139
    // |X509V3_get_section| returning NULL.
140
880
    if (!ctx->db) {
141
439
      OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_CONFIG_DATABASE);
142
439
      return nullptr;
143
439
    }
144
441
    if (!(ext_struc = method->r2i(method, ctx, value))) {
145
274
      return nullptr;
146
274
    }
147
441
  } else {
148
15
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED);
149
15
    ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid));
150
15
    return nullptr;
151
15
  }
152
153
2.65k
  ext = do_ext_i2d(method, ext_nid, crit, ext_struc);
154
2.65k
  ASN1_item_free(reinterpret_cast<ASN1_VALUE *>(ext_struc),
155
2.65k
                 ASN1_ITEM_ptr(method->it));
156
2.65k
  return ext;
157
8.79k
}
158
159
static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid,
160
5.96k
                                  int crit, void *ext_struc) {
161
  // Convert the extension's internal representation to DER.
162
5.96k
  unsigned char *ext_der = nullptr;
163
5.96k
  int ext_len = ASN1_item_i2d(reinterpret_cast<ASN1_VALUE *>(ext_struc),
164
5.96k
                              &ext_der, ASN1_ITEM_ptr(method->it));
165
5.96k
  if (ext_len < 0) {
166
221
    return nullptr;
167
221
  }
168
169
5.74k
  ASN1_OCTET_STRING *ext_oct = ASN1_OCTET_STRING_new();
170
5.74k
  if (ext_oct == nullptr) {
171
0
    OPENSSL_free(ext_der);
172
0
    return nullptr;
173
0
  }
174
5.74k
  ASN1_STRING_set0(ext_oct, ext_der, ext_len);
175
176
5.74k
  X509_EXTENSION *ext =
177
5.74k
      X509_EXTENSION_create_by_NID(nullptr, ext_nid, crit, ext_oct);
178
5.74k
  ASN1_OCTET_STRING_free(ext_oct);
179
5.74k
  return ext;
180
5.74k
}
181
182
// Given an internal structure, nid and critical flag create an extension
183
184
3.30k
X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc) {
185
3.30k
  const X509V3_EXT_METHOD *method;
186
3.30k
  if (!(method = X509V3_EXT_get_nid(ext_nid))) {
187
0
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION);
188
0
    return nullptr;
189
0
  }
190
3.30k
  return do_ext_i2d(method, ext_nid, crit, ext_struc);
191
3.30k
}
192
193
// Check the extension string for critical flag
194
23.0k
static int v3_check_critical(const char **value) {
195
23.0k
  const char *p = *value;
196
23.0k
  if ((strlen(p) < 9) || strncmp(p, "critical,", 9)) {
197
22.8k
    return 0;
198
22.8k
  }
199
202
  p += 9;
200
444
  while (OPENSSL_isspace((unsigned char)*p)) {
201
242
    p++;
202
242
  }
203
202
  *value = p;
204
202
  return 1;
205
23.0k
}
206
207
// Check extension string for generic extension and return the type
208
23.0k
static int v3_check_generic(const char **value) {
209
23.0k
  int gen_type = 0;
210
23.0k
  const char *p = *value;
211
23.0k
  if ((strlen(p) >= 4) && !strncmp(p, "DER:", 4)) {
212
3.87k
    p += 4;
213
3.87k
    gen_type = 1;
214
19.1k
  } else if ((strlen(p) >= 5) && !strncmp(p, "ASN1:", 5)) {
215
8.82k
    p += 5;
216
8.82k
    gen_type = 2;
217
10.3k
  } else {
218
10.3k
    return 0;
219
10.3k
  }
220
221
13.0k
  while (OPENSSL_isspace((unsigned char)*p)) {
222
334
    p++;
223
334
  }
224
12.7k
  *value = p;
225
12.7k
  return gen_type;
226
23.0k
}
227
228
// Create a generic extension: for now just handle DER type
229
static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value,
230
                                            int crit, int gen_type,
231
12.7k
                                            const X509V3_CTX *ctx) {
232
12.7k
  UniquePtr<ASN1_OBJECT> obj(OBJ_txt2obj(ext, 0));
233
12.7k
  if (obj == nullptr) {
234
949
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NAME_ERROR);
235
949
    ERR_add_error_data(2, "name=", ext);
236
949
    return nullptr;
237
949
  }
238
239
11.7k
  UniquePtr<unsigned char> ext_der;
240
11.7k
  size_t ext_len = 0;
241
11.7k
  if (gen_type == 1) {
242
2.95k
    ext_der.reset(x509v3_hex_to_bytes(value, &ext_len));
243
8.80k
  } else if (gen_type == 2) {
244
8.80k
    ext_der.reset(generic_asn1(value, ctx, &ext_len));
245
8.80k
  }
246
247
11.7k
  if (ext_der == nullptr) {
248
4.46k
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_VALUE_ERROR);
249
4.46k
    ERR_add_error_data(2, "value=", value);
250
4.46k
    return nullptr;
251
4.46k
  }
252
253
7.29k
  if (ext_len > INT_MAX) {
254
0
    OPENSSL_PUT_ERROR(X509V3, ERR_R_OVERFLOW);
255
0
    return nullptr;
256
0
  }
257
258
7.29k
  UniquePtr<ASN1_OCTET_STRING> oct(ASN1_OCTET_STRING_new());
259
7.29k
  if (oct == nullptr) {
260
0
    return nullptr;
261
0
  }
262
263
7.29k
  ASN1_STRING_set0(oct.get(), ext_der.get(), (int)ext_len);
264
7.29k
  ext_der.release();  // ASN1_STRING_set0 took ownership.
265
266
7.29k
  return X509_EXTENSION_create_by_OBJ(nullptr, obj.get(), crit, oct.get());
267
7.29k
}
268
269
static unsigned char *generic_asn1(const char *value, const X509V3_CTX *ctx,
270
8.80k
                                   size_t *ext_len) {
271
8.80k
  ASN1_TYPE *typ = ASN1_generate_v3(value, ctx);
272
8.80k
  if (typ == nullptr) {
273
4.40k
    return nullptr;
274
4.40k
  }
275
4.40k
  unsigned char *ext_der = nullptr;
276
4.40k
  int len = i2d_ASN1_TYPE(typ, &ext_der);
277
4.40k
  ASN1_TYPE_free(typ);
278
4.40k
  if (len < 0) {
279
0
    return nullptr;
280
0
  }
281
4.40k
  *ext_len = len;
282
4.40k
  return ext_der;
283
4.40k
}
284
285
// This is the main function: add a bunch of extensions based on a config
286
// file section to an extension STACK.
287
288
int X509V3_EXT_add_nconf_sk(const CONF *conf, const X509V3_CTX *ctx,
289
                            const char *section,
290
19.3k
                            STACK_OF(X509_EXTENSION) **sk) {
291
19.3k
  const STACK_OF(CONF_VALUE) *nval = NCONF_get_section(conf, section);
292
19.3k
  if (nval == nullptr) {
293
0
    return 0;
294
0
  }
295
29.0k
  for (size_t i = 0; i < sk_CONF_VALUE_num(nval); i++) {
296
23.0k
    const CONF_VALUE *val = sk_CONF_VALUE_value(nval, i);
297
23.0k
    X509_EXTENSION *ext = X509V3_EXT_nconf(conf, ctx, val->name, val->value);
298
23.0k
    int ok = ext != nullptr &&  //
299
9.72k
             (sk == nullptr || X509v3_add_ext(sk, ext, -1) != nullptr);
300
23.0k
    X509_EXTENSION_free(ext);
301
23.0k
    if (!ok) {
302
13.3k
      return 0;
303
13.3k
    }
304
23.0k
  }
305
6.00k
  return 1;
306
19.3k
}
307
308
// Convenience functions to add extensions to a certificate, CRL and request
309
310
int X509V3_EXT_add_nconf(const CONF *conf, const X509V3_CTX *ctx,
311
19.3k
                         const char *section, X509 *cert) {
312
19.3k
  STACK_OF(X509_EXTENSION) **sk = nullptr;
313
19.3k
  if (cert) {
314
19.3k
    sk = &FromOpaque(cert)->extensions;
315
19.3k
  }
316
19.3k
  return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
317
19.3k
}
318
319
// Same as above but for a CRL
320
321
int X509V3_EXT_CRL_add_nconf(const CONF *conf, const X509V3_CTX *ctx,
322
0
                             const char *section, X509_CRL *crl) {
323
0
  STACK_OF(X509_EXTENSION) **sk = nullptr;
324
0
  if (crl) {
325
0
    sk = &crl->crl->extensions;
326
0
  }
327
0
  return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
328
0
}
329
330
// Add extensions to certificate request
331
332
int X509V3_EXT_REQ_add_nconf(const CONF *conf, const X509V3_CTX *ctx,
333
0
                             const char *section, X509_REQ *req) {
334
0
  STACK_OF(X509_EXTENSION) *extlist = nullptr, **sk = nullptr;
335
0
  int i;
336
0
  if (req) {
337
0
    sk = &extlist;
338
0
  }
339
0
  i = X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
340
0
  if (!i || !sk) {
341
0
    return i;
342
0
  }
343
0
  i = X509_REQ_add_extensions(req, extlist);
344
0
  sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free);
345
0
  return i;
346
0
}
347
348
// Config database functions
349
350
const STACK_OF(CONF_VALUE) *bssl::X509V3_get_section(const X509V3_CTX *ctx,
351
227k
                                                     const char *section) {
352
227k
  if (ctx->db == nullptr) {
353
2.93k
    OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED);
354
2.93k
    return nullptr;
355
2.93k
  }
356
224k
  return NCONF_get_section(ctx->db, section);
357
227k
}
358
359
11.6k
void X509V3_set_nconf(X509V3_CTX *ctx, const CONF *conf) { ctx->db = conf; }
360
361
void X509V3_set_ctx(X509V3_CTX *ctx, const X509 *issuer, const X509 *subj,
362
21.3k
                    const X509_REQ *req, const X509_CRL *crl, int flags) {
363
21.3k
  OPENSSL_memset(ctx, 0, sizeof(*ctx));
364
21.3k
  ctx->issuer_cert = issuer;
365
21.3k
  ctx->subject_cert = subj;
366
21.3k
  ctx->crl = crl;
367
21.3k
  ctx->subject_req = req;
368
21.3k
  ctx->flags = flags;
369
21.3k
}