Home | History | Annotate | Download | only in x509v3
      1 /* v3_lib.c */
      2 /* Written by Dr Stephen N Henson (steve (at) openssl.org) for the OpenSSL
      3  * project 1999.
      4  */
      5 /* ====================================================================
      6  * Copyright (c) 1999 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 (at) 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 (at) cryptsoft.com).  This product includes software written by Tim
     55  * Hudson (tjh (at) cryptsoft.com).
     56  *
     57  */
     58 /* X509 v3 extension utilities */
     59 
     60 #include <stdio.h>
     61 
     62 #include <openssl/conf.h>
     63 #include <openssl/err.h>
     64 #include <openssl/mem.h>
     65 #include <openssl/obj.h>
     66 #include <openssl/x509v3.h>
     67 
     68 #include "ext_dat.h"
     69 static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
     70 
     71 static void ext_list_free(X509V3_EXT_METHOD *ext);
     72 
     73 static int ext_stack_cmp(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b)
     74 {
     75 	return ((*a)->ext_nid - (*b)->ext_nid);
     76 }
     77 
     78 int X509V3_EXT_add(X509V3_EXT_METHOD *ext)
     79 {
     80 	if(!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_stack_cmp))) {
     81 		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add, ERR_R_MALLOC_FAILURE);
     82 		ext_list_free(ext);
     83 		return 0;
     84 	}
     85 	if(!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
     86 		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add, ERR_R_MALLOC_FAILURE);
     87 		ext_list_free(ext);
     88 		return 0;
     89 	}
     90 	return 1;
     91 }
     92 
     93 static int ext_cmp(const void *void_a,
     94 		   const void *void_b)
     95 {
     96 	const X509V3_EXT_METHOD **a = (const X509V3_EXT_METHOD**) void_a;
     97 	const X509V3_EXT_METHOD **b = (const X509V3_EXT_METHOD**) void_b;
     98 	return ext_stack_cmp(a, b);
     99 }
    100 
    101 const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid)
    102 {
    103 	X509V3_EXT_METHOD tmp;
    104 	const X509V3_EXT_METHOD *t = &tmp, * const *ret;
    105 	size_t idx;
    106 
    107 	if(nid < 0) return NULL;
    108 	tmp.ext_nid = nid;
    109 	ret = bsearch(&t, standard_exts, STANDARD_EXTENSION_COUNT, sizeof(X509V3_EXT_METHOD*), ext_cmp);
    110 	if(ret) return *ret;
    111 	if(!ext_list) return NULL;
    112 
    113 	if (!sk_X509V3_EXT_METHOD_find(ext_list, &idx, &tmp))
    114 		return NULL;
    115 	return sk_X509V3_EXT_METHOD_value(ext_list, idx);
    116 }
    117 
    118 const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext)
    119 {
    120 	int nid;
    121 	if((nid = OBJ_obj2nid(ext->object)) == NID_undef) return NULL;
    122 	return X509V3_EXT_get_nid(nid);
    123 }
    124 
    125 int X509V3_EXT_free(int nid, void *ext_data)
    126 {
    127 	    const X509V3_EXT_METHOD *ext_method = X509V3_EXT_get_nid(nid);
    128 	    if (ext_method == NULL)
    129 	    {
    130 		    OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_free, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
    131 		    return 0;
    132 	    }
    133 
    134 	    if (ext_method->it != NULL)
    135 		    ASN1_item_free(ext_data, ASN1_ITEM_ptr(ext_method->it));
    136 	    else if (ext_method->ext_free != NULL)
    137 		    ext_method->ext_free(ext_data);
    138 	    else
    139 	    {
    140 		    OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_free, X509V3_R_CANNOT_FIND_FREE_FUNCTION);
    141 		    return 0;
    142 	    }
    143 
    144 	    return 1;
    145 }
    146 
    147 int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist)
    148 {
    149 	for(;extlist->ext_nid!=-1;extlist++)
    150 			if(!X509V3_EXT_add(extlist)) return 0;
    151 	return 1;
    152 }
    153 
    154 int X509V3_EXT_add_alias(int nid_to, int nid_from)
    155 {
    156 	const X509V3_EXT_METHOD *ext;
    157 	X509V3_EXT_METHOD *tmpext;
    158 
    159 	if(!(ext = X509V3_EXT_get_nid(nid_from))) {
    160 		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add_alias, X509V3_R_EXTENSION_NOT_FOUND);
    161 		return 0;
    162 	}
    163 	if(!(tmpext = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) {
    164 		OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add_alias, ERR_R_MALLOC_FAILURE);
    165 		return 0;
    166 	}
    167 	*tmpext = *ext;
    168 	tmpext->ext_nid = nid_to;
    169 	tmpext->ext_flags |= X509V3_EXT_DYNAMIC;
    170 	return X509V3_EXT_add(tmpext);
    171 }
    172 
    173 void X509V3_EXT_cleanup(void)
    174 {
    175 	sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free);
    176 	ext_list = NULL;
    177 }
    178 
    179 static void ext_list_free(X509V3_EXT_METHOD *ext)
    180 {
    181 	if(ext->ext_flags & X509V3_EXT_DYNAMIC) OPENSSL_free(ext);
    182 }
    183 
    184 /* Legacy function: we don't need to add standard extensions
    185  * any more because they are now kept in ext_dat.h.
    186  */
    187 
    188 int X509V3_add_standard_extensions(void)
    189 {
    190 	return 1;
    191 }
    192 
    193 /* Return an extension internal structure */
    194 
    195 void *X509V3_EXT_d2i(X509_EXTENSION *ext)
    196 {
    197 	const X509V3_EXT_METHOD *method;
    198 	const unsigned char *p;
    199 
    200 	if(!(method = X509V3_EXT_get(ext))) return NULL;
    201 	p = ext->value->data;
    202 	if(method->it) return ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it));
    203 	return method->d2i(NULL, &p, ext->value->length);
    204 }
    205 
    206 /* Get critical flag and decoded version of extension from a NID.
    207  * The "idx" variable returns the last found extension and can
    208  * be used to retrieve multiple extensions of the same NID.
    209  * However multiple extensions with the same NID is usually
    210  * due to a badly encoded certificate so if idx is NULL we
    211  * choke if multiple extensions exist.
    212  * The "crit" variable is set to the critical value.
    213  * The return value is the decoded extension or NULL on
    214  * error. The actual error can have several different causes,
    215  * the value of *crit reflects the cause:
    216  * >= 0, extension found but not decoded (reflects critical value).
    217  * -1 extension not found.
    218  * -2 extension occurs more than once.
    219  */
    220 
    221 void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx)
    222 {
    223 	int lastpos;
    224 	size_t i;
    225 	X509_EXTENSION *ex, *found_ex = NULL;
    226 	if(!x) {
    227 		if(idx) *idx = -1;
    228 		if(crit) *crit = -1;
    229 		return NULL;
    230 	}
    231 	if(idx) lastpos = *idx + 1;
    232 	else lastpos = 0;
    233 	if(lastpos < 0) lastpos = 0;
    234 	for(i = lastpos; i < sk_X509_EXTENSION_num(x); i++)
    235 	{
    236 		ex = sk_X509_EXTENSION_value(x, i);
    237 		if(OBJ_obj2nid(ex->object) == nid) {
    238 			if(idx) {
    239 				*idx = i;
    240 				found_ex = ex;
    241 				break;
    242 			} else if(found_ex) {
    243 				/* Found more than one */
    244 				if(crit) *crit = -2;
    245 				return NULL;
    246 			}
    247 			found_ex = ex;
    248 		}
    249 	}
    250 	if(found_ex) {
    251 		/* Found it */
    252 		if(crit) *crit = X509_EXTENSION_get_critical(found_ex);
    253 		return X509V3_EXT_d2i(found_ex);
    254 	}
    255 
    256 	/* Extension not found */
    257 	if(idx) *idx = -1;
    258 	if(crit) *crit = -1;
    259 	return NULL;
    260 }
    261 
    262 /* This function is a general extension append, replace and delete utility.
    263  * The precise operation is governed by the 'flags' value. The 'crit' and
    264  * 'value' arguments (if relevant) are the extensions internal structure.
    265  */
    266 
    267 int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
    268 					int crit, unsigned long flags)
    269 {
    270 	int extidx = -1;
    271 	int errcode;
    272 	X509_EXTENSION *ext, *extmp;
    273 	unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
    274 
    275 	/* If appending we don't care if it exists, otherwise
    276 	 * look for existing extension.
    277 	 */
    278 	if(ext_op != X509V3_ADD_APPEND)
    279 		extidx = X509v3_get_ext_by_NID(*x, nid, -1);
    280 
    281 	/* See if extension exists */
    282 	if(extidx >= 0) {
    283 		/* If keep existing, nothing to do */
    284 		if(ext_op == X509V3_ADD_KEEP_EXISTING)
    285 			return 1;
    286 		/* If default then its an error */
    287 		if(ext_op == X509V3_ADD_DEFAULT) {
    288 			errcode = X509V3_R_EXTENSION_EXISTS;
    289 			goto err;
    290 		}
    291 		/* If delete, just delete it */
    292 		if(ext_op == X509V3_ADD_DELETE) {
    293 			if(!sk_X509_EXTENSION_delete(*x, extidx)) return -1;
    294 			return 1;
    295 		}
    296 	} else {
    297 		/* If replace existing or delete, error since
    298 		 * extension must exist
    299 		 */
    300 		if((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
    301 		   (ext_op == X509V3_ADD_DELETE)) {
    302 			errcode = X509V3_R_EXTENSION_NOT_FOUND;
    303 			goto err;
    304 		}
    305 	}
    306 
    307 	/* If we get this far then we have to create an extension:
    308 	 * could have some flags for alternative encoding schemes...
    309 	 */
    310 
    311 	ext = X509V3_EXT_i2d(nid, crit, value);
    312 
    313 	if(!ext) {
    314 		OPENSSL_PUT_ERROR(X509V3, X509V3_add1_i2d, X509V3_R_ERROR_CREATING_EXTENSION);
    315 		return 0;
    316 	}
    317 
    318 	/* If extension exists replace it.. */
    319 	if(extidx >= 0) {
    320 		extmp = sk_X509_EXTENSION_value(*x, extidx);
    321 		X509_EXTENSION_free(extmp);
    322 		if(!sk_X509_EXTENSION_set(*x, extidx, ext)) return -1;
    323 		return 1;
    324 	}
    325 
    326 	if(!*x && !(*x = sk_X509_EXTENSION_new_null())) return -1;
    327 	if(!sk_X509_EXTENSION_push(*x, ext)) return -1;
    328 
    329 	return 1;
    330 
    331 	err:
    332 	if(!(flags & X509V3_ADD_SILENT))
    333 		OPENSSL_PUT_ERROR(X509V3, X509V3_add1_i2d, errcode);
    334 	return 0;
    335 }
    336