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