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