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