Coverage Report

Created: 2025-11-03 06:30

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