v3_utl.c revision 100928
1/* v3_utl.c */ 2/* Written by Dr Stephen N Henson (shenson@bigfoot.com) 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@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 */ 58/* X509 v3 extension utilities */ 59 60 61#include <stdio.h> 62#include <ctype.h> 63#include "cryptlib.h" 64#include <openssl/conf.h> 65#include <openssl/x509v3.h> 66 67static char *strip_spaces(char *name); 68static int sk_strcmp(const char * const *a, const char * const *b); 69static STACK *get_email(X509_NAME *name, STACK_OF(GENERAL_NAME) *gens); 70static void str_free(void *str); 71static int append_ia5(STACK **sk, ASN1_IA5STRING *email); 72 73/* Add a CONF_VALUE name value pair to stack */ 74 75int X509V3_add_value(const char *name, const char *value, 76 STACK_OF(CONF_VALUE) **extlist) 77{ 78 CONF_VALUE *vtmp = NULL; 79 char *tname = NULL, *tvalue = NULL; 80 if(name && !(tname = BUF_strdup(name))) goto err; 81 if(value && !(tvalue = BUF_strdup(value))) goto err;; 82 if(!(vtmp = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) goto err; 83 if(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err; 84 vtmp->section = NULL; 85 vtmp->name = tname; 86 vtmp->value = tvalue; 87 if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err; 88 return 1; 89 err: 90 X509V3err(X509V3_F_X509V3_ADD_VALUE,ERR_R_MALLOC_FAILURE); 91 if(vtmp) OPENSSL_free(vtmp); 92 if(tname) OPENSSL_free(tname); 93 if(tvalue) OPENSSL_free(tvalue); 94 return 0; 95} 96 97int X509V3_add_value_uchar(const char *name, const unsigned char *value, 98 STACK_OF(CONF_VALUE) **extlist) 99 { 100 return X509V3_add_value(name,(const char *)value,extlist); 101 } 102 103/* Free function for STACK_OF(CONF_VALUE) */ 104 105void X509V3_conf_free(CONF_VALUE *conf) 106{ 107 if(!conf) return; 108 if(conf->name) OPENSSL_free(conf->name); 109 if(conf->value) OPENSSL_free(conf->value); 110 if(conf->section) OPENSSL_free(conf->section); 111 OPENSSL_free(conf); 112} 113 114int X509V3_add_value_bool(const char *name, int asn1_bool, 115 STACK_OF(CONF_VALUE) **extlist) 116{ 117 if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); 118 return X509V3_add_value(name, "FALSE", extlist); 119} 120 121int X509V3_add_value_bool_nf(char *name, int asn1_bool, 122 STACK_OF(CONF_VALUE) **extlist) 123{ 124 if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); 125 return 1; 126} 127 128 129char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) 130{ 131 BIGNUM *bntmp = NULL; 132 char *strtmp = NULL; 133 if(!a) return NULL; 134 if(!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) || 135 !(strtmp = BN_bn2dec(bntmp)) ) 136 X509V3err(X509V3_F_I2S_ASN1_ENUMERATED,ERR_R_MALLOC_FAILURE); 137 BN_free(bntmp); 138 return strtmp; 139} 140 141char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a) 142{ 143 BIGNUM *bntmp = NULL; 144 char *strtmp = NULL; 145 if(!a) return NULL; 146 if(!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) || 147 !(strtmp = BN_bn2dec(bntmp)) ) 148 X509V3err(X509V3_F_I2S_ASN1_INTEGER,ERR_R_MALLOC_FAILURE); 149 BN_free(bntmp); 150 return strtmp; 151} 152 153ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, char *value) 154{ 155 BIGNUM *bn = NULL; 156 ASN1_INTEGER *aint; 157 bn = BN_new(); 158 if(!value) { 159 X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_INVALID_NULL_VALUE); 160 return 0; 161 } 162 if(!BN_dec2bn(&bn, value)) { 163 X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_DEC2BN_ERROR); 164 return 0; 165 } 166 167 if(!(aint = BN_to_ASN1_INTEGER(bn, NULL))) { 168 X509V3err(X509V3_F_S2I_ASN1_INTEGER,X509V3_R_BN_TO_ASN1_INTEGER_ERROR); 169 return 0; 170 } 171 BN_free(bn); 172 return aint; 173} 174 175int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, 176 STACK_OF(CONF_VALUE) **extlist) 177{ 178 char *strtmp; 179 int ret; 180 if(!aint) return 1; 181 if(!(strtmp = i2s_ASN1_INTEGER(NULL, aint))) return 0; 182 ret = X509V3_add_value(name, strtmp, extlist); 183 OPENSSL_free(strtmp); 184 return ret; 185} 186 187int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool) 188{ 189 char *btmp; 190 if(!(btmp = value->value)) goto err; 191 if(!strcmp(btmp, "TRUE") || !strcmp(btmp, "true") 192 || !strcmp(btmp, "Y") || !strcmp(btmp, "y") 193 || !strcmp(btmp, "YES") || !strcmp(btmp, "yes")) { 194 *asn1_bool = 0xff; 195 return 1; 196 } else if(!strcmp(btmp, "FALSE") || !strcmp(btmp, "false") 197 || !strcmp(btmp, "N") || !strcmp(btmp, "n") 198 || !strcmp(btmp, "NO") || !strcmp(btmp, "no")) { 199 *asn1_bool = 0; 200 return 1; 201 } 202 err: 203 X509V3err(X509V3_F_X509V3_GET_VALUE_BOOL,X509V3_R_INVALID_BOOLEAN_STRING); 204 X509V3_conf_err(value); 205 return 0; 206} 207 208int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint) 209{ 210 ASN1_INTEGER *itmp; 211 if(!(itmp = s2i_ASN1_INTEGER(NULL, value->value))) { 212 X509V3_conf_err(value); 213 return 0; 214 } 215 *aint = itmp; 216 return 1; 217} 218 219#define HDR_NAME 1 220#define HDR_VALUE 2 221 222/*#define DEBUG*/ 223 224STACK_OF(CONF_VALUE) *X509V3_parse_list(char *line) 225{ 226 char *p, *q, c; 227 char *ntmp, *vtmp; 228 STACK_OF(CONF_VALUE) *values = NULL; 229 char *linebuf; 230 int state; 231 /* We are going to modify the line so copy it first */ 232 linebuf = BUF_strdup(line); 233 state = HDR_NAME; 234 ntmp = NULL; 235 /* Go through all characters */ 236 for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) { 237 238 switch(state) { 239 case HDR_NAME: 240 if(c == ':') { 241 state = HDR_VALUE; 242 *p = 0; 243 ntmp = strip_spaces(q); 244 if(!ntmp) { 245 X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); 246 goto err; 247 } 248 q = p + 1; 249 } else if(c == ',') { 250 *p = 0; 251 ntmp = strip_spaces(q); 252 q = p + 1; 253#if 0 254 printf("%s\n", ntmp); 255#endif 256 if(!ntmp) { 257 X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); 258 goto err; 259 } 260 X509V3_add_value(ntmp, NULL, &values); 261 } 262 break ; 263 264 case HDR_VALUE: 265 if(c == ',') { 266 state = HDR_NAME; 267 *p = 0; 268 vtmp = strip_spaces(q); 269#if 0 270 printf("%s\n", ntmp); 271#endif 272 if(!vtmp) { 273 X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE); 274 goto err; 275 } 276 X509V3_add_value(ntmp, vtmp, &values); 277 ntmp = NULL; 278 q = p + 1; 279 } 280 281 } 282 } 283 284 if(state == HDR_VALUE) { 285 vtmp = strip_spaces(q); 286#if 0 287 printf("%s=%s\n", ntmp, vtmp); 288#endif 289 if(!vtmp) { 290 X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_VALUE); 291 goto err; 292 } 293 X509V3_add_value(ntmp, vtmp, &values); 294 } else { 295 ntmp = strip_spaces(q); 296#if 0 297 printf("%s\n", ntmp); 298#endif 299 if(!ntmp) { 300 X509V3err(X509V3_F_X509V3_PARSE_LIST, X509V3_R_INVALID_NULL_NAME); 301 goto err; 302 } 303 X509V3_add_value(ntmp, NULL, &values); 304 } 305OPENSSL_free(linebuf); 306return values; 307 308err: 309OPENSSL_free(linebuf); 310sk_CONF_VALUE_pop_free(values, X509V3_conf_free); 311return NULL; 312 313} 314 315/* Delete leading and trailing spaces from a string */ 316static char *strip_spaces(char *name) 317{ 318 char *p, *q; 319 /* Skip over leading spaces */ 320 p = name; 321 while(*p && isspace((unsigned char)*p)) p++; 322 if(!*p) return NULL; 323 q = p + strlen(p) - 1; 324 while((q != p) && isspace((unsigned char)*q)) q--; 325 if(p != q) q[1] = 0; 326 if(!*p) return NULL; 327 return p; 328} 329 330/* hex string utilities */ 331 332/* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its 333 * hex representation 334 * @@@ (Contents of buffer are always kept in ASCII, also on EBCDIC machines) 335 */ 336 337char *hex_to_string(unsigned char *buffer, long len) 338{ 339 char *tmp, *q; 340 unsigned char *p; 341 int i; 342 static char hexdig[] = "0123456789ABCDEF"; 343 if(!buffer || !len) return NULL; 344 if(!(tmp = OPENSSL_malloc(len * 3 + 1))) { 345 X509V3err(X509V3_F_HEX_TO_STRING,ERR_R_MALLOC_FAILURE); 346 return NULL; 347 } 348 q = tmp; 349 for(i = 0, p = buffer; i < len; i++,p++) { 350 *q++ = hexdig[(*p >> 4) & 0xf]; 351 *q++ = hexdig[*p & 0xf]; 352 *q++ = ':'; 353 } 354 q[-1] = 0; 355#ifdef CHARSET_EBCDIC 356 ebcdic2ascii(tmp, tmp, q - tmp - 1); 357#endif 358 359 return tmp; 360} 361 362/* Give a string of hex digits convert to 363 * a buffer 364 */ 365 366unsigned char *string_to_hex(char *str, long *len) 367{ 368 unsigned char *hexbuf, *q; 369 unsigned char ch, cl, *p; 370 if(!str) { 371 X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_INVALID_NULL_ARGUMENT); 372 return NULL; 373 } 374 if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err; 375 for(p = (unsigned char *)str, q = hexbuf; *p;) { 376 ch = *p++; 377#ifdef CHARSET_EBCDIC 378 ch = os_toebcdic[ch]; 379#endif 380 if(ch == ':') continue; 381 cl = *p++; 382#ifdef CHARSET_EBCDIC 383 cl = os_toebcdic[cl]; 384#endif 385 if(!cl) { 386 X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ODD_NUMBER_OF_DIGITS); 387 OPENSSL_free(hexbuf); 388 return NULL; 389 } 390 if(isupper(ch)) ch = tolower(ch); 391 if(isupper(cl)) cl = tolower(cl); 392 393 if((ch >= '0') && (ch <= '9')) ch -= '0'; 394 else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10; 395 else goto badhex; 396 397 if((cl >= '0') && (cl <= '9')) cl -= '0'; 398 else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10; 399 else goto badhex; 400 401 *q++ = (ch << 4) | cl; 402 } 403 404 if(len) *len = q - hexbuf; 405 406 return hexbuf; 407 408 err: 409 if(hexbuf) OPENSSL_free(hexbuf); 410 X509V3err(X509V3_F_STRING_TO_HEX,ERR_R_MALLOC_FAILURE); 411 return NULL; 412 413 badhex: 414 OPENSSL_free(hexbuf); 415 X509V3err(X509V3_F_STRING_TO_HEX,X509V3_R_ILLEGAL_HEX_DIGIT); 416 return NULL; 417 418} 419 420/* V2I name comparison function: returns zero if 'name' matches 421 * cmp or cmp.* 422 */ 423 424int name_cmp(const char *name, const char *cmp) 425{ 426 int len, ret; 427 char c; 428 len = strlen(cmp); 429 if((ret = strncmp(name, cmp, len))) return ret; 430 c = name[len]; 431 if(!c || (c=='.')) return 0; 432 return 1; 433} 434 435static int sk_strcmp(const char * const *a, const char * const *b) 436{ 437 return strcmp(*a, *b); 438} 439 440STACK *X509_get1_email(X509 *x) 441{ 442 STACK_OF(GENERAL_NAME) *gens; 443 STACK *ret; 444 gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); 445 ret = get_email(X509_get_subject_name(x), gens); 446 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 447 return ret; 448} 449 450STACK *X509_REQ_get1_email(X509_REQ *x) 451{ 452 STACK_OF(GENERAL_NAME) *gens; 453 STACK_OF(X509_EXTENSION) *exts; 454 STACK *ret; 455 exts = X509_REQ_get_extensions(x); 456 gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL); 457 ret = get_email(X509_REQ_get_subject_name(x), gens); 458 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 459 sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); 460 return ret; 461} 462 463 464static STACK *get_email(X509_NAME *name, STACK_OF(GENERAL_NAME) *gens) 465{ 466 STACK *ret = NULL; 467 X509_NAME_ENTRY *ne; 468 ASN1_IA5STRING *email; 469 GENERAL_NAME *gen; 470 int i; 471 /* Now add any email address(es) to STACK */ 472 i = -1; 473 /* First supplied X509_NAME */ 474 while((i = X509_NAME_get_index_by_NID(name, 475 NID_pkcs9_emailAddress, i)) > 0) { 476 ne = X509_NAME_get_entry(name, i); 477 email = X509_NAME_ENTRY_get_data(ne); 478 if(!append_ia5(&ret, email)) return NULL; 479 } 480 for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) 481 { 482 gen = sk_GENERAL_NAME_value(gens, i); 483 if(gen->type != GEN_EMAIL) continue; 484 if(!append_ia5(&ret, gen->d.ia5)) return NULL; 485 } 486 return ret; 487} 488 489static void str_free(void *str) 490{ 491 OPENSSL_free(str); 492} 493 494static int append_ia5(STACK **sk, ASN1_IA5STRING *email) 495{ 496 char *emtmp; 497 /* First some sanity checks */ 498 if(email->type != V_ASN1_IA5STRING) return 1; 499 if(!email->data || !email->length) return 1; 500 if(!*sk) *sk = sk_new(sk_strcmp); 501 if(!*sk) return 0; 502 /* Don't add duplicates */ 503 if(sk_find(*sk, (char *)email->data) != -1) return 1; 504 emtmp = BUF_strdup((char *)email->data); 505 if(!emtmp || !sk_push(*sk, emtmp)) { 506 X509_email_free(*sk); 507 *sk = NULL; 508 return 0; 509 } 510 return 1; 511} 512 513void X509_email_free(STACK *sk) 514{ 515 sk_pop_free(sk, str_free); 516} 517