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