155714Skris/* v3_lib.c */ 2296465Sdelphij/* 3296465Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4296465Sdelphij * 1999. 555714Skris */ 655714Skris/* ==================================================================== 755714Skris * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 855714Skris * 955714Skris * Redistribution and use in source and binary forms, with or without 1055714Skris * modification, are permitted provided that the following conditions 1155714Skris * are met: 1255714Skris * 1355714Skris * 1. Redistributions of source code must retain the above copyright 14296465Sdelphij * notice, this list of conditions and the following disclaimer. 1555714Skris * 1655714Skris * 2. Redistributions in binary form must reproduce the above copyright 1755714Skris * notice, this list of conditions and the following disclaimer in 1855714Skris * the documentation and/or other materials provided with the 1955714Skris * distribution. 2055714Skris * 2155714Skris * 3. All advertising materials mentioning features or use of this 2255714Skris * software must display the following acknowledgment: 2355714Skris * "This product includes software developed by the OpenSSL Project 2455714Skris * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 2555714Skris * 2655714Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2755714Skris * endorse or promote products derived from this software without 2855714Skris * prior written permission. For written permission, please contact 2955714Skris * licensing@OpenSSL.org. 3055714Skris * 3155714Skris * 5. Products derived from this software may not be called "OpenSSL" 3255714Skris * nor may "OpenSSL" appear in their names without prior written 3355714Skris * permission of the OpenSSL Project. 3455714Skris * 3555714Skris * 6. Redistributions of any form whatsoever must retain the following 3655714Skris * acknowledgment: 3755714Skris * "This product includes software developed by the OpenSSL Project 3855714Skris * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 3955714Skris * 4055714Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 4155714Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4255714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4355714Skris * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 4455714Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4555714Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4655714Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4755714Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4955714Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5055714Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 5155714Skris * OF THE POSSIBILITY OF SUCH DAMAGE. 5255714Skris * ==================================================================== 5355714Skris * 5455714Skris * This product includes cryptographic software written by Eric Young 5555714Skris * (eay@cryptsoft.com). This product includes software written by Tim 5655714Skris * Hudson (tjh@cryptsoft.com). 5755714Skris * 5855714Skris */ 5955714Skris/* X509 v3 extension utilities */ 6055714Skris 6155714Skris#include <stdio.h> 6255714Skris#include "cryptlib.h" 6355714Skris#include <openssl/conf.h> 6455714Skris#include <openssl/x509v3.h> 6555714Skris 6659191Skris#include "ext_dat.h" 6759191Skris 6868651Skrisstatic STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL; 6955714Skris 70296465Sdelphijstatic int ext_cmp(const X509V3_EXT_METHOD *const *a, 71296465Sdelphij const X509V3_EXT_METHOD *const *b); 7255714Skrisstatic void ext_list_free(X509V3_EXT_METHOD *ext); 7355714Skris 7455714Skrisint X509V3_EXT_add(X509V3_EXT_METHOD *ext) 7555714Skris{ 76296465Sdelphij if (!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp))) { 77296465Sdelphij X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); 78296465Sdelphij return 0; 79296465Sdelphij } 80296465Sdelphij if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) { 81296465Sdelphij X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE); 82296465Sdelphij return 0; 83296465Sdelphij } 84296465Sdelphij return 1; 8555714Skris} 8655714Skris 87296465Sdelphijstatic int ext_cmp(const X509V3_EXT_METHOD *const *a, 88296465Sdelphij const X509V3_EXT_METHOD *const *b) 8955714Skris{ 90296465Sdelphij return ((*a)->ext_nid - (*b)->ext_nid); 9155714Skris} 9255714Skris 9355714SkrisX509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) 9455714Skris{ 95296465Sdelphij X509V3_EXT_METHOD tmp, *t = &tmp, **ret; 96296465Sdelphij int idx; 97296465Sdelphij if (nid < 0) 98296465Sdelphij return NULL; 99296465Sdelphij tmp.ext_nid = nid; 100296465Sdelphij ret = (X509V3_EXT_METHOD **)OBJ_bsearch((char *)&t, 101296465Sdelphij (char *)standard_exts, 102296465Sdelphij STANDARD_EXTENSION_COUNT, 103296465Sdelphij sizeof(X509V3_EXT_METHOD *), 104296465Sdelphij (int (*) 105296465Sdelphij (const void *, 106296465Sdelphij const void *))ext_cmp); 107296465Sdelphij if (ret) 108296465Sdelphij return *ret; 109296465Sdelphij if (!ext_list) 110296465Sdelphij return NULL; 111296465Sdelphij idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp); 112296465Sdelphij if (idx == -1) 113296465Sdelphij return NULL; 114296465Sdelphij return sk_X509V3_EXT_METHOD_value(ext_list, idx); 11555714Skris} 11655714Skris 11755714SkrisX509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext) 11855714Skris{ 119296465Sdelphij int nid; 120296465Sdelphij if ((nid = OBJ_obj2nid(ext->object)) == NID_undef) 121296465Sdelphij return NULL; 122296465Sdelphij return X509V3_EXT_get_nid(nid); 12355714Skris} 12455714Skris 12555714Skrisint X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist) 12655714Skris{ 127296465Sdelphij for (; extlist->ext_nid != -1; extlist++) 128296465Sdelphij if (!X509V3_EXT_add(extlist)) 129296465Sdelphij return 0; 130296465Sdelphij return 1; 13155714Skris} 13255714Skris 13355714Skrisint X509V3_EXT_add_alias(int nid_to, int nid_from) 13455714Skris{ 135296465Sdelphij X509V3_EXT_METHOD *ext, *tmpext; 136296465Sdelphij if (!(ext = X509V3_EXT_get_nid(nid_from))) { 137296465Sdelphij X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, 138296465Sdelphij X509V3_R_EXTENSION_NOT_FOUND); 139296465Sdelphij return 0; 140296465Sdelphij } 141296465Sdelphij if (! 142296465Sdelphij (tmpext = 143296465Sdelphij (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) { 144296465Sdelphij X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, ERR_R_MALLOC_FAILURE); 145296465Sdelphij return 0; 146296465Sdelphij } 147296465Sdelphij *tmpext = *ext; 148296465Sdelphij tmpext->ext_nid = nid_to; 149296465Sdelphij tmpext->ext_flags |= X509V3_EXT_DYNAMIC; 150296465Sdelphij return X509V3_EXT_add(tmpext); 15155714Skris} 15255714Skris 15355714Skrisvoid X509V3_EXT_cleanup(void) 15455714Skris{ 155296465Sdelphij sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free); 156296465Sdelphij ext_list = NULL; 15755714Skris} 15855714Skris 15955714Skrisstatic void ext_list_free(X509V3_EXT_METHOD *ext) 16055714Skris{ 161296465Sdelphij if (ext->ext_flags & X509V3_EXT_DYNAMIC) 162296465Sdelphij OPENSSL_free(ext); 16355714Skris} 16455714Skris 165296465Sdelphij/* 166296465Sdelphij * Legacy function: we don't need to add standard extensions any more because 167296465Sdelphij * they are now kept in ext_dat.h. 16859191Skris */ 16955714Skris 17055714Skrisint X509V3_add_standard_extensions(void) 17155714Skris{ 172296465Sdelphij return 1; 17355714Skris} 17455714Skris 17555714Skris/* Return an extension internal structure */ 17655714Skris 17755714Skrisvoid *X509V3_EXT_d2i(X509_EXTENSION *ext) 17855714Skris{ 179296465Sdelphij X509V3_EXT_METHOD *method; 180296465Sdelphij const unsigned char *p; 181160814Ssimon 182296465Sdelphij if (!(method = X509V3_EXT_get(ext))) 183296465Sdelphij return NULL; 184296465Sdelphij p = ext->value->data; 185296465Sdelphij if (method->it) 186296465Sdelphij return ASN1_item_d2i(NULL, &p, ext->value->length, 187296465Sdelphij ASN1_ITEM_ptr(method->it)); 188296465Sdelphij return method->d2i(NULL, &p, ext->value->length); 18955714Skris} 19055714Skris 191296465Sdelphij/*- 192296465Sdelphij * Get critical flag and decoded version of extension from a NID. 19359191Skris * The "idx" variable returns the last found extension and can 19459191Skris * be used to retrieve multiple extensions of the same NID. 19559191Skris * However multiple extensions with the same NID is usually 19659191Skris * due to a badly encoded certificate so if idx is NULL we 19759191Skris * choke if multiple extensions exist. 19859191Skris * The "crit" variable is set to the critical value. 19959191Skris * The return value is the decoded extension or NULL on 20059191Skris * error. The actual error can have several different causes, 20159191Skris * the value of *crit reflects the cause: 20259191Skris * >= 0, extension found but not decoded (reflects critical value). 20359191Skris * -1 extension not found. 20459191Skris * -2 extension occurs more than once. 20559191Skris */ 20659191Skris 207296465Sdelphijvoid *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, 208296465Sdelphij int *idx) 20959191Skris{ 210296465Sdelphij int lastpos, i; 211296465Sdelphij X509_EXTENSION *ex, *found_ex = NULL; 212296465Sdelphij if (!x) { 213296465Sdelphij if (idx) 214296465Sdelphij *idx = -1; 215296465Sdelphij if (crit) 216296465Sdelphij *crit = -1; 217296465Sdelphij return NULL; 218296465Sdelphij } 219296465Sdelphij if (idx) 220296465Sdelphij lastpos = *idx + 1; 221296465Sdelphij else 222296465Sdelphij lastpos = 0; 223296465Sdelphij if (lastpos < 0) 224296465Sdelphij lastpos = 0; 225296465Sdelphij for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) { 226296465Sdelphij ex = sk_X509_EXTENSION_value(x, i); 227296465Sdelphij if (OBJ_obj2nid(ex->object) == nid) { 228296465Sdelphij if (idx) { 229296465Sdelphij *idx = i; 230296465Sdelphij found_ex = ex; 231296465Sdelphij break; 232296465Sdelphij } else if (found_ex) { 233296465Sdelphij /* Found more than one */ 234296465Sdelphij if (crit) 235296465Sdelphij *crit = -2; 236296465Sdelphij return NULL; 237296465Sdelphij } 238296465Sdelphij found_ex = ex; 239296465Sdelphij } 240296465Sdelphij } 241296465Sdelphij if (found_ex) { 242296465Sdelphij /* Found it */ 243296465Sdelphij if (crit) 244296465Sdelphij *crit = X509_EXTENSION_get_critical(found_ex); 245296465Sdelphij return X509V3_EXT_d2i(found_ex); 246296465Sdelphij } 24768651Skris 248296465Sdelphij /* Extension not found */ 249296465Sdelphij if (idx) 250296465Sdelphij *idx = -1; 251296465Sdelphij if (crit) 252296465Sdelphij *crit = -1; 253296465Sdelphij return NULL; 25459191Skris} 25568651Skris 256296465Sdelphij/* 257296465Sdelphij * This function is a general extension append, replace and delete utility. 258109998Smarkm * The precise operation is governed by the 'flags' value. The 'crit' and 259109998Smarkm * 'value' arguments (if relevant) are the extensions internal structure. 260109998Smarkm */ 261109998Smarkm 262109998Smarkmint X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, 263296465Sdelphij int crit, unsigned long flags) 264109998Smarkm{ 265296465Sdelphij int extidx = -1; 266296465Sdelphij int errcode; 267296465Sdelphij X509_EXTENSION *ext, *extmp; 268296465Sdelphij unsigned long ext_op = flags & X509V3_ADD_OP_MASK; 269109998Smarkm 270296465Sdelphij /* 271296465Sdelphij * If appending we don't care if it exists, otherwise look for existing 272296465Sdelphij * extension. 273296465Sdelphij */ 274296465Sdelphij if (ext_op != X509V3_ADD_APPEND) 275296465Sdelphij extidx = X509v3_get_ext_by_NID(*x, nid, -1); 276109998Smarkm 277296465Sdelphij /* See if extension exists */ 278296465Sdelphij if (extidx >= 0) { 279296465Sdelphij /* If keep existing, nothing to do */ 280296465Sdelphij if (ext_op == X509V3_ADD_KEEP_EXISTING) 281296465Sdelphij return 1; 282296465Sdelphij /* If default then its an error */ 283296465Sdelphij if (ext_op == X509V3_ADD_DEFAULT) { 284296465Sdelphij errcode = X509V3_R_EXTENSION_EXISTS; 285296465Sdelphij goto err; 286296465Sdelphij } 287296465Sdelphij /* If delete, just delete it */ 288296465Sdelphij if (ext_op == X509V3_ADD_DELETE) { 289296465Sdelphij if (!sk_X509_EXTENSION_delete(*x, extidx)) 290296465Sdelphij return -1; 291296465Sdelphij return 1; 292296465Sdelphij } 293296465Sdelphij } else { 294296465Sdelphij /* 295296465Sdelphij * If replace existing or delete, error since extension must exist 296296465Sdelphij */ 297296465Sdelphij if ((ext_op == X509V3_ADD_REPLACE_EXISTING) || 298296465Sdelphij (ext_op == X509V3_ADD_DELETE)) { 299296465Sdelphij errcode = X509V3_R_EXTENSION_NOT_FOUND; 300296465Sdelphij goto err; 301296465Sdelphij } 302296465Sdelphij } 303109998Smarkm 304296465Sdelphij /* 305296465Sdelphij * If we get this far then we have to create an extension: could have 306296465Sdelphij * some flags for alternative encoding schemes... 307296465Sdelphij */ 308109998Smarkm 309296465Sdelphij ext = X509V3_EXT_i2d(nid, crit, value); 310109998Smarkm 311296465Sdelphij if (!ext) { 312296465Sdelphij X509V3err(X509V3_F_X509V3_ADD1_I2D, 313296465Sdelphij X509V3_R_ERROR_CREATING_EXTENSION); 314296465Sdelphij return 0; 315296465Sdelphij } 316109998Smarkm 317296465Sdelphij /* If extension exists replace it.. */ 318296465Sdelphij if (extidx >= 0) { 319296465Sdelphij extmp = sk_X509_EXTENSION_value(*x, extidx); 320296465Sdelphij X509_EXTENSION_free(extmp); 321296465Sdelphij if (!sk_X509_EXTENSION_set(*x, extidx, ext)) 322296465Sdelphij return -1; 323296465Sdelphij return 1; 324296465Sdelphij } 325109998Smarkm 326296465Sdelphij if (!*x && !(*x = sk_X509_EXTENSION_new_null())) 327296465Sdelphij return -1; 328296465Sdelphij if (!sk_X509_EXTENSION_push(*x, ext)) 329296465Sdelphij return -1; 330109998Smarkm 331296465Sdelphij return 1; 332109998Smarkm 333296465Sdelphij err: 334296465Sdelphij if (!(flags & X509V3_ADD_SILENT)) 335296465Sdelphij X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode); 336296465Sdelphij return 0; 337109998Smarkm} 338109998Smarkm 33968651SkrisIMPLEMENT_STACK_OF(X509V3_EXT_METHOD) 340