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