v3_alt.c revision 306195
1/* v3_alt.c */ 2/* 3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 4 * project. 5 */ 6/* ==================================================================== 7 * Copyright (c) 1999-2003 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 60#include <stdio.h> 61#include "cryptlib.h" 62#include <openssl/conf.h> 63#include <openssl/x509v3.h> 64 65static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, 66 X509V3_CTX *ctx, 67 STACK_OF(CONF_VALUE) *nval); 68static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, 69 X509V3_CTX *ctx, 70 STACK_OF(CONF_VALUE) *nval); 71static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p); 72static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens); 73static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx); 74static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx); 75 76const X509V3_EXT_METHOD v3_alt[] = { 77 {NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), 78 0, 0, 0, 0, 79 0, 0, 80 (X509V3_EXT_I2V) i2v_GENERAL_NAMES, 81 (X509V3_EXT_V2I)v2i_subject_alt, 82 NULL, NULL, NULL}, 83 84 {NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), 85 0, 0, 0, 0, 86 0, 0, 87 (X509V3_EXT_I2V) i2v_GENERAL_NAMES, 88 (X509V3_EXT_V2I)v2i_issuer_alt, 89 NULL, NULL, NULL}, 90 91 {NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES), 92 0, 0, 0, 0, 93 0, 0, 94 (X509V3_EXT_I2V) i2v_GENERAL_NAMES, 95 NULL, NULL, NULL, NULL}, 96}; 97 98STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, 99 GENERAL_NAMES *gens, 100 STACK_OF(CONF_VALUE) *ret) 101{ 102 int i; 103 GENERAL_NAME *gen; 104 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { 105 gen = sk_GENERAL_NAME_value(gens, i); 106 ret = i2v_GENERAL_NAME(method, gen, ret); 107 } 108 if (!ret) 109 return sk_CONF_VALUE_new_null(); 110 return ret; 111} 112 113STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, 114 GENERAL_NAME *gen, 115 STACK_OF(CONF_VALUE) *ret) 116{ 117 unsigned char *p; 118 char oline[256], htmp[5]; 119 int i; 120 switch (gen->type) { 121 case GEN_OTHERNAME: 122 X509V3_add_value("othername", "<unsupported>", &ret); 123 break; 124 125 case GEN_X400: 126 X509V3_add_value("X400Name", "<unsupported>", &ret); 127 break; 128 129 case GEN_EDIPARTY: 130 X509V3_add_value("EdiPartyName", "<unsupported>", &ret); 131 break; 132 133 case GEN_EMAIL: 134 X509V3_add_value_uchar("email", gen->d.ia5->data, &ret); 135 break; 136 137 case GEN_DNS: 138 X509V3_add_value_uchar("DNS", gen->d.ia5->data, &ret); 139 break; 140 141 case GEN_URI: 142 X509V3_add_value_uchar("URI", gen->d.ia5->data, &ret); 143 break; 144 145 case GEN_DIRNAME: 146 X509_NAME_oneline(gen->d.dirn, oline, 256); 147 X509V3_add_value("DirName", oline, &ret); 148 break; 149 150 case GEN_IPADD: 151 p = gen->d.ip->data; 152 if (gen->d.ip->length == 4) 153 BIO_snprintf(oline, sizeof oline, 154 "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 155 else if (gen->d.ip->length == 16) { 156 oline[0] = 0; 157 for (i = 0; i < 8; i++) { 158 BIO_snprintf(htmp, sizeof htmp, "%X", p[0] << 8 | p[1]); 159 p += 2; 160 strcat(oline, htmp); 161 if (i != 7) 162 strcat(oline, ":"); 163 } 164 } else { 165 X509V3_add_value("IP Address", "<invalid>", &ret); 166 break; 167 } 168 X509V3_add_value("IP Address", oline, &ret); 169 break; 170 171 case GEN_RID: 172 i2t_ASN1_OBJECT(oline, 256, gen->d.rid); 173 X509V3_add_value("Registered ID", oline, &ret); 174 break; 175 } 176 return ret; 177} 178 179int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) 180{ 181 unsigned char *p; 182 int i; 183 switch (gen->type) { 184 case GEN_OTHERNAME: 185 BIO_printf(out, "othername:<unsupported>"); 186 break; 187 188 case GEN_X400: 189 BIO_printf(out, "X400Name:<unsupported>"); 190 break; 191 192 case GEN_EDIPARTY: 193 /* Maybe fix this: it is supported now */ 194 BIO_printf(out, "EdiPartyName:<unsupported>"); 195 break; 196 197 case GEN_EMAIL: 198 BIO_printf(out, "email:%s", gen->d.ia5->data); 199 break; 200 201 case GEN_DNS: 202 BIO_printf(out, "DNS:%s", gen->d.ia5->data); 203 break; 204 205 case GEN_URI: 206 BIO_printf(out, "URI:%s", gen->d.ia5->data); 207 break; 208 209 case GEN_DIRNAME: 210 BIO_printf(out, "DirName: "); 211 X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); 212 break; 213 214 case GEN_IPADD: 215 p = gen->d.ip->data; 216 if (gen->d.ip->length == 4) 217 BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 218 else if (gen->d.ip->length == 16) { 219 BIO_printf(out, "IP Address"); 220 for (i = 0; i < 8; i++) { 221 BIO_printf(out, ":%X", p[0] << 8 | p[1]); 222 p += 2; 223 } 224 BIO_puts(out, "\n"); 225 } else { 226 BIO_printf(out, "IP Address:<invalid>"); 227 break; 228 } 229 break; 230 231 case GEN_RID: 232 BIO_printf(out, "Registered ID"); 233 i2a_ASN1_OBJECT(out, gen->d.rid); 234 break; 235 } 236 return 1; 237} 238 239static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, 240 X509V3_CTX *ctx, 241 STACK_OF(CONF_VALUE) *nval) 242{ 243 GENERAL_NAMES *gens = NULL; 244 CONF_VALUE *cnf; 245 int i; 246 if (!(gens = sk_GENERAL_NAME_new_null())) { 247 X509V3err(X509V3_F_V2I_ISSUER_ALT, ERR_R_MALLOC_FAILURE); 248 return NULL; 249 } 250 for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { 251 cnf = sk_CONF_VALUE_value(nval, i); 252 if (!name_cmp(cnf->name, "issuer") && cnf->value && 253 !strcmp(cnf->value, "copy")) { 254 if (!copy_issuer(ctx, gens)) 255 goto err; 256 } else { 257 GENERAL_NAME *gen; 258 if (!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) 259 goto err; 260 sk_GENERAL_NAME_push(gens, gen); 261 } 262 } 263 return gens; 264 err: 265 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 266 return NULL; 267} 268 269/* Append subject altname of issuer to issuer alt name of subject */ 270 271static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens) 272{ 273 GENERAL_NAMES *ialt; 274 GENERAL_NAME *gen; 275 X509_EXTENSION *ext; 276 int i; 277 if (ctx && (ctx->flags == CTX_TEST)) 278 return 1; 279 if (!ctx || !ctx->issuer_cert) { 280 X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_NO_ISSUER_DETAILS); 281 goto err; 282 } 283 i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1); 284 if (i < 0) 285 return 1; 286 if (!(ext = X509_get_ext(ctx->issuer_cert, i)) || 287 !(ialt = X509V3_EXT_d2i(ext))) { 288 X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_ISSUER_DECODE_ERROR); 289 goto err; 290 } 291 292 for (i = 0; i < sk_GENERAL_NAME_num(ialt); i++) { 293 gen = sk_GENERAL_NAME_value(ialt, i); 294 if (!sk_GENERAL_NAME_push(gens, gen)) { 295 X509V3err(X509V3_F_COPY_ISSUER, ERR_R_MALLOC_FAILURE); 296 goto err; 297 } 298 } 299 sk_GENERAL_NAME_free(ialt); 300 301 return 1; 302 303 err: 304 return 0; 305 306} 307 308static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, 309 X509V3_CTX *ctx, 310 STACK_OF(CONF_VALUE) *nval) 311{ 312 GENERAL_NAMES *gens = NULL; 313 CONF_VALUE *cnf; 314 int i; 315 if (!(gens = sk_GENERAL_NAME_new_null())) { 316 X509V3err(X509V3_F_V2I_SUBJECT_ALT, ERR_R_MALLOC_FAILURE); 317 return NULL; 318 } 319 for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { 320 cnf = sk_CONF_VALUE_value(nval, i); 321 if (!name_cmp(cnf->name, "email") && cnf->value && 322 !strcmp(cnf->value, "copy")) { 323 if (!copy_email(ctx, gens, 0)) 324 goto err; 325 } else if (!name_cmp(cnf->name, "email") && cnf->value && 326 !strcmp(cnf->value, "move")) { 327 if (!copy_email(ctx, gens, 1)) 328 goto err; 329 } else { 330 GENERAL_NAME *gen; 331 if (!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) 332 goto err; 333 sk_GENERAL_NAME_push(gens, gen); 334 } 335 } 336 return gens; 337 err: 338 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 339 return NULL; 340} 341 342/* 343 * Copy any email addresses in a certificate or request to GENERAL_NAMES 344 */ 345 346static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p) 347{ 348 X509_NAME *nm; 349 ASN1_IA5STRING *email = NULL; 350 X509_NAME_ENTRY *ne; 351 GENERAL_NAME *gen = NULL; 352 int i; 353 if (ctx != NULL && ctx->flags == CTX_TEST) 354 return 1; 355 if (!ctx || (!ctx->subject_cert && !ctx->subject_req)) { 356 X509V3err(X509V3_F_COPY_EMAIL, X509V3_R_NO_SUBJECT_DETAILS); 357 goto err; 358 } 359 /* Find the subject name */ 360 if (ctx->subject_cert) 361 nm = X509_get_subject_name(ctx->subject_cert); 362 else 363 nm = X509_REQ_get_subject_name(ctx->subject_req); 364 365 /* Now add any email address(es) to STACK */ 366 i = -1; 367 while ((i = X509_NAME_get_index_by_NID(nm, 368 NID_pkcs9_emailAddress, i)) >= 0) { 369 ne = X509_NAME_get_entry(nm, i); 370 email = M_ASN1_IA5STRING_dup(X509_NAME_ENTRY_get_data(ne)); 371 if (move_p) { 372 X509_NAME_delete_entry(nm, i); 373 X509_NAME_ENTRY_free(ne); 374 i--; 375 } 376 if (!email || !(gen = GENERAL_NAME_new())) { 377 X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE); 378 goto err; 379 } 380 gen->d.ia5 = email; 381 email = NULL; 382 gen->type = GEN_EMAIL; 383 if (!sk_GENERAL_NAME_push(gens, gen)) { 384 X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE); 385 goto err; 386 } 387 gen = NULL; 388 } 389 390 return 1; 391 392 err: 393 GENERAL_NAME_free(gen); 394 M_ASN1_IA5STRING_free(email); 395 return 0; 396 397} 398 399GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, 400 X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) 401{ 402 GENERAL_NAME *gen; 403 GENERAL_NAMES *gens = NULL; 404 CONF_VALUE *cnf; 405 int i; 406 if (!(gens = sk_GENERAL_NAME_new_null())) { 407 X509V3err(X509V3_F_V2I_GENERAL_NAMES, ERR_R_MALLOC_FAILURE); 408 return NULL; 409 } 410 for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { 411 cnf = sk_CONF_VALUE_value(nval, i); 412 if (!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) 413 goto err; 414 sk_GENERAL_NAME_push(gens, gen); 415 } 416 return gens; 417 err: 418 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 419 return NULL; 420} 421 422GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, 423 X509V3_CTX *ctx, CONF_VALUE *cnf) 424{ 425 return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0); 426} 427 428GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, 429 const X509V3_EXT_METHOD *method, 430 X509V3_CTX *ctx, int gen_type, char *value, 431 int is_nc) 432{ 433 char is_string = 0; 434 GENERAL_NAME *gen = NULL; 435 436 if (!value) { 437 X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_MISSING_VALUE); 438 return NULL; 439 } 440 441 if (out) 442 gen = out; 443 else { 444 gen = GENERAL_NAME_new(); 445 if (gen == NULL) { 446 X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE); 447 return NULL; 448 } 449 } 450 451 switch (gen_type) { 452 case GEN_URI: 453 case GEN_EMAIL: 454 case GEN_DNS: 455 is_string = 1; 456 break; 457 458 case GEN_RID: 459 { 460 ASN1_OBJECT *obj; 461 if (!(obj = OBJ_txt2obj(value, 0))) { 462 X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_OBJECT); 463 ERR_add_error_data(2, "value=", value); 464 goto err; 465 } 466 gen->d.rid = obj; 467 } 468 break; 469 470 case GEN_IPADD: 471 if (is_nc) 472 gen->d.ip = a2i_IPADDRESS_NC(value); 473 else 474 gen->d.ip = a2i_IPADDRESS(value); 475 if (gen->d.ip == NULL) { 476 X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_IP_ADDRESS); 477 ERR_add_error_data(2, "value=", value); 478 goto err; 479 } 480 break; 481 482 case GEN_DIRNAME: 483 if (!do_dirname(gen, value, ctx)) { 484 X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_DIRNAME_ERROR); 485 goto err; 486 } 487 break; 488 489 case GEN_OTHERNAME: 490 if (!do_othername(gen, value, ctx)) { 491 X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_OTHERNAME_ERROR); 492 goto err; 493 } 494 break; 495 default: 496 X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_UNSUPPORTED_TYPE); 497 goto err; 498 } 499 500 if (is_string) { 501 if (!(gen->d.ia5 = M_ASN1_IA5STRING_new()) || 502 !ASN1_STRING_set(gen->d.ia5, (unsigned char *)value, 503 strlen(value))) { 504 X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE); 505 goto err; 506 } 507 } 508 509 gen->type = gen_type; 510 511 return gen; 512 513 err: 514 if (!out) 515 GENERAL_NAME_free(gen); 516 return NULL; 517} 518 519GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, 520 const X509V3_EXT_METHOD *method, 521 X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc) 522{ 523 int type; 524 525 char *name, *value; 526 527 name = cnf->name; 528 value = cnf->value; 529 530 if (!value) { 531 X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_MISSING_VALUE); 532 return NULL; 533 } 534 535 if (!name_cmp(name, "email")) 536 type = GEN_EMAIL; 537 else if (!name_cmp(name, "URI")) 538 type = GEN_URI; 539 else if (!name_cmp(name, "DNS")) 540 type = GEN_DNS; 541 else if (!name_cmp(name, "RID")) 542 type = GEN_RID; 543 else if (!name_cmp(name, "IP")) 544 type = GEN_IPADD; 545 else if (!name_cmp(name, "dirName")) 546 type = GEN_DIRNAME; 547 else if (!name_cmp(name, "otherName")) 548 type = GEN_OTHERNAME; 549 else { 550 X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_UNSUPPORTED_OPTION); 551 ERR_add_error_data(2, "name=", name); 552 return NULL; 553 } 554 555 return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc); 556 557} 558 559static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) 560{ 561 char *objtmp = NULL, *p; 562 int objlen; 563 if (!(p = strchr(value, ';'))) 564 return 0; 565 if (!(gen->d.otherName = OTHERNAME_new())) 566 return 0; 567 /* 568 * Free this up because we will overwrite it. no need to free type_id 569 * because it is static 570 */ 571 ASN1_TYPE_free(gen->d.otherName->value); 572 if (!(gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx))) 573 return 0; 574 objlen = p - value; 575 objtmp = OPENSSL_malloc(objlen + 1); 576 if (objtmp == NULL) 577 return 0; 578 strncpy(objtmp, value, objlen); 579 objtmp[objlen] = 0; 580 gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0); 581 OPENSSL_free(objtmp); 582 if (!gen->d.otherName->type_id) 583 return 0; 584 return 1; 585} 586 587static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) 588{ 589 int ret = 0; 590 STACK_OF(CONF_VALUE) *sk = NULL; 591 X509_NAME *nm = NULL; 592 if (!(nm = X509_NAME_new())) 593 goto err; 594 sk = X509V3_get_section(ctx, value); 595 if (!sk) { 596 X509V3err(X509V3_F_DO_DIRNAME, X509V3_R_SECTION_NOT_FOUND); 597 ERR_add_error_data(2, "section=", value); 598 goto err; 599 } 600 /* FIXME: should allow other character types... */ 601 ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC); 602 if (!ret) 603 goto err; 604 gen->d.dirn = nm; 605 606err: 607 if (ret == 0) 608 X509_NAME_free(nm); 609 X509V3_section_free(ctx, sk); 610 return ret; 611} 612