/src/boringssl/crypto/x509v3/v3_alt.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | | * project. |
4 | | */ |
5 | | /* ==================================================================== |
6 | | * Copyright (c) 1999-2003 The OpenSSL Project. All rights reserved. |
7 | | * |
8 | | * Redistribution and use in source and binary forms, with or without |
9 | | * modification, are permitted provided that the following conditions |
10 | | * are met: |
11 | | * |
12 | | * 1. Redistributions of source code must retain the above copyright |
13 | | * notice, this list of conditions and the following disclaimer. |
14 | | * |
15 | | * 2. Redistributions in binary form must reproduce the above copyright |
16 | | * notice, this list of conditions and the following disclaimer in |
17 | | * the documentation and/or other materials provided with the |
18 | | * distribution. |
19 | | * |
20 | | * 3. All advertising materials mentioning features or use of this |
21 | | * software must display the following acknowledgment: |
22 | | * "This product includes software developed by the OpenSSL Project |
23 | | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
24 | | * |
25 | | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
26 | | * endorse or promote products derived from this software without |
27 | | * prior written permission. For written permission, please contact |
28 | | * licensing@OpenSSL.org. |
29 | | * |
30 | | * 5. Products derived from this software may not be called "OpenSSL" |
31 | | * nor may "OpenSSL" appear in their names without prior written |
32 | | * permission of the OpenSSL Project. |
33 | | * |
34 | | * 6. Redistributions of any form whatsoever must retain the following |
35 | | * acknowledgment: |
36 | | * "This product includes software developed by the OpenSSL Project |
37 | | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
38 | | * |
39 | | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
40 | | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
41 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
42 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
43 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
44 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
45 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
46 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
47 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
48 | | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
49 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
50 | | * OF THE POSSIBILITY OF SUCH DAMAGE. |
51 | | * ==================================================================== |
52 | | * |
53 | | * This product includes cryptographic software written by Eric Young |
54 | | * (eay@cryptsoft.com). This product includes software written by Tim |
55 | | * Hudson (tjh@cryptsoft.com). */ |
56 | | |
57 | | #include <stdio.h> |
58 | | #include <string.h> |
59 | | |
60 | | #include <openssl/conf.h> |
61 | | #include <openssl/err.h> |
62 | | #include <openssl/mem.h> |
63 | | #include <openssl/obj.h> |
64 | | #include <openssl/x509v3.h> |
65 | | |
66 | | #include "../x509/internal.h" |
67 | | #include "internal.h" |
68 | | |
69 | | |
70 | | static void *v2i_subject_alt(const X509V3_EXT_METHOD *method, |
71 | | const X509V3_CTX *ctx, |
72 | | const STACK_OF(CONF_VALUE) *nval); |
73 | | static void *v2i_issuer_alt(const X509V3_EXT_METHOD *method, |
74 | | const X509V3_CTX *ctx, |
75 | | const STACK_OF(CONF_VALUE) *nval); |
76 | | static int copy_email(const X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p); |
77 | | static int copy_issuer(const X509V3_CTX *ctx, GENERAL_NAMES *gens); |
78 | | static int do_othername(GENERAL_NAME *gen, const char *value, |
79 | | const X509V3_CTX *ctx); |
80 | | static int do_dirname(GENERAL_NAME *gen, const char *value, |
81 | | const X509V3_CTX *ctx); |
82 | | |
83 | | static STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES_cb( |
84 | 348 | const X509V3_EXT_METHOD *method, void *ext, STACK_OF(CONF_VALUE) *ret) { |
85 | 348 | return i2v_GENERAL_NAMES(method, ext, ret); |
86 | 348 | } |
87 | | |
88 | | const X509V3_EXT_METHOD v3_alt[] = { |
89 | | {NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), 0, 0, 0, 0, 0, 0, |
90 | | i2v_GENERAL_NAMES_cb, v2i_subject_alt, NULL, NULL, NULL}, |
91 | | |
92 | | {NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), 0, 0, 0, 0, 0, 0, |
93 | | i2v_GENERAL_NAMES_cb, v2i_issuer_alt, NULL, NULL, NULL}, |
94 | | |
95 | | {NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES), 0, 0, 0, 0, 0, 0, |
96 | | i2v_GENERAL_NAMES_cb, NULL, NULL, NULL, NULL}, |
97 | | }; |
98 | | |
99 | | STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(const X509V3_EXT_METHOD *method, |
100 | | const GENERAL_NAMES *gens, |
101 | 530 | STACK_OF(CONF_VALUE) *ret) { |
102 | 530 | int ret_was_null = ret == NULL; |
103 | 10.4k | for (size_t i = 0; i < sk_GENERAL_NAME_num(gens); i++) { |
104 | 10.0k | const GENERAL_NAME *gen = sk_GENERAL_NAME_value(gens, i); |
105 | 10.0k | STACK_OF(CONF_VALUE) *tmp = i2v_GENERAL_NAME(method, gen, ret); |
106 | 10.0k | if (tmp == NULL) { |
107 | 131 | if (ret_was_null) { |
108 | 110 | sk_CONF_VALUE_pop_free(ret, X509V3_conf_free); |
109 | 110 | } |
110 | 131 | return NULL; |
111 | 131 | } |
112 | 9.93k | ret = tmp; |
113 | 9.93k | } |
114 | 399 | if (!ret) { |
115 | 127 | return sk_CONF_VALUE_new_null(); |
116 | 127 | } |
117 | 272 | return ret; |
118 | 399 | } |
119 | | |
120 | | STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(const X509V3_EXT_METHOD *method, |
121 | | const GENERAL_NAME *gen, |
122 | 10.1k | STACK_OF(CONF_VALUE) *ret) { |
123 | | // Note the error-handling for this function relies on there being at most |
124 | | // one |X509V3_add_value| call. If there were two and the second failed, we |
125 | | // would need to sometimes free the first call's result. |
126 | 10.1k | unsigned char *p; |
127 | 10.1k | char oline[256], htmp[5]; |
128 | 10.1k | int i; |
129 | 10.1k | switch (gen->type) { |
130 | 119 | case GEN_OTHERNAME: |
131 | 119 | if (!X509V3_add_value("othername", "<unsupported>", &ret)) { |
132 | 0 | return NULL; |
133 | 0 | } |
134 | 119 | break; |
135 | | |
136 | 1.88k | case GEN_X400: |
137 | 1.88k | if (!X509V3_add_value("X400Name", "<unsupported>", &ret)) { |
138 | 0 | return NULL; |
139 | 0 | } |
140 | 1.88k | break; |
141 | | |
142 | 1.88k | case GEN_EDIPARTY: |
143 | 3 | if (!X509V3_add_value("EdiPartyName", "<unsupported>", &ret)) { |
144 | 0 | return NULL; |
145 | 0 | } |
146 | 3 | break; |
147 | | |
148 | 1.13k | case GEN_EMAIL: |
149 | 1.13k | if (!x509V3_add_value_asn1_string("email", gen->d.ia5, &ret)) { |
150 | 39 | return NULL; |
151 | 39 | } |
152 | 1.09k | break; |
153 | | |
154 | 1.12k | case GEN_DNS: |
155 | 1.12k | if (!x509V3_add_value_asn1_string("DNS", gen->d.ia5, &ret)) { |
156 | 55 | return NULL; |
157 | 55 | } |
158 | 1.06k | break; |
159 | | |
160 | 1.06k | case GEN_URI: |
161 | 587 | if (!x509V3_add_value_asn1_string("URI", gen->d.ia5, &ret)) { |
162 | 58 | return NULL; |
163 | 58 | } |
164 | 529 | break; |
165 | | |
166 | 529 | case GEN_DIRNAME: |
167 | 116 | if (X509_NAME_oneline(gen->d.dirn, oline, 256) == NULL || |
168 | 116 | !X509V3_add_value("DirName", oline, &ret)) { |
169 | 0 | return NULL; |
170 | 0 | } |
171 | 116 | break; |
172 | | |
173 | 1.63k | case GEN_IPADD: |
174 | 1.63k | p = gen->d.ip->data; |
175 | 1.63k | if (gen->d.ip->length == 4) { |
176 | 1.05k | BIO_snprintf(oline, sizeof(oline), "%d.%d.%d.%d", p[0], p[1], p[2], |
177 | 1.05k | p[3]); |
178 | 1.05k | } else if (gen->d.ip->length == 16) { |
179 | 355 | oline[0] = 0; |
180 | 3.19k | for (i = 0; i < 8; i++) { |
181 | 2.84k | uint16_t v = ((uint16_t)p[0] << 8) | p[1]; |
182 | 2.84k | BIO_snprintf(htmp, sizeof(htmp), "%X", v); |
183 | 2.84k | p += 2; |
184 | 2.84k | OPENSSL_strlcat(oline, htmp, sizeof(oline)); |
185 | 2.84k | if (i != 7) { |
186 | 2.48k | OPENSSL_strlcat(oline, ":", sizeof(oline)); |
187 | 2.48k | } |
188 | 2.84k | } |
189 | 355 | } else { |
190 | 218 | if (!X509V3_add_value("IP Address", "<invalid>", &ret)) { |
191 | 0 | return NULL; |
192 | 0 | } |
193 | 218 | break; |
194 | 218 | } |
195 | 1.41k | if (!X509V3_add_value("IP Address", oline, &ret)) { |
196 | 0 | return NULL; |
197 | 0 | } |
198 | 1.41k | break; |
199 | | |
200 | 3.57k | case GEN_RID: |
201 | 3.57k | i2t_ASN1_OBJECT(oline, 256, gen->d.rid); |
202 | 3.57k | if (!X509V3_add_value("Registered ID", oline, &ret)) { |
203 | 0 | return NULL; |
204 | 0 | } |
205 | 3.57k | break; |
206 | 10.1k | } |
207 | 10.0k | return ret; |
208 | 10.1k | } |
209 | | |
210 | 1.22k | int GENERAL_NAME_print(BIO *out, const GENERAL_NAME *gen) { |
211 | 1.22k | switch (gen->type) { |
212 | 40 | case GEN_OTHERNAME: |
213 | 40 | BIO_printf(out, "othername:<unsupported>"); |
214 | 40 | break; |
215 | | |
216 | 189 | case GEN_X400: |
217 | 189 | BIO_printf(out, "X400Name:<unsupported>"); |
218 | 189 | break; |
219 | | |
220 | 0 | case GEN_EDIPARTY: |
221 | | // Maybe fix this: it is supported now |
222 | 0 | BIO_printf(out, "EdiPartyName:<unsupported>"); |
223 | 0 | break; |
224 | | |
225 | 118 | case GEN_EMAIL: |
226 | 118 | BIO_printf(out, "email:"); |
227 | 118 | ASN1_STRING_print(out, gen->d.ia5); |
228 | 118 | break; |
229 | | |
230 | 115 | case GEN_DNS: |
231 | 115 | BIO_printf(out, "DNS:"); |
232 | 115 | ASN1_STRING_print(out, gen->d.ia5); |
233 | 115 | break; |
234 | | |
235 | 156 | case GEN_URI: |
236 | 156 | BIO_printf(out, "URI:"); |
237 | 156 | ASN1_STRING_print(out, gen->d.ia5); |
238 | 156 | break; |
239 | | |
240 | 257 | case GEN_DIRNAME: |
241 | 257 | BIO_printf(out, "DirName: "); |
242 | 257 | X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); |
243 | 257 | break; |
244 | | |
245 | 207 | case GEN_IPADD: { |
246 | 207 | const unsigned char *p = gen->d.ip->data; |
247 | 207 | if (gen->d.ip->length == 4) { |
248 | 103 | BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]); |
249 | 104 | } else if (gen->d.ip->length == 16) { |
250 | 42 | BIO_printf(out, "IP Address"); |
251 | 378 | for (int i = 0; i < 8; i++) { |
252 | 336 | uint16_t v = ((uint16_t)p[0] << 8) | p[1]; |
253 | 336 | BIO_printf(out, ":%X", v); |
254 | 336 | p += 2; |
255 | 336 | } |
256 | 42 | BIO_puts(out, "\n"); |
257 | 62 | } else { |
258 | 62 | BIO_printf(out, "IP Address:<invalid>"); |
259 | 62 | break; |
260 | 62 | } |
261 | 145 | break; |
262 | 207 | } |
263 | | |
264 | 145 | case GEN_RID: |
265 | 142 | BIO_printf(out, "Registered ID"); |
266 | 142 | i2a_ASN1_OBJECT(out, gen->d.rid); |
267 | 142 | break; |
268 | 1.22k | } |
269 | 1.22k | return 1; |
270 | 1.22k | } |
271 | | |
272 | | static void *v2i_issuer_alt(const X509V3_EXT_METHOD *method, |
273 | | const X509V3_CTX *ctx, |
274 | 441 | const STACK_OF(CONF_VALUE) *nval) { |
275 | 441 | GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null(); |
276 | 441 | if (gens == NULL) { |
277 | 0 | return NULL; |
278 | 0 | } |
279 | 2.53k | for (size_t i = 0; i < sk_CONF_VALUE_num(nval); i++) { |
280 | 2.47k | const CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i); |
281 | 2.47k | if (x509v3_conf_name_matches(cnf->name, "issuer") && cnf->value && |
282 | 2.47k | !strcmp(cnf->value, "copy")) { |
283 | 1.57k | if (!copy_issuer(ctx, gens)) { |
284 | 277 | goto err; |
285 | 277 | } |
286 | 1.57k | } else { |
287 | 899 | GENERAL_NAME *gen = v2i_GENERAL_NAME(method, ctx, cnf); |
288 | 899 | if (gen == NULL || !sk_GENERAL_NAME_push(gens, gen)) { |
289 | 98 | GENERAL_NAME_free(gen); |
290 | 98 | goto err; |
291 | 98 | } |
292 | 899 | } |
293 | 2.47k | } |
294 | 66 | return gens; |
295 | 375 | err: |
296 | 375 | sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); |
297 | 375 | return NULL; |
298 | 441 | } |
299 | | |
300 | | // Append subject altname of issuer to issuer alt name of subject |
301 | | |
302 | 1.57k | static int copy_issuer(const X509V3_CTX *ctx, GENERAL_NAMES *gens) { |
303 | 1.57k | if (ctx && (ctx->flags == X509V3_CTX_TEST)) { |
304 | 0 | return 1; |
305 | 0 | } |
306 | 1.57k | if (!ctx || !ctx->issuer_cert) { |
307 | 186 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_ISSUER_DETAILS); |
308 | 186 | return 0; |
309 | 186 | } |
310 | 1.38k | int i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1); |
311 | 1.38k | if (i < 0) { |
312 | 488 | return 1; |
313 | 488 | } |
314 | | |
315 | 899 | int ret = 0; |
316 | 899 | GENERAL_NAMES *ialt = NULL; |
317 | 899 | X509_EXTENSION *ext; |
318 | 899 | if (!(ext = X509_get_ext(ctx->issuer_cert, i)) || |
319 | 899 | !(ialt = X509V3_EXT_d2i(ext))) { |
320 | 91 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_ISSUER_DECODE_ERROR); |
321 | 91 | goto err; |
322 | 91 | } |
323 | | |
324 | 24.3k | for (size_t j = 0; j < sk_GENERAL_NAME_num(ialt); j++) { |
325 | 23.4k | GENERAL_NAME *gen = sk_GENERAL_NAME_value(ialt, j); |
326 | 23.4k | if (!sk_GENERAL_NAME_push(gens, gen)) { |
327 | 0 | goto err; |
328 | 0 | } |
329 | | // Ownership of |gen| has moved from |ialt| to |gens|. |
330 | 23.4k | sk_GENERAL_NAME_set(ialt, j, NULL); |
331 | 23.4k | } |
332 | | |
333 | 808 | ret = 1; |
334 | | |
335 | 899 | err: |
336 | 899 | GENERAL_NAMES_free(ialt); |
337 | 899 | return ret; |
338 | 808 | } |
339 | | |
340 | | static void *v2i_subject_alt(const X509V3_EXT_METHOD *method, |
341 | | const X509V3_CTX *ctx, |
342 | 262 | const STACK_OF(CONF_VALUE) *nval) { |
343 | 262 | GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null(); |
344 | 262 | if (gens == NULL) { |
345 | 0 | return NULL; |
346 | 0 | } |
347 | 5.88k | for (size_t i = 0; i < sk_CONF_VALUE_num(nval); i++) { |
348 | 5.70k | const CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i); |
349 | 5.70k | if (x509v3_conf_name_matches(cnf->name, "email") && cnf->value && |
350 | 5.70k | !strcmp(cnf->value, "copy")) { |
351 | 327 | if (!copy_email(ctx, gens, 0)) { |
352 | 17 | goto err; |
353 | 17 | } |
354 | 5.37k | } else if (x509v3_conf_name_matches(cnf->name, "email") && cnf->value && |
355 | 5.37k | !strcmp(cnf->value, "move")) { |
356 | 227 | if (!copy_email(ctx, gens, 1)) { |
357 | 13 | goto err; |
358 | 13 | } |
359 | 5.15k | } else { |
360 | 5.15k | GENERAL_NAME *gen = v2i_GENERAL_NAME(method, ctx, cnf); |
361 | 5.15k | if (gen == NULL || !sk_GENERAL_NAME_push(gens, gen)) { |
362 | 56 | GENERAL_NAME_free(gen); |
363 | 56 | goto err; |
364 | 56 | } |
365 | 5.15k | } |
366 | 5.70k | } |
367 | 176 | return gens; |
368 | 86 | err: |
369 | 86 | sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); |
370 | 86 | return NULL; |
371 | 262 | } |
372 | | |
373 | | // Copy any email addresses in a certificate or request to GENERAL_NAMES |
374 | | |
375 | 554 | static int copy_email(const X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p) { |
376 | 554 | X509_NAME *nm; |
377 | 554 | ASN1_IA5STRING *email = NULL; |
378 | 554 | X509_NAME_ENTRY *ne; |
379 | 554 | GENERAL_NAME *gen = NULL; |
380 | 554 | int i; |
381 | 554 | if (ctx != NULL && ctx->flags == X509V3_CTX_TEST) { |
382 | 0 | return 1; |
383 | 0 | } |
384 | 554 | if (!ctx || (!ctx->subject_cert && !ctx->subject_req)) { |
385 | 30 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_SUBJECT_DETAILS); |
386 | 30 | goto err; |
387 | 30 | } |
388 | | // Find the subject name |
389 | 524 | if (ctx->subject_cert) { |
390 | 524 | nm = X509_get_subject_name(ctx->subject_cert); |
391 | 524 | } else { |
392 | 0 | nm = X509_REQ_get_subject_name(ctx->subject_req); |
393 | 0 | } |
394 | | |
395 | | // Now add any email address(es) to STACK |
396 | 524 | i = -1; |
397 | 524 | while ((i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i)) >= 0) { |
398 | 0 | ne = X509_NAME_get_entry(nm, i); |
399 | 0 | email = ASN1_STRING_dup(X509_NAME_ENTRY_get_data(ne)); |
400 | 0 | if (move_p) { |
401 | 0 | X509_NAME_delete_entry(nm, i); |
402 | 0 | X509_NAME_ENTRY_free(ne); |
403 | 0 | i--; |
404 | 0 | } |
405 | 0 | if (!email || !(gen = GENERAL_NAME_new())) { |
406 | 0 | goto err; |
407 | 0 | } |
408 | 0 | gen->d.ia5 = email; |
409 | 0 | email = NULL; |
410 | 0 | gen->type = GEN_EMAIL; |
411 | 0 | if (!sk_GENERAL_NAME_push(gens, gen)) { |
412 | 0 | goto err; |
413 | 0 | } |
414 | 0 | gen = NULL; |
415 | 0 | } |
416 | | |
417 | 524 | return 1; |
418 | | |
419 | 30 | err: |
420 | 30 | GENERAL_NAME_free(gen); |
421 | 30 | ASN1_IA5STRING_free(email); |
422 | 30 | return 0; |
423 | 524 | } |
424 | | |
425 | | GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, |
426 | | const X509V3_CTX *ctx, |
427 | 16.5k | const STACK_OF(CONF_VALUE) *nval) { |
428 | 16.5k | GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null(); |
429 | 16.5k | if (gens == NULL) { |
430 | 0 | return NULL; |
431 | 0 | } |
432 | 158k | for (size_t i = 0; i < sk_CONF_VALUE_num(nval); i++) { |
433 | 142k | const CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i); |
434 | 142k | GENERAL_NAME *gen = v2i_GENERAL_NAME(method, ctx, cnf); |
435 | 142k | if (gen == NULL || !sk_GENERAL_NAME_push(gens, gen)) { |
436 | 43 | GENERAL_NAME_free(gen); |
437 | 43 | goto err; |
438 | 43 | } |
439 | 142k | } |
440 | 16.4k | return gens; |
441 | 43 | err: |
442 | 43 | sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); |
443 | 43 | return NULL; |
444 | 16.5k | } |
445 | | |
446 | | GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, |
447 | 150k | const X509V3_CTX *ctx, const CONF_VALUE *cnf) { |
448 | 150k | return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0); |
449 | 150k | } |
450 | | |
451 | | GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, |
452 | | const X509V3_EXT_METHOD *method, |
453 | | const X509V3_CTX *ctx, int gen_type, |
454 | 152k | const char *value, int is_nc) { |
455 | 152k | if (!value) { |
456 | 0 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE); |
457 | 0 | return NULL; |
458 | 0 | } |
459 | | |
460 | 152k | GENERAL_NAME *gen = NULL; |
461 | 152k | if (out) { |
462 | 2.03k | gen = out; |
463 | 149k | } else { |
464 | 149k | gen = GENERAL_NAME_new(); |
465 | 149k | if (gen == NULL) { |
466 | 0 | return NULL; |
467 | 0 | } |
468 | 149k | } |
469 | | |
470 | 152k | switch (gen_type) { |
471 | 7.71k | case GEN_URI: |
472 | 74.8k | case GEN_EMAIL: |
473 | 75.5k | case GEN_DNS: { |
474 | 75.5k | ASN1_IA5STRING *str = ASN1_IA5STRING_new(); |
475 | 75.5k | if (str == NULL || !ASN1_STRING_set(str, value, strlen(value))) { |
476 | 0 | ASN1_STRING_free(str); |
477 | 0 | goto err; |
478 | 0 | } |
479 | 75.5k | gen->type = gen_type; |
480 | 75.5k | gen->d.ia5 = str; |
481 | 75.5k | break; |
482 | 75.5k | } |
483 | | |
484 | 253 | case GEN_RID: { |
485 | 253 | ASN1_OBJECT *obj; |
486 | 253 | if (!(obj = OBJ_txt2obj(value, 0))) { |
487 | 6 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT); |
488 | 6 | ERR_add_error_data(2, "value=", value); |
489 | 6 | goto err; |
490 | 6 | } |
491 | 247 | gen->type = GEN_RID; |
492 | 247 | gen->d.rid = obj; |
493 | 247 | break; |
494 | 253 | } |
495 | | |
496 | 4.36k | case GEN_IPADD: |
497 | 4.36k | gen->type = GEN_IPADD; |
498 | 4.36k | if (is_nc) { |
499 | 6 | gen->d.ip = a2i_IPADDRESS_NC(value); |
500 | 4.36k | } else { |
501 | 4.36k | gen->d.ip = a2i_IPADDRESS(value); |
502 | 4.36k | } |
503 | 4.36k | if (gen->d.ip == NULL) { |
504 | 671 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_IP_ADDRESS); |
505 | 671 | ERR_add_error_data(2, "value=", value); |
506 | 671 | goto err; |
507 | 671 | } |
508 | 3.69k | break; |
509 | | |
510 | 64.1k | case GEN_DIRNAME: |
511 | 64.1k | if (!do_dirname(gen, value, ctx)) { |
512 | 256 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_DIRNAME_ERROR); |
513 | 256 | goto err; |
514 | 256 | } |
515 | 63.8k | break; |
516 | | |
517 | 63.8k | case GEN_OTHERNAME: |
518 | 7.73k | if (!do_othername(gen, value, ctx)) { |
519 | 29 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_OTHERNAME_ERROR); |
520 | 29 | goto err; |
521 | 29 | } |
522 | 7.70k | break; |
523 | 7.70k | default: |
524 | 0 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_TYPE); |
525 | 0 | goto err; |
526 | 152k | } |
527 | | |
528 | 151k | return gen; |
529 | | |
530 | 962 | err: |
531 | 962 | if (!out) { |
532 | 950 | GENERAL_NAME_free(gen); |
533 | 950 | } |
534 | 962 | return NULL; |
535 | 152k | } |
536 | | |
537 | | GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, |
538 | | const X509V3_EXT_METHOD *method, |
539 | | const X509V3_CTX *ctx, const CONF_VALUE *cnf, |
540 | 152k | int is_nc) { |
541 | 152k | const char *name = cnf->name; |
542 | 152k | const char *value = cnf->value; |
543 | 152k | if (!value) { |
544 | 107 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE); |
545 | 107 | return NULL; |
546 | 107 | } |
547 | | |
548 | 152k | int type; |
549 | 152k | if (x509v3_conf_name_matches(name, "email")) { |
550 | 67.1k | type = GEN_EMAIL; |
551 | 85.0k | } else if (x509v3_conf_name_matches(name, "URI")) { |
552 | 7.71k | type = GEN_URI; |
553 | 77.3k | } else if (x509v3_conf_name_matches(name, "DNS")) { |
554 | 676 | type = GEN_DNS; |
555 | 76.6k | } else if (x509v3_conf_name_matches(name, "RID")) { |
556 | 253 | type = GEN_RID; |
557 | 76.4k | } else if (x509v3_conf_name_matches(name, "IP")) { |
558 | 4.36k | type = GEN_IPADD; |
559 | 72.0k | } else if (x509v3_conf_name_matches(name, "dirName")) { |
560 | 64.1k | type = GEN_DIRNAME; |
561 | 64.1k | } else if (x509v3_conf_name_matches(name, "otherName")) { |
562 | 7.73k | type = GEN_OTHERNAME; |
563 | 7.73k | } else { |
564 | 179 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_OPTION); |
565 | 179 | ERR_add_error_data(2, "name=", name); |
566 | 179 | return NULL; |
567 | 179 | } |
568 | | |
569 | 152k | return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc); |
570 | 152k | } |
571 | | |
572 | | static int do_othername(GENERAL_NAME *gen, const char *value, |
573 | 7.73k | const X509V3_CTX *ctx) { |
574 | 7.73k | const char *semicolon = strchr(value, ';'); |
575 | 7.73k | if (semicolon == NULL) { |
576 | 3 | return 0; |
577 | 3 | } |
578 | | |
579 | 7.72k | OTHERNAME *name = OTHERNAME_new(); |
580 | 7.72k | if (name == NULL) { |
581 | 0 | return 0; |
582 | 0 | } |
583 | | |
584 | 7.72k | char *objtmp = OPENSSL_strndup(value, semicolon - value); |
585 | 7.72k | if (objtmp == NULL) { |
586 | 0 | goto err; |
587 | 0 | } |
588 | 7.72k | ASN1_OBJECT_free(name->type_id); |
589 | 7.72k | name->type_id = OBJ_txt2obj(objtmp, /*dont_search_names=*/0); |
590 | 7.72k | OPENSSL_free(objtmp); |
591 | 7.72k | if (name->type_id == NULL) { |
592 | 11 | goto err; |
593 | 11 | } |
594 | | |
595 | 7.71k | ASN1_TYPE_free(name->value); |
596 | 7.71k | name->value = ASN1_generate_v3(semicolon + 1, ctx); |
597 | 7.71k | if (name->value == NULL) { |
598 | 15 | goto err; |
599 | 15 | } |
600 | | |
601 | 7.70k | gen->type = GEN_OTHERNAME; |
602 | 7.70k | gen->d.otherName = name; |
603 | 7.70k | return 1; |
604 | | |
605 | 26 | err: |
606 | 26 | OTHERNAME_free(name); |
607 | 26 | return 0; |
608 | 7.71k | } |
609 | | |
610 | | static int do_dirname(GENERAL_NAME *gen, const char *value, |
611 | 64.1k | const X509V3_CTX *ctx) { |
612 | 64.1k | int ret = 0; |
613 | 64.1k | X509_NAME *nm = X509_NAME_new(); |
614 | 64.1k | if (nm == NULL) { |
615 | 0 | goto err; |
616 | 0 | } |
617 | 64.1k | const STACK_OF(CONF_VALUE) *sk = X509V3_get_section(ctx, value); |
618 | 64.1k | if (sk == NULL) { |
619 | 224 | OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND); |
620 | 224 | ERR_add_error_data(2, "section=", value); |
621 | 224 | goto err; |
622 | 224 | } |
623 | | // FIXME: should allow other character types... |
624 | 63.9k | if (!X509V3_NAME_from_section(nm, sk, MBSTRING_ASC)) { |
625 | 32 | goto err; |
626 | 32 | } |
627 | 63.8k | gen->type = GEN_DIRNAME; |
628 | 63.8k | gen->d.dirn = nm; |
629 | 63.8k | ret = 1; |
630 | | |
631 | 64.1k | err: |
632 | 64.1k | if (!ret) { |
633 | 256 | X509_NAME_free(nm); |
634 | 256 | } |
635 | 64.1k | return ret; |
636 | 63.8k | } |