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