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 
init_pem_load_state(pem_load_state_t * st,SSL_CTX * ctx,SSL * ssl,const char * origin)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 
use_chain(pem_load_state_t * st)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 
load_cert(pem_load_state_t * st,unsigned char * buf,long buflen)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 
load_pkey(pem_load_state_t * st,int pkey_type,unsigned char * buf,long buflen)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 
load_pem_object(pem_load_state_t * st)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 
load_pem_bio(pem_load_state_t * st,int more)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 
load_chain_files(SSL_CTX * ctx,const char * chain_files)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 
load_mixed_file(SSL_CTX * ctx,const char * file)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 
tls_set_ca_certificate_info(SSL_CTX * ctx,const char * CAfile,const char * CApath)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 
set_cert_stuff(SSL_CTX * ctx,const char * cert_type,const char * cert_file,const char * key_file)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 
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)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 
tls_load_pem_chain(SSL * ssl,const char * pem,const char * origin)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 
usage(void)639 static NORETURN usage(void)
640 {
641     fprintf(stderr, "usage: tls_certkey [-m] <chainfiles>\n");
642     exit(1);
643 }
644 
main(int argc,char * argv[])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