Home | History | Annotate | Line # | Download | only in tls
      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