1 /* $NetBSD: tls_certkey.c,v 1.4 2022/10/08 16:12:50 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* tls_certkey 3 6 /* SUMMARY 7 /* public key certificate and private key loader 8 /* SYNOPSIS 9 /* #define TLS_INTERNAL 10 /* #include <tls.h> 11 /* 12 /* int tls_set_ca_certificate_info(ctx, CAfile, CApath) 13 /* SSL_CTX *ctx; 14 /* const char *CAfile; 15 /* const char *CApath; 16 /* 17 /* int tls_set_my_certificate_key_info(ctx, chain_files, 18 /* cert_file, key_file, 19 /* dcert_file, dkey_file, 20 /* eccert_file, eckey_file) 21 /* SSL_CTX *ctx; 22 /* const char *chain_files; 23 /* const char *cert_file; 24 /* const char *key_file; 25 /* const char *dcert_file; 26 /* const char *dkey_file; 27 /* const char *eccert_file; 28 /* const char *eckey_file; 29 /* 30 /* int tls_load_pem_chain(ssl, pem, origin); 31 /* SSL *ssl; 32 /* const char *pem; 33 /* const char *origin; 34 /* DESCRIPTION 35 /* OpenSSL supports two options to specify CA certificates: 36 /* either one file CAfile that contains all CA certificates, 37 /* or a directory CApath with separate files for each 38 /* individual CA, with symbolic links named after the hash 39 /* values of the certificates. The second option is not 40 /* convenient with a chrooted process. 41 /* 42 /* tls_set_ca_certificate_info() loads the CA certificate 43 /* information for the specified TLS server or client context. 44 /* The result is -1 on failure, 0 on success. 45 /* 46 /* tls_set_my_certificate_key_info() loads the public key 47 /* certificates and private keys for the specified TLS server 48 /* or client context. Up to 3 pairs of key pairs (RSA, DSA and 49 /* ECDSA) may be specified; each certificate and key pair must 50 /* match. The chain_files argument makes it possible to load 51 /* keys and certificates for more than 3 algorithms, via either 52 /* a single file, or a list of multiple files. The result is -1 53 /* on failure, 0 on success. 54 /* 55 /* tls_load_pem_chain() loads one or more (key, cert, [chain]) 56 /* triples from an in-memory PEM blob. The "origin" argument 57 /* is used for error logging, to identify the provenance of the 58 /* PEM blob. "ssl" must be non-zero, and the keys and certificates 59 /* will be loaded into that object. 60 /* LICENSE 61 /* .ad 62 /* .fi 63 /* This software is free. You can do with it whatever you want. 64 /* The original author kindly requests that you acknowledge 65 /* the use of his software. 66 /* AUTHOR(S) 67 /* Originally written by: 68 /* Lutz Jaenicke 69 /* BTU Cottbus 70 /* Allgemeine Elektrotechnik 71 /* Universitaetsplatz 3-4 72 /* D-03044 Cottbus, Germany 73 /* 74 /* Updated by: 75 /* Wietse Venema 76 /* IBM T.J. Watson Research 77 /* P.O. Box 704 78 /* Yorktown Heights, NY 10598, USA 79 /* 80 /* Wietse Venema 81 /* Google, Inc. 82 /* 111 8th Avenue 83 /* New York, NY 10011, USA 84 /*--*/ 85 86 /* System library. */ 87 88 #include <sys_defs.h> 89 90 #ifdef USE_TLS 91 92 /* Utility library. */ 93 94 #include <msg.h> 95 96 /* Global library. */ 97 98 #include <mail_params.h> 99 100 /* TLS library. */ 101 102 #define TLS_INTERNAL 103 #include <tls.h> 104 105 #define PEM_LOAD_STATE_NOGO -2 /* Unusable object or sequence */ 106 #define PEM_LOAD_STATE_FAIL -1 /* Error in libcrypto */ 107 #define PEM_LOAD_STATE_DONE 0 /* End of PEM file, return value only */ 108 #define PEM_LOAD_STATE_INIT 1 /* No PEM objects seen */ 109 #define PEM_LOAD_STATE_PKEY 2 /* Last object was a private key */ 110 #define PEM_LOAD_STATE_CERT 3 /* Last object was a certificate */ 111 #define PEM_LOAD_STATE_BOTH 4 /* Unordered, key + first cert seen */ 112 113 #define PEM_LOAD_READ_LAST 0 /* Reading last file */ 114 #define PEM_LOAD_READ_MORE 1 /* More files to be read */ 115 116 typedef struct pem_load_state_t { 117 const char *origin; /* PEM chain origin description */ 118 const char *source; /* PEM BIO origin description */ 119 const char *keysrc; /* Source of last key */ 120 BIO *pembio; /* PEM input stream */ 121 SSL_CTX *ctx; /* SSL connection factory */ 122 SSL *ssl; /* SSL connection handle */ 123 EVP_PKEY *pkey; /* current key */ 124 X509 *cert; /* current certificate */ 125 x509_stack_t *chain; /* current chain */ 126 int keynum; /* Index of last key */ 127 int objnum; /* Index in current source */ 128 int state; /* Current state, never "DONE" */ 129 int mixed; /* Single file with key anywhere */ 130 } pem_load_state_t; 131 132 /* init_pem_load_state - fill in initial pem_load_state structure */ 133 134 static void init_pem_load_state(pem_load_state_t *st, SSL_CTX *ctx, SSL *ssl, 135 const char *origin) 136 { 137 st->origin = origin; 138 st->source = origin; 139 st->keysrc = 0; 140 st->pembio = 0; 141 st->ctx = ctx; 142 st->ssl = ssl; 143 st->pkey = 0; 144 st->cert = 0; 145 st->chain = 0; 146 st->keynum = 0; 147 st->objnum = 0; 148 st->state = PEM_LOAD_STATE_INIT; 149 st->mixed = 0; 150 } 151 152 /* use_chain - load cert, key and chain into ctx or ssl */ 153 154 static int use_chain(pem_load_state_t *st) 155 { 156 int ret; 157 int replace = 0; 158 159 /* 160 * With replace == 0, an error is returned if the algorithm slot is 161 * already taken, and a previous key + chain of the same type would be 162 * clobbered. 163 */ 164 if (st->ctx) 165 ret = SSL_CTX_use_cert_and_key(st->ctx, st->cert, st->pkey, st->chain, 166 replace); 167 else 168 ret = SSL_use_cert_and_key(st->ssl, st->cert, st->pkey, st->chain, 169 replace); 170 171 /* 172 * SSL_[CTX_]_use_cert_key() uprefs all the objects in question, so we 173 * must free ours. 174 */ 175 X509_free(st->cert); 176 st->cert = 0; 177 EVP_PKEY_free(st->pkey); 178 st->pkey = 0; 179 sk_X509_pop_free(st->chain, X509_free); 180 st->chain = 0; 181 182 return ret; 183 } 184 185 /* load_cert - decode and load a DER-encoded X509 certificate */ 186 187 static void load_cert(pem_load_state_t *st, unsigned char *buf, 188 long buflen) 189 { 190 const unsigned char *p = buf; 191 X509 *cert = d2i_X509(0, &p, buflen); 192 193 /* 194 * When expecting one or more keys, each key must precede the associated 195 * certificate (chain). 196 */ 197 if (!st->mixed && st->state == PEM_LOAD_STATE_INIT) { 198 msg_warn("error loading chain from %s: key not first", st->source); 199 if (cert) 200 X509_free(cert); 201 st->state = PEM_LOAD_STATE_NOGO; 202 return; 203 } 204 if (!cert) { 205 msg_warn("error loading certificate (PEM object number %d) from %s", 206 st->objnum, st->source); 207 st->state = PEM_LOAD_STATE_FAIL; 208 return; 209 } 210 if (p - buf != buflen) { 211 msg_warn("error loading certificate (PEM object number %d) from %s:" 212 " excess data", st->objnum, st->source); 213 X509_free(cert); 214 st->state = PEM_LOAD_STATE_NOGO; 215 return; 216 } 217 218 /* 219 * The first certificate after a new key becomes the leaf certificate for 220 * that key. Subsequent certificates are added to the issuer chain. 221 * 222 * In "mixed" mode, the first certificate is either after the key, or else 223 * comes first. 224 */ 225 switch (st->state) { 226 case PEM_LOAD_STATE_PKEY: 227 st->cert = cert; 228 st->state = st->mixed ? PEM_LOAD_STATE_BOTH : PEM_LOAD_STATE_CERT; 229 return; 230 case PEM_LOAD_STATE_INIT: 231 st->cert = cert; 232 st->state = PEM_LOAD_STATE_CERT; 233 return; 234 case PEM_LOAD_STATE_CERT: 235 case PEM_LOAD_STATE_BOTH: 236 if ((!st->chain && (st->chain = sk_X509_new_null()) == 0) 237 || !sk_X509_push(st->chain, cert)) { 238 X509_free(cert); 239 st->state = PEM_LOAD_STATE_FAIL; 240 } 241 return; 242 } 243 } 244 245 /* load_pkey - decode and load a DER-encoded private key */ 246 247 static void load_pkey(pem_load_state_t *st, int pkey_type, 248 unsigned char *buf, long buflen) 249 { 250 const char *myname = "load_pkey"; 251 const unsigned char *p = buf; 252 PKCS8_PRIV_KEY_INFO *p8; 253 EVP_PKEY *pkey = 0; 254 255 /* 256 * Keys are either algorithm-specific, or else (ideally) algorithm 257 * agnostic, in which case they are wrapped as PKCS#8 objects with an 258 * algorithm OID. 259 */ 260 if (pkey_type != NID_undef) { 261 pkey = d2i_PrivateKey(pkey_type, 0, &p, buflen); 262 } else { 263 p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, buflen); 264 if (p8) { 265 pkey = EVP_PKCS82PKEY(p8); 266 PKCS8_PRIV_KEY_INFO_free(p8); 267 } 268 } 269 270 /* 271 * Except in "mixed" mode, where a single key appears anywhere in a file 272 * with multiple certificates, a given key is either at the first object 273 * we process, or occurs after a previous key and one or more associated 274 * certificates. Thus, encountering a key in a state other than "INIT" 275 * or "CERT" is an error, except in "mixed" mode where a second key is 276 * ignored with a warning. 277 */ 278 switch (st->state) { 279 case PEM_LOAD_STATE_CERT: 280 281 /* 282 * When processing the key of a "next" chain, we're in the "CERT" 283 * state, and first complete the processing of the previous chain. 284 */ 285 if (!st->mixed && !use_chain(st)) { 286 msg_warn("error loading certificate chain: " 287 "key at index %d in %s does not match the certificate", 288 st->keynum, st->keysrc); 289 st->state = PEM_LOAD_STATE_FAIL; 290 return; 291 } 292 /* FALLTHROUGH */ 293 case PEM_LOAD_STATE_INIT: 294 295 if (!pkey) { 296 msg_warn("error loading private key (PEM object number %d) from %s", 297 st->objnum, st->source); 298 st->state = PEM_LOAD_STATE_FAIL; 299 return; 300 } 301 /* Reject unexpected data beyond the end of the DER-encoded object */ 302 if (p - buf != buflen) { 303 msg_warn("error loading private key (PEM object number %d) from" 304 " %s: excess data", st->objnum, st->source); 305 EVP_PKEY_free(pkey); 306 st->state = PEM_LOAD_STATE_NOGO; 307 return; 308 } 309 /* All's well, update the state */ 310 st->pkey = pkey; 311 if (st->state == PEM_LOAD_STATE_INIT) 312 st->state = PEM_LOAD_STATE_PKEY; 313 else if (st->mixed) 314 st->state = PEM_LOAD_STATE_BOTH; 315 else 316 st->state = PEM_LOAD_STATE_PKEY; 317 return; 318 319 case PEM_LOAD_STATE_PKEY: 320 case PEM_LOAD_STATE_BOTH: 321 if (pkey) 322 EVP_PKEY_free(pkey); 323 324 /* XXX: Legacy behavior was silent, should we stay silent? */ 325 if (st->mixed) { 326 msg_warn("ignoring 2nd key at index %d in %s after 1st at %d", 327 st->objnum, st->source, st->keynum); 328 return; 329 } 330 /* else back-to-back keys */ 331 msg_warn("error loading certificate chain: " 332 "key at index %d in %s not followed by a certificate", 333 st->keynum, st->keysrc); 334 st->state = PEM_LOAD_STATE_NOGO; 335 return; 336 337 default: 338 msg_error("%s: internal error: bad state: %d", myname, st->state); 339 st->state = PEM_LOAD_STATE_NOGO; 340 return; 341 } 342 } 343 344 /* load_pem_object - load next pkey or cert from open BIO */ 345 346 static int load_pem_object(pem_load_state_t *st) 347 { 348 char *name = 0; 349 char *header = 0; 350 unsigned char *buf = 0; 351 long buflen; 352 int pkey_type = NID_undef; 353 354 if (!PEM_read_bio(st->pembio, &name, &header, &buf, &buflen)) { 355 if (ERR_GET_REASON(ERR_peek_last_error()) != PEM_R_NO_START_LINE) 356 return (st->state = PEM_LOAD_STATE_FAIL); 357 358 ERR_clear_error(); 359 /* Clean EOF, preserve stored state for any next input file */ 360 return (PEM_LOAD_STATE_DONE); 361 } 362 if (strcmp(name, PEM_STRING_X509) == 0 363 || strcmp(name, PEM_STRING_X509_OLD) == 0) { 364 load_cert(st, buf, buflen); 365 } else if (strcmp(name, PEM_STRING_PKCS8INF) == 0 366 || ((pkey_type = EVP_PKEY_RSA) != NID_undef 367 && strcmp(name, PEM_STRING_RSA) == 0) 368 || ((pkey_type = EVP_PKEY_EC) != NID_undef 369 && strcmp(name, PEM_STRING_ECPRIVATEKEY) == 0) 370 || ((pkey_type = EVP_PKEY_DSA) != NID_undef 371 && strcmp(name, PEM_STRING_DSA) == 0)) { 372 load_pkey(st, pkey_type, buf, buflen); 373 } else if (!st->mixed) { 374 msg_warn("loading %s: ignoring PEM type: %s", st->source, name); 375 } 376 OPENSSL_free(name); 377 OPENSSL_free(header); 378 OPENSSL_free(buf); 379 return (st->state); 380 } 381 382 /* load_pem_bio - load all key/certs from bio and free the bio */ 383 384 static int load_pem_bio(pem_load_state_t *st, int more) 385 { 386 int state = st->state; 387 388 /* Don't report old news */ 389 ERR_clear_error(); 390 391 /* 392 * When "more" is PEM_LOAD_READ_MORE, more files will be loaded after the 393 * current file, and final processing for the last key and chain is 394 * deferred. 395 * 396 * When "more" is PEM_LOAD_READ_LAST, this is the last file in the list, and 397 * we validate the final chain. 398 * 399 * When st->mixed is true, this is the only file, and its key can occur at 400 * any location. In this case we load at most one key. 401 */ 402 for (st->objnum = 1; state > PEM_LOAD_STATE_DONE; ++st->objnum) { 403 state = load_pem_object(st); 404 if ((st->mixed && st->keynum == 0 && 405 (state == PEM_LOAD_STATE_PKEY || state == PEM_LOAD_STATE_BOTH)) 406 || (!st->mixed && state == PEM_LOAD_STATE_PKEY)) { 407 /* Squirrel-away the current key location */ 408 st->keynum = st->objnum; 409 st->keysrc = st->source; 410 } 411 } 412 /* We're responsible for unconditionally freeing the BIO */ 413 BIO_free(st->pembio); 414 415 /* Success with current file, go back for more? */ 416 if (more == PEM_LOAD_READ_MORE && state >= PEM_LOAD_STATE_DONE) 417 return 0; 418 419 /* 420 * If all is well so far, complete processing for the final chain. 421 */ 422 switch (st->state) { 423 case PEM_LOAD_STATE_FAIL: 424 tls_print_errors(); 425 break; 426 default: 427 break; 428 case PEM_LOAD_STATE_INIT: 429 msg_warn("No PEM data in %s", st->origin); 430 break; 431 case PEM_LOAD_STATE_PKEY: 432 msg_warn("No certs for key at index %d in %s", st->keynum, st->keysrc); 433 break; 434 case PEM_LOAD_STATE_CERT: 435 if (st->mixed) { 436 msg_warn("No private key found in %s", st->origin); 437 break; 438 } 439 /* FALLTHROUGH */ 440 case PEM_LOAD_STATE_BOTH: 441 /* use_chain() frees the key and certs, and zeroes the pointers */ 442 if (use_chain(st)) 443 return (0); 444 msg_warn("key at index %d in %s does not match next certificate", 445 st->keynum, st->keysrc); 446 tls_print_errors(); 447 break; 448 } 449 /* Free any left-over unused keys and certs */ 450 EVP_PKEY_free(st->pkey); 451 X509_free(st->cert); 452 sk_X509_pop_free(st->chain, X509_free); 453 454 msg_warn("error loading private keys and certificates from: %s: %s", 455 st->origin, st->ctx ? "disabling TLS support" : 456 "aborting TLS handshake"); 457 return (-1); 458 } 459 460 /* load_chain_files - load sequence of (key, cert, [chain]) from files */ 461 462 static int load_chain_files(SSL_CTX *ctx, const char *chain_files) 463 { 464 pem_load_state_t st; 465 ARGV *files = argv_split(chain_files, CHARS_COMMA_SP); 466 char **filep; 467 int ret = 0; 468 int more; 469 470 init_pem_load_state(&st, ctx, 0, chain_files); 471 for (filep = files->argv; ret == 0 && *filep; ++filep) { 472 st.source = *filep; 473 if ((st.pembio = BIO_new_file(st.source, "r")) == NULL) { 474 msg_warn("error opening chain file: %s: %m", st.source); 475 st.state = PEM_LOAD_STATE_NOGO; 476 break; 477 } 478 more = filep[1] ? PEM_LOAD_READ_MORE : PEM_LOAD_READ_LAST; 479 /* load_pem_bio() frees the BIO */ 480 ret = load_pem_bio(&st, more); 481 } 482 argv_free(files); 483 return (ret); 484 } 485 486 /* load_mixed_file - load certs with single key anywhere in the file */ 487 488 static int load_mixed_file(SSL_CTX *ctx, const char *file) 489 { 490 pem_load_state_t st; 491 492 init_pem_load_state(&st, ctx, 0, file); 493 if ((st.pembio = BIO_new_file(st.source, "r")) == NULL) { 494 msg_warn("error opening chain file: %s: %m", st.source); 495 return (-1); 496 } 497 st.mixed = 1; 498 /* load_pem_bio() frees the BIO */ 499 return load_pem_bio(&st, PEM_LOAD_READ_LAST); 500 } 501 502 /* tls_set_ca_certificate_info - load Certification Authority certificates */ 503 504 int tls_set_ca_certificate_info(SSL_CTX *ctx, const char *CAfile, 505 const char *CApath) 506 { 507 if (*CAfile == 0) 508 CAfile = 0; 509 if (*CApath == 0) 510 CApath = 0; 511 512 #define CA_PATH_FMT "%s%s%s" 513 #define CA_PATH_ARGS(var, nextvar) \ 514 var ? #var "=\"" : "", \ 515 var ? var : "", \ 516 var ? (nextvar ? "\", " : "\"") : "" 517 518 if (CAfile || CApath) { 519 if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) { 520 msg_info("cannot load Certification Authority data, " 521 CA_PATH_FMT CA_PATH_FMT ": disabling TLS support", 522 CA_PATH_ARGS(CAfile, CApath), 523 CA_PATH_ARGS(CApath, 0)); 524 tls_print_errors(); 525 return (-1); 526 } 527 if (var_tls_append_def_CA && !SSL_CTX_set_default_verify_paths(ctx)) { 528 msg_info("cannot set default OpenSSL certificate verification " 529 "paths: disabling TLS support"); 530 tls_print_errors(); 531 return (-1); 532 } 533 } 534 return (0); 535 } 536 537 /* set_cert_stuff - specify certificate and key information */ 538 539 static int set_cert_stuff(SSL_CTX *ctx, const char *cert_type, 540 const char *cert_file, 541 const char *key_file) 542 { 543 544 /* 545 * When the certfile and keyfile are one and the same, load both in a 546 * single pass, avoiding potential race conditions during key rollover. 547 */ 548 if (strcmp(cert_file, key_file) == 0) 549 return (load_mixed_file(ctx, cert_file) == 0); 550 551 /* 552 * We need both the private key (in key_file) and the public key 553 * certificate (in cert_file). 554 * 555 * Code adapted from OpenSSL apps/s_cb.c. 556 */ 557 ERR_clear_error(); 558 if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) { 559 msg_warn("cannot get %s certificate from file \"%s\": " 560 "disabling TLS support", cert_type, cert_file); 561 tls_print_errors(); 562 return (0); 563 } 564 if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) { 565 msg_warn("cannot get %s private key from file \"%s\": " 566 "disabling TLS support", cert_type, key_file); 567 tls_print_errors(); 568 return (0); 569 } 570 571 /* 572 * Sanity check. 573 */ 574 if (!SSL_CTX_check_private_key(ctx)) { 575 msg_warn("%s private key in %s does not match public key in %s: " 576 "disabling TLS support", cert_type, key_file, cert_file); 577 return (0); 578 } 579 return (1); 580 } 581 582 /* tls_set_my_certificate_key_info - load client or server certificates/keys */ 583 584 int tls_set_my_certificate_key_info(SSL_CTX *ctx, const char *chain_files, 585 const char *cert_file, 586 const char *key_file, 587 const char *dcert_file, 588 const char *dkey_file, 589 const char *eccert_file, 590 const char *eckey_file) 591 { 592 593 /* The "chain_files" parameter overrides all the legacy parameters */ 594 if (chain_files && *chain_files) 595 return load_chain_files(ctx, chain_files); 596 597 /* 598 * Lack of certificates is fine so long as we are prepared to use 599 * anonymous ciphers. 600 */ 601 if (*cert_file && !set_cert_stuff(ctx, "RSA", cert_file, key_file)) 602 return (-1); /* logged */ 603 if (*dcert_file && !set_cert_stuff(ctx, "DSA", dcert_file, dkey_file)) 604 return (-1); /* logged */ 605 #ifndef OPENSSL_NO_ECDH 606 if (*eccert_file && !set_cert_stuff(ctx, "ECDSA", eccert_file, eckey_file)) 607 return (-1); /* logged */ 608 #else 609 if (*eccert_file) 610 msg_warn("ECDSA not supported. Ignoring ECDSA certificate file \"%s\"", 611 eccert_file); 612 #endif 613 return (0); 614 } 615 616 /* tls_load_pem_chain - load in-memory PEM client or server chain */ 617 618 int tls_load_pem_chain(SSL *ssl, const char *pem, const char *origin) 619 { 620 static VSTRING *obuf; 621 pem_load_state_t st; 622 623 if (!obuf) 624 obuf = vstring_alloc(100); 625 vstring_sprintf(obuf, "SNI data for %s", origin); 626 init_pem_load_state(&st, 0, ssl, vstring_str(obuf)); 627 628 if ((st.pembio = BIO_new_mem_buf(pem, -1)) == NULL) { 629 msg_warn("error opening memory BIO for %s", st.origin); 630 tls_print_errors(); 631 return (-1); 632 } 633 /* load_pem_bio() frees the BIO */ 634 return (load_pem_bio(&st, PEM_LOAD_READ_LAST)); 635 } 636 637 #ifdef TEST 638 639 static NORETURN usage(void) 640 { 641 fprintf(stderr, "usage: tls_certkey [-m] <chainfiles>\n"); 642 exit(1); 643 } 644 645 int main(int argc, char *argv[]) 646 { 647 int ch; 648 int mixed = 0; 649 int ret; 650 char *key_file = 0; 651 SSL_CTX *ctx; 652 653 if (!(ctx = SSL_CTX_new(TLS_client_method()))) { 654 tls_print_errors(); 655 exit(1); 656 } 657 while ((ch = GETOPT(argc, argv, "mk:")) > 0) { 658 switch (ch) { 659 case 'k': 660 key_file = optarg; 661 break; 662 case 'm': 663 mixed = 1; 664 break; 665 default: 666 usage(); 667 } 668 } 669 argc -= optind; 670 argv += optind; 671 672 if (argc < 1) 673 usage(); 674 675 if (key_file) 676 ret = set_cert_stuff(ctx, "any", argv[0], key_file) == 0; 677 else if (mixed) 678 ret = load_mixed_file(ctx, argv[0]); 679 else 680 ret = load_chain_files(ctx, argv[0]); 681 682 if (ret != 0) 683 exit(1); 684 685 if (SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST) != 1) { 686 fprintf(stderr, "error selecting first certificate\n"); 687 tls_print_errors(); 688 exit(1); 689 } 690 do { 691 STACK_OF(X509) *chain; 692 int i; 693 694 if (SSL_CTX_get0_chain_certs(ctx, &chain) != 1) { 695 fprintf(stderr, "error locating certificate chain\n"); 696 tls_print_errors(); 697 exit(1); 698 } 699 for (i = 0; i <= sk_X509_num(chain); ++i) { 700 char buf[CCERT_BUFSIZ]; 701 X509 *cert; 702 703 if (i > 0) 704 cert = sk_X509_value(chain, i - 1); 705 else 706 cert = SSL_CTX_get0_certificate(ctx); 707 708 printf("depth = %d\n", i); 709 710 X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf)); 711 printf("issuer = %s\n", buf); 712 713 X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); 714 printf("subject = %s\n\n", buf); 715 } 716 } while (SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_NEXT) != 0); 717 718 exit(0); 719 } 720 721 #endif 722 723 #endif 724