1 /* $OpenBSD: x509_alt.c,v 1.1 2020/06/04 15:19:31 jsing Exp $ */
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  */
58 
59 #include <stdio.h>
60 #include <string.h>
61 
62 #include <openssl/conf.h>
63 #include <openssl/err.h>
64 #include <openssl/x509v3.h>
65 
66 static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
67     X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
68 static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method,
69     X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
70 static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p);
71 static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens);
72 static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
73 static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
74 
75 const X509V3_EXT_METHOD v3_alt[] = {
76 	{
77 		.ext_nid = NID_subject_alt_name,
78 		.ext_flags = 0,
79 		.it = &GENERAL_NAMES_it,
80 		.ext_new = NULL,
81 		.ext_free = NULL,
82 		.d2i = NULL,
83 		.i2d = NULL,
84 		.i2s = NULL,
85 		.s2i = NULL,
86 		.i2v = (X509V3_EXT_I2V)i2v_GENERAL_NAMES,
87 		.v2i = (X509V3_EXT_V2I)v2i_subject_alt,
88 		.i2r = NULL,
89 		.r2i = NULL,
90 		.usr_data = NULL,
91 	},
92 	{
93 		.ext_nid = NID_issuer_alt_name,
94 		.ext_flags = 0,
95 		.it = &GENERAL_NAMES_it,
96 		.ext_new = NULL,
97 		.ext_free = NULL,
98 		.d2i = NULL,
99 		.i2d = NULL,
100 		.i2s = NULL,
101 		.s2i = NULL,
102 		.i2v = (X509V3_EXT_I2V)i2v_GENERAL_NAMES,
103 		.v2i = (X509V3_EXT_V2I)v2i_issuer_alt,
104 		.i2r = NULL,
105 		.r2i = NULL,
106 		.usr_data = NULL,
107 	},
108 	{
109 		.ext_nid = NID_certificate_issuer,
110 		.ext_flags = 0,
111 		.it = &GENERAL_NAMES_it,
112 		.ext_new = NULL,
113 		.ext_free = NULL,
114 		.d2i = NULL,
115 		.i2d = NULL,
116 		.i2s = NULL,
117 		.s2i = NULL,
118 		.i2v = (X509V3_EXT_I2V)i2v_GENERAL_NAMES,
119 		.v2i = NULL,
120 		.i2r = NULL,
121 		.r2i = NULL,
122 		.usr_data = NULL,
123 	},
124 };
125 
126 STACK_OF(CONF_VALUE) *
127 i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, GENERAL_NAMES *gens,
128     STACK_OF(CONF_VALUE) *ret)
129 {
130 	STACK_OF(CONF_VALUE) *free_ret = NULL;
131 	GENERAL_NAME *gen;
132 	int i;
133 
134 	if (ret == NULL) {
135 		if ((free_ret = ret = sk_CONF_VALUE_new_null()) == NULL)
136 			return NULL;
137 	}
138 
139 	for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
140 		if ((gen = sk_GENERAL_NAME_value(gens, i)) == NULL)
141 			goto err;
142 		if ((ret = i2v_GENERAL_NAME(method, gen, ret)) == NULL)
143 			goto err;
144 	}
145 
146 	return ret;
147 
148  err:
149 	sk_CONF_VALUE_pop_free(free_ret, X509V3_conf_free);
150 
151 	return NULL;
152 }
153 
154 STACK_OF(CONF_VALUE) *
155 i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen,
156     STACK_OF(CONF_VALUE) *ret)
157 {
158 	STACK_OF(CONF_VALUE) *free_ret = NULL;
159 	unsigned char *p;
160 	char oline[256], htmp[5];
161 	int i;
162 
163 	if (ret == NULL) {
164 		if ((free_ret = ret = sk_CONF_VALUE_new_null()) == NULL)
165 			return NULL;
166 	}
167 
168 	switch (gen->type) {
169 	case GEN_OTHERNAME:
170 		if (!X509V3_add_value("othername", "<unsupported>", &ret))
171 			goto err;
172 		break;
173 
174 	case GEN_X400:
175 		if (!X509V3_add_value("X400Name", "<unsupported>", &ret))
176 			goto err;
177 		break;
178 
179 	case GEN_EDIPARTY:
180 		if (!X509V3_add_value("EdiPartyName", "<unsupported>", &ret))
181 			goto err;
182 		break;
183 
184 	case GEN_EMAIL:
185 		if (!X509V3_add_value_uchar("email", gen->d.ia5->data, &ret))
186 			goto err;
187 		break;
188 
189 	case GEN_DNS:
190 		if (!X509V3_add_value_uchar("DNS", gen->d.ia5->data, &ret))
191 			goto err;
192 		break;
193 
194 	case GEN_URI:
195 		if (!X509V3_add_value_uchar("URI", gen->d.ia5->data, &ret))
196 			goto err;
197 		break;
198 
199 	case GEN_DIRNAME:
200 		if (X509_NAME_oneline(gen->d.dirn, oline, 256) == NULL)
201 			goto err;
202 		if (!X509V3_add_value("DirName", oline, &ret))
203 			goto err;
204 		break;
205 
206 	case GEN_IPADD: /* XXX */
207 		p = gen->d.ip->data;
208 		if (gen->d.ip->length == 4)
209 			(void) snprintf(oline, sizeof oline,
210 			    "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
211 		else if (gen->d.ip->length == 16) {
212 			oline[0] = 0;
213 			for (i = 0; i < 8; i++) {
214 				(void) snprintf(htmp, sizeof htmp,
215 				    "%X", p[0] << 8 | p[1]);
216 				p += 2;
217 				strlcat(oline, htmp, sizeof(oline));
218 				if (i != 7)
219 					strlcat(oline, ":", sizeof(oline));
220 			}
221 		} else {
222 			if (!X509V3_add_value("IP Address", "<invalid>", &ret))
223 				goto err;
224 			break;
225 		}
226 		if (!X509V3_add_value("IP Address", oline, &ret))
227 			goto err;
228 		break;
229 
230 	case GEN_RID:
231 		if (!i2t_ASN1_OBJECT(oline, 256, gen->d.rid))
232 			goto err;
233 		if (!X509V3_add_value("Registered ID", oline, &ret))
234 			goto err;
235 		break;
236 	}
237 
238 	return ret;
239 
240  err:
241 	sk_CONF_VALUE_pop_free(free_ret, X509V3_conf_free);
242 
243 	return NULL;
244 }
245 
246 int
247 GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
248 {
249 	unsigned char *p;
250 	int i;
251 
252 	switch (gen->type) {
253 	case GEN_OTHERNAME:
254 		BIO_printf(out, "othername:<unsupported>");
255 		break;
256 
257 	case GEN_X400:
258 		BIO_printf(out, "X400Name:<unsupported>");
259 		break;
260 
261 	case GEN_EDIPARTY:
262 		/* Maybe fix this: it is supported now */
263 		BIO_printf(out, "EdiPartyName:<unsupported>");
264 		break;
265 
266 	case GEN_EMAIL:
267 		BIO_printf(out, "email:%s", gen->d.ia5->data);
268 		break;
269 
270 	case GEN_DNS:
271 		BIO_printf(out, "DNS:%s", gen->d.ia5->data);
272 		break;
273 
274 	case GEN_URI:
275 		BIO_printf(out, "URI:%s", gen->d.ia5->data);
276 		break;
277 
278 	case GEN_DIRNAME:
279 		BIO_printf(out, "DirName: ");
280 		X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE);
281 		break;
282 
283 	case GEN_IPADD:
284 		p = gen->d.ip->data;
285 		if (gen->d.ip->length == 4)
286 			BIO_printf(out, "IP Address:%d.%d.%d.%d",
287 			    p[0], p[1], p[2], p[3]);
288 		else if (gen->d.ip->length == 16) {
289 			BIO_printf(out, "IP Address");
290 			for (i = 0; i < 8; i++) {
291 				BIO_printf(out, ":%X", p[0] << 8 | p[1]);
292 				p += 2;
293 			}
294 			BIO_puts(out, "\n");
295 		} else {
296 			BIO_printf(out, "IP Address:<invalid>");
297 			break;
298 		}
299 		break;
300 
301 	case GEN_RID:
302 		BIO_printf(out, "Registered ID");
303 		i2a_ASN1_OBJECT(out, gen->d.rid);
304 		break;
305 	}
306 	return 1;
307 }
308 
309 static GENERAL_NAMES *
310 v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
311     STACK_OF(CONF_VALUE) *nval)
312 {
313 	GENERAL_NAMES *gens = NULL;
314 	CONF_VALUE *cnf;
315 	int i;
316 
317 	if ((gens = sk_GENERAL_NAME_new_null()) == NULL) {
318 		X509V3error(ERR_R_MALLOC_FAILURE);
319 		return NULL;
320 	}
321 	for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
322 		cnf = sk_CONF_VALUE_value(nval, i);
323 		if (name_cmp(cnf->name, "issuer") == 0 && cnf->value != NULL &&
324 		    strcmp(cnf->value, "copy") == 0) {
325 			if (!copy_issuer(ctx, gens))
326 				goto err;
327 		} else {
328 			GENERAL_NAME *gen;
329 			if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL)
330 				goto err;
331 			if (sk_GENERAL_NAME_push(gens, gen) == 0) {
332 				GENERAL_NAME_free(gen);
333 				goto err;
334 			}
335 		}
336 	}
337 	return gens;
338 
339 err:
340 	sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
341 	return NULL;
342 }
343 
344 /* Append subject altname of issuer to issuer alt name of subject */
345 
346 static int
347 copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens)
348 {
349 	GENERAL_NAMES *ialt;
350 	GENERAL_NAME *gen;
351 	X509_EXTENSION *ext;
352 	int i;
353 
354 	if (ctx && (ctx->flags == CTX_TEST))
355 		return 1;
356 	if (!ctx || !ctx->issuer_cert) {
357 		X509V3error(X509V3_R_NO_ISSUER_DETAILS);
358 		goto err;
359 	}
360 	i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1);
361 	if (i < 0)
362 		return 1;
363 	if (!(ext = X509_get_ext(ctx->issuer_cert, i)) ||
364 	    !(ialt = X509V3_EXT_d2i(ext))) {
365 		X509V3error(X509V3_R_ISSUER_DECODE_ERROR);
366 		goto err;
367 	}
368 
369 	for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) {
370 		gen = sk_GENERAL_NAME_value(ialt, i);
371 		if (!sk_GENERAL_NAME_push(gens, gen)) {
372 			X509V3error(ERR_R_MALLOC_FAILURE);
373 			goto err;
374 		}
375 	}
376 	sk_GENERAL_NAME_free(ialt);
377 
378 	return 1;
379 
380 err:
381 	return 0;
382 
383 }
384 
385 static GENERAL_NAMES *
386 v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
387     STACK_OF(CONF_VALUE) *nval)
388 {
389 	GENERAL_NAMES *gens = NULL;
390 	CONF_VALUE *cnf;
391 	int i;
392 
393 	if (!(gens = sk_GENERAL_NAME_new_null())) {
394 		X509V3error(ERR_R_MALLOC_FAILURE);
395 		return NULL;
396 	}
397 	for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
398 		cnf = sk_CONF_VALUE_value(nval, i);
399 		if (!name_cmp(cnf->name, "email") && cnf->value &&
400 		    !strcmp(cnf->value, "copy")) {
401 			if (!copy_email(ctx, gens, 0))
402 				goto err;
403 		} else if (!name_cmp(cnf->name, "email") && cnf->value &&
404 		    !strcmp(cnf->value, "move")) {
405 			if (!copy_email(ctx, gens, 1))
406 				goto err;
407 		} else {
408 			GENERAL_NAME *gen;
409 			if (!(gen = v2i_GENERAL_NAME(method, ctx, cnf)))
410 				goto err;
411 			if (sk_GENERAL_NAME_push(gens, gen) == 0) {
412 				GENERAL_NAME_free(gen);
413 				goto err;
414 			}
415 		}
416 	}
417 	return gens;
418 
419 err:
420 	sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
421 	return NULL;
422 }
423 
424 /* Copy any email addresses in a certificate or request to
425  * GENERAL_NAMES
426  */
427 
428 static int
429 copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p)
430 {
431 	X509_NAME *nm;
432 	ASN1_IA5STRING *email = NULL;
433 	X509_NAME_ENTRY *ne;
434 	GENERAL_NAME *gen = NULL;
435 	int i;
436 
437 	if (ctx != NULL && ctx->flags == CTX_TEST)
438 		return 1;
439 	if (!ctx || (!ctx->subject_cert && !ctx->subject_req)) {
440 		X509V3error(X509V3_R_NO_SUBJECT_DETAILS);
441 		goto err;
442 	}
443 	/* Find the subject name */
444 	if (ctx->subject_cert)
445 		nm = X509_get_subject_name(ctx->subject_cert);
446 	else
447 		nm = X509_REQ_get_subject_name(ctx->subject_req);
448 
449 	/* Now add any email address(es) to STACK */
450 	i = -1;
451 	while ((i = X509_NAME_get_index_by_NID(nm,
452 	    NID_pkcs9_emailAddress, i)) >= 0) {
453 		ne = X509_NAME_get_entry(nm, i);
454 		email = ASN1_STRING_dup(X509_NAME_ENTRY_get_data(ne));
455 		if (move_p) {
456 			X509_NAME_delete_entry(nm, i);
457 			X509_NAME_ENTRY_free(ne);
458 			i--;
459 		}
460 		if (!email || !(gen = GENERAL_NAME_new())) {
461 			X509V3error(ERR_R_MALLOC_FAILURE);
462 			goto err;
463 		}
464 		gen->d.ia5 = email;
465 		email = NULL;
466 		gen->type = GEN_EMAIL;
467 		if (!sk_GENERAL_NAME_push(gens, gen)) {
468 			X509V3error(ERR_R_MALLOC_FAILURE);
469 			goto err;
470 		}
471 		gen = NULL;
472 	}
473 
474 	return 1;
475 
476 err:
477 	GENERAL_NAME_free(gen);
478 	ASN1_IA5STRING_free(email);
479 	return 0;
480 }
481 
482 GENERAL_NAMES *
483 v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
484     STACK_OF(CONF_VALUE) *nval)
485 {
486 	GENERAL_NAME *gen;
487 	GENERAL_NAMES *gens = NULL;
488 	CONF_VALUE *cnf;
489 	int i;
490 
491 	if (!(gens = sk_GENERAL_NAME_new_null())) {
492 		X509V3error(ERR_R_MALLOC_FAILURE);
493 		return NULL;
494 	}
495 	for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
496 		cnf = sk_CONF_VALUE_value(nval, i);
497 		if (!(gen = v2i_GENERAL_NAME(method, ctx, cnf)))
498 			goto err;
499 		if (sk_GENERAL_NAME_push(gens, gen) == 0) {
500 			GENERAL_NAME_free(gen);
501 			goto err;
502 		}
503 	}
504 	return gens;
505 
506 err:
507 	sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
508 	return NULL;
509 }
510 
511 GENERAL_NAME *
512 v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
513     CONF_VALUE *cnf)
514 {
515 	return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0);
516 }
517 
518 GENERAL_NAME *
519 a2i_GENERAL_NAME(GENERAL_NAME *out, const X509V3_EXT_METHOD *method,
520     X509V3_CTX *ctx, int gen_type, const char *value, int is_nc)
521 {
522 	char is_string = 0;
523 	GENERAL_NAME *gen = NULL;
524 
525 	if (!value) {
526 		X509V3error(X509V3_R_MISSING_VALUE);
527 		return NULL;
528 	}
529 
530 	if (out)
531 		gen = out;
532 	else {
533 		gen = GENERAL_NAME_new();
534 		if (gen == NULL) {
535 			X509V3error(ERR_R_MALLOC_FAILURE);
536 			return NULL;
537 		}
538 	}
539 
540 	switch (gen_type) {
541 	case GEN_URI:
542 	case GEN_EMAIL:
543 	case GEN_DNS:
544 		is_string = 1;
545 		break;
546 
547 	case GEN_RID:
548 		{
549 			ASN1_OBJECT *obj;
550 			if (!(obj = OBJ_txt2obj(value, 0))) {
551 				X509V3error(X509V3_R_BAD_OBJECT);
552 				ERR_asprintf_error_data("value=%s", value);
553 				goto err;
554 			}
555 			gen->d.rid = obj;
556 		}
557 		break;
558 
559 	case GEN_IPADD:
560 		if (is_nc)
561 			gen->d.ip = a2i_IPADDRESS_NC(value);
562 		else
563 			gen->d.ip = a2i_IPADDRESS(value);
564 		if (gen->d.ip == NULL) {
565 			X509V3error(X509V3_R_BAD_IP_ADDRESS);
566 			ERR_asprintf_error_data("value=%s", value);
567 			goto err;
568 		}
569 		break;
570 
571 	case GEN_DIRNAME:
572 		if (!do_dirname(gen, value, ctx)) {
573 			X509V3error(X509V3_R_DIRNAME_ERROR);
574 			goto err;
575 		}
576 		break;
577 
578 	case GEN_OTHERNAME:
579 		if (!do_othername(gen, value, ctx)) {
580 			X509V3error(X509V3_R_OTHERNAME_ERROR);
581 			goto err;
582 		}
583 		break;
584 
585 	default:
586 		X509V3error(X509V3_R_UNSUPPORTED_TYPE);
587 		goto err;
588 	}
589 
590 	if (is_string) {
591 		if (!(gen->d.ia5 = ASN1_IA5STRING_new()) ||
592 		    !ASN1_STRING_set(gen->d.ia5, value, strlen(value))) {
593 			X509V3error(ERR_R_MALLOC_FAILURE);
594 			goto err;
595 		}
596 	}
597 
598 	gen->type = gen_type;
599 
600 	return gen;
601 
602 err:
603 	if (out == NULL)
604 		GENERAL_NAME_free(gen);
605 	return NULL;
606 }
607 
608 GENERAL_NAME *
609 v2i_GENERAL_NAME_ex(GENERAL_NAME *out, const X509V3_EXT_METHOD *method,
610     X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc)
611 {
612 	int type;
613 	char *name, *value;
614 
615 	name = cnf->name;
616 	value = cnf->value;
617 
618 	if (!value) {
619 		X509V3error(X509V3_R_MISSING_VALUE);
620 		return NULL;
621 	}
622 
623 	if (!name_cmp(name, "email"))
624 		type = GEN_EMAIL;
625 	else if (!name_cmp(name, "URI"))
626 		type = GEN_URI;
627 	else if (!name_cmp(name, "DNS"))
628 		type = GEN_DNS;
629 	else if (!name_cmp(name, "RID"))
630 		type = GEN_RID;
631 	else if (!name_cmp(name, "IP"))
632 		type = GEN_IPADD;
633 	else if (!name_cmp(name, "dirName"))
634 		type = GEN_DIRNAME;
635 	else if (!name_cmp(name, "otherName"))
636 		type = GEN_OTHERNAME;
637 	else {
638 		X509V3error(X509V3_R_UNSUPPORTED_OPTION);
639 		ERR_asprintf_error_data("name=%s", name);
640 		return NULL;
641 	}
642 
643 	return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc);
644 }
645 
646 static int
647 do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx)
648 {
649 	char *objtmp = NULL, *p;
650 	int objlen;
651 
652 	if (!(p = strchr(value, ';')))
653 		return 0;
654 	if (!(gen->d.otherName = OTHERNAME_new()))
655 		return 0;
656 	/* Free this up because we will overwrite it.
657 	 * no need to free type_id because it is static
658 	 */
659 	ASN1_TYPE_free(gen->d.otherName->value);
660 	if (!(gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx)))
661 		return 0;
662 	objlen = p - value;
663 	objtmp = malloc(objlen + 1);
664 	if (objtmp) {
665 		strlcpy(objtmp, value, objlen + 1);
666 		gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0);
667 		free(objtmp);
668 	} else
669 		gen->d.otherName->type_id = NULL;
670 	if (!gen->d.otherName->type_id)
671 		return 0;
672 	return 1;
673 }
674 
675 static int
676 do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx)
677 {
678 	int ret;
679 	STACK_OF(CONF_VALUE) *sk;
680 	X509_NAME *nm;
681 
682 	if (!(nm = X509_NAME_new()))
683 		return 0;
684 	sk = X509V3_get_section(ctx, value);
685 	if (!sk) {
686 		X509V3error(X509V3_R_SECTION_NOT_FOUND);
687 		ERR_asprintf_error_data("section=%s", value);
688 		X509_NAME_free(nm);
689 		return 0;
690 	}
691 	/* FIXME: should allow other character types... */
692 	ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC);
693 	if (!ret)
694 		X509_NAME_free(nm);
695 	gen->d.dirn = nm;
696 	X509V3_section_free(ctx, sk);
697 
698 	return ret;
699 }
700