xref: /onnv-gate/usr/src/common/openssl/crypto/x509v3/v3_lib.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /* v3_lib.c */
2*0Sstevel@tonic-gate /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3*0Sstevel@tonic-gate  * project 1999.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate /* ====================================================================
6*0Sstevel@tonic-gate  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7*0Sstevel@tonic-gate  *
8*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
9*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
10*0Sstevel@tonic-gate  * are met:
11*0Sstevel@tonic-gate  *
12*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
13*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
14*0Sstevel@tonic-gate  *
15*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
16*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
17*0Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
18*0Sstevel@tonic-gate  *    distribution.
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this
21*0Sstevel@tonic-gate  *    software must display the following acknowledgment:
22*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
23*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24*0Sstevel@tonic-gate  *
25*0Sstevel@tonic-gate  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26*0Sstevel@tonic-gate  *    endorse or promote products derived from this software without
27*0Sstevel@tonic-gate  *    prior written permission. For written permission, please contact
28*0Sstevel@tonic-gate  *    licensing@OpenSSL.org.
29*0Sstevel@tonic-gate  *
30*0Sstevel@tonic-gate  * 5. Products derived from this software may not be called "OpenSSL"
31*0Sstevel@tonic-gate  *    nor may "OpenSSL" appear in their names without prior written
32*0Sstevel@tonic-gate  *    permission of the OpenSSL Project.
33*0Sstevel@tonic-gate  *
34*0Sstevel@tonic-gate  * 6. Redistributions of any form whatsoever must retain the following
35*0Sstevel@tonic-gate  *    acknowledgment:
36*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
37*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38*0Sstevel@tonic-gate  *
39*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40*0Sstevel@tonic-gate  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42*0Sstevel@tonic-gate  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43*0Sstevel@tonic-gate  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44*0Sstevel@tonic-gate  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46*0Sstevel@tonic-gate  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48*0Sstevel@tonic-gate  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49*0Sstevel@tonic-gate  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50*0Sstevel@tonic-gate  * OF THE POSSIBILITY OF SUCH DAMAGE.
51*0Sstevel@tonic-gate  * ====================================================================
52*0Sstevel@tonic-gate  *
53*0Sstevel@tonic-gate  * This product includes cryptographic software written by Eric Young
54*0Sstevel@tonic-gate  * (eay@cryptsoft.com).  This product includes software written by Tim
55*0Sstevel@tonic-gate  * Hudson (tjh@cryptsoft.com).
56*0Sstevel@tonic-gate  *
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate /* X509 v3 extension utilities */
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #include <stdio.h>
61*0Sstevel@tonic-gate #include "cryptlib.h"
62*0Sstevel@tonic-gate #include <openssl/conf.h>
63*0Sstevel@tonic-gate #include <openssl/x509v3.h>
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #include "ext_dat.h"
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate static int ext_cmp(const X509V3_EXT_METHOD * const *a,
70*0Sstevel@tonic-gate 		const X509V3_EXT_METHOD * const *b);
71*0Sstevel@tonic-gate static void ext_list_free(X509V3_EXT_METHOD *ext);
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate int X509V3_EXT_add(X509V3_EXT_METHOD *ext)
74*0Sstevel@tonic-gate {
75*0Sstevel@tonic-gate 	if(!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp))) {
76*0Sstevel@tonic-gate 		X509V3err(X509V3_F_X509V3_EXT_ADD,ERR_R_MALLOC_FAILURE);
77*0Sstevel@tonic-gate 		return 0;
78*0Sstevel@tonic-gate 	}
79*0Sstevel@tonic-gate 	if(!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
80*0Sstevel@tonic-gate 		X509V3err(X509V3_F_X509V3_EXT_ADD,ERR_R_MALLOC_FAILURE);
81*0Sstevel@tonic-gate 		return 0;
82*0Sstevel@tonic-gate 	}
83*0Sstevel@tonic-gate 	return 1;
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate static int ext_cmp(const X509V3_EXT_METHOD * const *a,
87*0Sstevel@tonic-gate 		const X509V3_EXT_METHOD * const *b)
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate 	return ((*a)->ext_nid - (*b)->ext_nid);
90*0Sstevel@tonic-gate }
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid)
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate 	X509V3_EXT_METHOD tmp, *t = &tmp, **ret;
95*0Sstevel@tonic-gate 	int idx;
96*0Sstevel@tonic-gate 	if(nid < 0) return NULL;
97*0Sstevel@tonic-gate 	tmp.ext_nid = nid;
98*0Sstevel@tonic-gate 	ret = (X509V3_EXT_METHOD **) OBJ_bsearch((char *)&t,
99*0Sstevel@tonic-gate 			(char *)standard_exts, STANDARD_EXTENSION_COUNT,
100*0Sstevel@tonic-gate 			sizeof(X509V3_EXT_METHOD *), (int (*)(const void *, const void *))ext_cmp);
101*0Sstevel@tonic-gate 	if(ret) return *ret;
102*0Sstevel@tonic-gate 	if(!ext_list) return NULL;
103*0Sstevel@tonic-gate 	idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp);
104*0Sstevel@tonic-gate 	if(idx == -1) return NULL;
105*0Sstevel@tonic-gate 	return sk_X509V3_EXT_METHOD_value(ext_list, idx);
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext)
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate 	int nid;
111*0Sstevel@tonic-gate 	if((nid = OBJ_obj2nid(ext->object)) == NID_undef) return NULL;
112*0Sstevel@tonic-gate 	return X509V3_EXT_get_nid(nid);
113*0Sstevel@tonic-gate }
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 	for(;extlist->ext_nid!=-1;extlist++)
119*0Sstevel@tonic-gate 			if(!X509V3_EXT_add(extlist)) return 0;
120*0Sstevel@tonic-gate 	return 1;
121*0Sstevel@tonic-gate }
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate int X509V3_EXT_add_alias(int nid_to, int nid_from)
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate 	X509V3_EXT_METHOD *ext, *tmpext;
126*0Sstevel@tonic-gate 	if(!(ext = X509V3_EXT_get_nid(nid_from))) {
127*0Sstevel@tonic-gate 		X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS,X509V3_R_EXTENSION_NOT_FOUND);
128*0Sstevel@tonic-gate 		return 0;
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 	if(!(tmpext = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) {
131*0Sstevel@tonic-gate 		X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS,ERR_R_MALLOC_FAILURE);
132*0Sstevel@tonic-gate 		return 0;
133*0Sstevel@tonic-gate 	}
134*0Sstevel@tonic-gate 	*tmpext = *ext;
135*0Sstevel@tonic-gate 	tmpext->ext_nid = nid_to;
136*0Sstevel@tonic-gate 	tmpext->ext_flags |= X509V3_EXT_DYNAMIC;
137*0Sstevel@tonic-gate 	return X509V3_EXT_add(tmpext);
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate void X509V3_EXT_cleanup(void)
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free);
143*0Sstevel@tonic-gate 	ext_list = NULL;
144*0Sstevel@tonic-gate }
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate static void ext_list_free(X509V3_EXT_METHOD *ext)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	if(ext->ext_flags & X509V3_EXT_DYNAMIC) OPENSSL_free(ext);
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate /* Legacy function: we don't need to add standard extensions
152*0Sstevel@tonic-gate  * any more because they are now kept in ext_dat.h.
153*0Sstevel@tonic-gate  */
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate int X509V3_add_standard_extensions(void)
156*0Sstevel@tonic-gate {
157*0Sstevel@tonic-gate 	return 1;
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate /* Return an extension internal structure */
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate void *X509V3_EXT_d2i(X509_EXTENSION *ext)
163*0Sstevel@tonic-gate {
164*0Sstevel@tonic-gate 	X509V3_EXT_METHOD *method;
165*0Sstevel@tonic-gate 	unsigned char *p;
166*0Sstevel@tonic-gate 	if(!(method = X509V3_EXT_get(ext))) return NULL;
167*0Sstevel@tonic-gate 	p = ext->value->data;
168*0Sstevel@tonic-gate 	if(method->it) return ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it));
169*0Sstevel@tonic-gate 	return method->d2i(NULL, &p, ext->value->length);
170*0Sstevel@tonic-gate }
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate /* Get critical flag and decoded version of extension from a NID.
173*0Sstevel@tonic-gate  * The "idx" variable returns the last found extension and can
174*0Sstevel@tonic-gate  * be used to retrieve multiple extensions of the same NID.
175*0Sstevel@tonic-gate  * However multiple extensions with the same NID is usually
176*0Sstevel@tonic-gate  * due to a badly encoded certificate so if idx is NULL we
177*0Sstevel@tonic-gate  * choke if multiple extensions exist.
178*0Sstevel@tonic-gate  * The "crit" variable is set to the critical value.
179*0Sstevel@tonic-gate  * The return value is the decoded extension or NULL on
180*0Sstevel@tonic-gate  * error. The actual error can have several different causes,
181*0Sstevel@tonic-gate  * the value of *crit reflects the cause:
182*0Sstevel@tonic-gate  * >= 0, extension found but not decoded (reflects critical value).
183*0Sstevel@tonic-gate  * -1 extension not found.
184*0Sstevel@tonic-gate  * -2 extension occurs more than once.
185*0Sstevel@tonic-gate  */
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx)
188*0Sstevel@tonic-gate {
189*0Sstevel@tonic-gate 	int lastpos, i;
190*0Sstevel@tonic-gate 	X509_EXTENSION *ex, *found_ex = NULL;
191*0Sstevel@tonic-gate 	if(!x) {
192*0Sstevel@tonic-gate 		if(idx) *idx = -1;
193*0Sstevel@tonic-gate 		if(crit) *crit = -1;
194*0Sstevel@tonic-gate 		return NULL;
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate 	if(idx) lastpos = *idx + 1;
197*0Sstevel@tonic-gate 	else lastpos = 0;
198*0Sstevel@tonic-gate 	if(lastpos < 0) lastpos = 0;
199*0Sstevel@tonic-gate 	for(i = lastpos; i < sk_X509_EXTENSION_num(x); i++)
200*0Sstevel@tonic-gate 	{
201*0Sstevel@tonic-gate 		ex = sk_X509_EXTENSION_value(x, i);
202*0Sstevel@tonic-gate 		if(OBJ_obj2nid(ex->object) == nid) {
203*0Sstevel@tonic-gate 			if(idx) {
204*0Sstevel@tonic-gate 				*idx = i;
205*0Sstevel@tonic-gate 				found_ex = ex;
206*0Sstevel@tonic-gate 				break;
207*0Sstevel@tonic-gate 			} else if(found_ex) {
208*0Sstevel@tonic-gate 				/* Found more than one */
209*0Sstevel@tonic-gate 				if(crit) *crit = -2;
210*0Sstevel@tonic-gate 				return NULL;
211*0Sstevel@tonic-gate 			}
212*0Sstevel@tonic-gate 			found_ex = ex;
213*0Sstevel@tonic-gate 		}
214*0Sstevel@tonic-gate 	}
215*0Sstevel@tonic-gate 	if(found_ex) {
216*0Sstevel@tonic-gate 		/* Found it */
217*0Sstevel@tonic-gate 		if(crit) *crit = X509_EXTENSION_get_critical(found_ex);
218*0Sstevel@tonic-gate 		return X509V3_EXT_d2i(found_ex);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/* Extension not found */
222*0Sstevel@tonic-gate 	if(idx) *idx = -1;
223*0Sstevel@tonic-gate 	if(crit) *crit = -1;
224*0Sstevel@tonic-gate 	return NULL;
225*0Sstevel@tonic-gate }
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate /* This function is a general extension append, replace and delete utility.
228*0Sstevel@tonic-gate  * The precise operation is governed by the 'flags' value. The 'crit' and
229*0Sstevel@tonic-gate  * 'value' arguments (if relevant) are the extensions internal structure.
230*0Sstevel@tonic-gate  */
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
233*0Sstevel@tonic-gate 					int crit, unsigned long flags)
234*0Sstevel@tonic-gate {
235*0Sstevel@tonic-gate 	int extidx = -1;
236*0Sstevel@tonic-gate 	int errcode;
237*0Sstevel@tonic-gate 	X509_EXTENSION *ext, *extmp;
238*0Sstevel@tonic-gate 	unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	/* If appending we don't care if it exists, otherwise
241*0Sstevel@tonic-gate 	 * look for existing extension.
242*0Sstevel@tonic-gate 	 */
243*0Sstevel@tonic-gate 	if(ext_op != X509V3_ADD_APPEND)
244*0Sstevel@tonic-gate 		extidx = X509v3_get_ext_by_NID(*x, nid, -1);
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	/* See if extension exists */
247*0Sstevel@tonic-gate 	if(extidx >= 0) {
248*0Sstevel@tonic-gate 		/* If keep existing, nothing to do */
249*0Sstevel@tonic-gate 		if(ext_op == X509V3_ADD_KEEP_EXISTING)
250*0Sstevel@tonic-gate 			return 1;
251*0Sstevel@tonic-gate 		/* If default then its an error */
252*0Sstevel@tonic-gate 		if(ext_op == X509V3_ADD_DEFAULT) {
253*0Sstevel@tonic-gate 			errcode = X509V3_R_EXTENSION_EXISTS;
254*0Sstevel@tonic-gate 			goto err;
255*0Sstevel@tonic-gate 		}
256*0Sstevel@tonic-gate 		/* If delete, just delete it */
257*0Sstevel@tonic-gate 		if(ext_op == X509V3_ADD_DELETE) {
258*0Sstevel@tonic-gate 			if(!sk_X509_EXTENSION_delete(*x, extidx)) return -1;
259*0Sstevel@tonic-gate 			return 1;
260*0Sstevel@tonic-gate 		}
261*0Sstevel@tonic-gate 	} else {
262*0Sstevel@tonic-gate 		/* If replace existing or delete, error since
263*0Sstevel@tonic-gate 		 * extension must exist
264*0Sstevel@tonic-gate 		 */
265*0Sstevel@tonic-gate 		if((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
266*0Sstevel@tonic-gate 		   (ext_op == X509V3_ADD_DELETE)) {
267*0Sstevel@tonic-gate 			errcode = X509V3_R_EXTENSION_NOT_FOUND;
268*0Sstevel@tonic-gate 			goto err;
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	/* If we get this far then we have to create an extension:
273*0Sstevel@tonic-gate 	 * could have some flags for alternative encoding schemes...
274*0Sstevel@tonic-gate 	 */
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	ext = X509V3_EXT_i2d(nid, crit, value);
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	if(!ext) {
279*0Sstevel@tonic-gate 		X509V3err(X509V3_F_X509V3_ADD_I2D, X509V3_R_ERROR_CREATING_EXTENSION);
280*0Sstevel@tonic-gate 		return 0;
281*0Sstevel@tonic-gate 	}
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	/* If extension exists replace it.. */
284*0Sstevel@tonic-gate 	if(extidx >= 0) {
285*0Sstevel@tonic-gate 		extmp = sk_X509_EXTENSION_value(*x, extidx);
286*0Sstevel@tonic-gate 		X509_EXTENSION_free(extmp);
287*0Sstevel@tonic-gate 		if(!sk_X509_EXTENSION_set(*x, extidx, ext)) return -1;
288*0Sstevel@tonic-gate 		return 1;
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if(!*x && !(*x = sk_X509_EXTENSION_new_null())) return -1;
292*0Sstevel@tonic-gate 	if(!sk_X509_EXTENSION_push(*x, ext)) return -1;
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	return 1;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	err:
297*0Sstevel@tonic-gate 	if(!(flags & X509V3_ADD_SILENT))
298*0Sstevel@tonic-gate 		X509V3err(X509V3_F_X509V3_ADD_I2D, errcode);
299*0Sstevel@tonic-gate 	return 0;
300*0Sstevel@tonic-gate }
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate IMPLEMENT_STACK_OF(X509V3_EXT_METHOD)
303