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