Been running it for a few days, no regressions so far

> On 5 Feb 2021, at 09:35, Eric Faurot <e...@openbsd.org> wrote:
> 
> No much report so far.
> Anybody had a chance to test this?
> Here is the same diff again with manpage update this time.
> 
> Eric.
> 
> Index: ca.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/ca.c,v
> retrieving revision 1.37
> diff -u -p -r1.37 ca.c
> --- ca.c      31 Dec 2020 08:27:15 -0000      1.37
> +++ ca.c      19 Jan 2021 11:09:54 -0000
> @@ -69,6 +69,7 @@ static int ecdsae_do_verify(const unsign
>     EC_KEY *);
> 
> 
> +static struct dict pkeys;
> static uint64_t        reqid = 0;
> 
> static void
> @@ -132,26 +133,29 @@ ca_init(void)
>       struct pki      *pki;
>       const char      *k;
>       void            *iter_dict;
> +     char            *hash;
> 
>       log_debug("debug: init private ssl-tree");
> +     dict_init(&pkeys);
>       iter_dict = NULL;
>       while (dict_iter(env->sc_pki_dict, &iter_dict, &k, (void **)&pki)) {
>               if (pki->pki_key == NULL)
>                       continue;
> 
> -             if ((in = BIO_new_mem_buf(pki->pki_key,
> -                 pki->pki_key_len)) == NULL)
> -                     fatalx("ca_launch: key");
> -
> -             if ((pkey = PEM_read_bio_PrivateKey(in,
> -                 NULL, NULL, NULL)) == NULL)
> -                     fatalx("ca_launch: PEM");
> +             in = BIO_new_mem_buf(pki->pki_key, pki->pki_key_len);
> +             if (in == NULL)
> +                     fatalx("ca_init: key");
> +             pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
> +             if (pkey == NULL)
> +                     fatalx("ca_init: PEM");
>               BIO_free(in);
> 
> -             pki->pki_pkey = pkey;
> -
> -             freezero(pki->pki_key, pki->pki_key_len);
> -             pki->pki_key = NULL;
> +             hash = ssl_pubkey_hash(pki->pki_cert, pki->pki_cert_len);
> +             if (dict_check(&pkeys, hash))
> +                     EVP_PKEY_free(pkey);
> +             else
> +                     dict_xset(&pkeys, hash, pkey);
> +             free(hash);
>       }
> }
> 
> @@ -223,15 +227,15 @@ end:
> void
> ca_imsg(struct mproc *p, struct imsg *imsg)
> {
> +     EVP_PKEY                *pkey;
>       RSA                     *rsa = NULL;
>       EC_KEY                  *ecdsa = NULL;
>       const void              *from = NULL;
>       unsigned char           *to = NULL;
>       struct msg               m;
> -     const char              *pkiname;
> +     const char              *hash;
>       size_t                   flen, tlen, padding;
>       int                      buf_len;
> -     struct pki              *pki;
>       int                      ret = 0;
>       uint64_t                 id;
>       int                      v;
> @@ -267,16 +271,15 @@ ca_imsg(struct mproc *p, struct imsg *im
>       case IMSG_CA_RSA_PRIVDEC:
>               m_msg(&m, imsg);
>               m_get_id(&m, &id);
> -             m_get_string(&m, &pkiname);
> +             m_get_string(&m, &hash);
>               m_get_data(&m, &from, &flen);
>               m_get_size(&m, &tlen);
>               m_get_size(&m, &padding);
>               m_end(&m);
> 
> -             pki = dict_get(env->sc_pki_dict, pkiname);
> -             if (pki == NULL || pki->pki_pkey == NULL ||
> -                 (rsa = EVP_PKEY_get1_RSA(pki->pki_pkey)) == NULL)
> -                     fatalx("ca_imsg: invalid pki");
> +             pkey = dict_get(&pkeys, hash);
> +             if (pkey == NULL || (rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
> +                     fatalx("ca_imsg: invalid pkey hash");
> 
>               if ((to = calloc(1, tlen)) == NULL)
>                       fatalx("ca_imsg: calloc");
> @@ -306,14 +309,14 @@ ca_imsg(struct mproc *p, struct imsg *im
>       case IMSG_CA_ECDSA_SIGN:
>               m_msg(&m, imsg);
>               m_get_id(&m, &id);
> -             m_get_string(&m, &pkiname);
> +             m_get_string(&m, &hash);
>               m_get_data(&m, &from, &flen);
>               m_end(&m);
> 
> -             pki = dict_get(env->sc_pki_dict, pkiname);
> -             if (pki == NULL || pki->pki_pkey == NULL ||
> -                 (ecdsa = EVP_PKEY_get1_EC_KEY(pki->pki_pkey)) == NULL)
> -                     fatalx("ca_imsg: invalid pki");
> +             pkey = dict_get(&pkeys, hash);
> +             if (pkey == NULL ||
> +                 (ecdsa = EVP_PKEY_get1_EC_KEY(pkey)) == NULL)
> +                     fatalx("ca_imsg: invalid pkey hash");
> 
>               buf_len = ECDSA_size(ecdsa);
>               if ((to = calloc(1, buf_len)) == NULL)
> @@ -350,12 +353,12 @@ rsae_send_imsg(int flen, const unsigned 
>       struct imsg      imsg;
>       int              n, done = 0;
>       const void      *toptr;
> -     char            *pkiname;
> +     char            *hash;
>       size_t           tlen;
>       struct msg       m;
>       uint64_t         id;
> 
> -     if ((pkiname = RSA_get_ex_data(rsa, 0)) == NULL)
> +     if ((hash = RSA_get_ex_data(rsa, 0)) == NULL)
>               return (0);
> 
>       /*
> @@ -365,7 +368,7 @@ rsae_send_imsg(int flen, const unsigned 
>       m_create(p_ca, cmd, 0, 0, -1);
>       reqid++;
>       m_add_id(p_ca, reqid);
> -     m_add_string(p_ca, pkiname);
> +     m_add_string(p_ca, hash);
>       m_add_data(p_ca, (const void *)from, (size_t)flen);
>       m_add_size(p_ca, (size_t)RSA_size(rsa));
>       m_add_size(p_ca, (size_t)padding);
> @@ -536,13 +539,13 @@ ecdsae_send_enc_imsg(const unsigned char
>       struct imsg      imsg;
>       int              n, done = 0;
>       const void      *toptr;
> -     char            *pkiname;
> +     char            *hash;
>       size_t           tlen;
>       struct msg       m;
>       uint64_t         id;
>       ECDSA_SIG       *sig = NULL;
> 
> -     if ((pkiname = ECDSA_get_ex_data(eckey, 0)) == NULL)
> +     if ((hash = ECDSA_get_ex_data(eckey, 0)) == NULL)
>               return (0);
> 
>       /*
> @@ -552,7 +555,7 @@ ecdsae_send_enc_imsg(const unsigned char
>       m_create(p_ca, IMSG_CA_ECDSA_SIGN, 0, 0, -1);
>       reqid++;
>       m_add_id(p_ca, reqid);
> -     m_add_string(p_ca, pkiname);
> +     m_add_string(p_ca, hash);
>       m_add_data(p_ca, (const void *)dgst, (size_t)dgst_len);
>       m_flush(p_ca);
> 
> Index: config.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/config.c,v
> retrieving revision 1.53
> diff -u -p -r1.53 config.c
> --- config.c  19 Jan 2021 09:16:20 -0000      1.53
> +++ config.c  19 Jan 2021 11:47:07 -0000
> @@ -252,6 +252,7 @@ purge_config(uint8_t what)
>       if (what & PURGE_LISTENERS) {
>               while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
>                       TAILQ_REMOVE(env->sc_listeners, l, entry);
> +                     free(l->pki);
>                       free(l);
>               }
>               free(env->sc_listeners);
> Index: dispatcher.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/dispatcher.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 dispatcher.c
> --- dispatcher.c      31 Dec 2020 08:27:15 -0000      1.1
> +++ dispatcher.c      19 Jan 2021 11:04:32 -0000
> @@ -154,6 +154,8 @@ dispatcher(void)
> {
>       struct passwd   *pw;
> 
> +     ca_engine_init();
> +
>       mda_postfork();
>       mta_postfork();
>       smtp_postfork();
> @@ -195,8 +197,6 @@ dispatcher(void)
>       config_peer(PROC_LKA);
>       config_peer(PROC_CONTROL);
>       config_peer(PROC_CA);
> -
> -     ca_engine_init();
> 
>       if (pledge("stdio inet unix recvfd sendfd", NULL) == -1)
>               err(1, "pledge");
> Index: iobuf.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/iobuf.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 iobuf.c
> --- iobuf.c   23 Jan 2021 16:11:11 -0000      1.14
> +++ iobuf.c   25 Jan 2021 11:14:58 -0000
> @@ -21,15 +21,14 @@
> 
> #include <errno.h>
> #include <limits.h>
> +#include <stdarg.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> -#include <unistd.h>
> -
> #ifdef IO_TLS
> -#include <openssl/err.h>
> -#include <openssl/ssl.h>
> +#include <tls.h>
> #endif
> +#include <unistd.h>
> 
> #include "iobuf.h"
> 
> @@ -388,7 +387,7 @@ iobuf_flush(struct iobuf *io, int fd)
> #ifdef IO_TLS
> 
> int
> -iobuf_flush_tls(struct iobuf *io, void *tls)
> +iobuf_flush_tls(struct iobuf *io, struct tls *tls)
> {
>       ssize_t s;
> 
> @@ -400,55 +399,42 @@ iobuf_flush_tls(struct iobuf *io, void *
> }
> 
> ssize_t
> -iobuf_write_tls(struct iobuf *io, void *tls)
> +iobuf_write_tls(struct iobuf *io, struct tls *tls)
> {
>       struct ioqbuf   *q;
>       ssize_t          n;
> 
>       q = io->outq;
> -     n = SSL_write(tls, q->buf + q->rpos, q->wpos - q->rpos);
> -     if (n <= 0) {
> -             switch (SSL_get_error(tls, n)) {
> -             case SSL_ERROR_WANT_READ:
> -                     return (IOBUF_WANT_READ);
> -             case SSL_ERROR_WANT_WRITE:
> -                     return (IOBUF_WANT_WRITE);
> -             case SSL_ERROR_ZERO_RETURN: /* connection closed */
> -                     return (IOBUF_CLOSED);
> -             case SSL_ERROR_SYSCALL:
> -                     if (ERR_peek_last_error())
> -                             return (IOBUF_TLSERROR);
> -                     return (IOBUF_ERROR);
> -             default:
> -                     return (IOBUF_TLSERROR);
> -             }
> -     }
> +
> +     n = tls_write(tls, q->buf + q->rpos, q->wpos - q->rpos);
> +     if (n == TLS_WANT_POLLIN)
> +             return (IOBUF_WANT_READ);
> +     else if (n == TLS_WANT_POLLOUT)
> +             return (IOBUF_WANT_WRITE);
> +     else if (n == 0)
> +             return (IOBUF_CLOSED);
> +     else if (n == -1)
> +             return (IOBUF_ERROR);
> +
>       iobuf_drain(io, n);
> 
>       return (n);
> }
> 
> ssize_t
> -iobuf_read_tls(struct iobuf *io, void *tls)
> +iobuf_read_tls(struct iobuf *io, struct tls *tls)
> {
>       ssize_t n;
> 
> -     n = SSL_read(tls, io->buf + io->wpos, iobuf_left(io));
> -     if (n < 0) {
> -             switch (SSL_get_error(tls, n)) {
> -             case SSL_ERROR_WANT_READ:
> -                     return (IOBUF_WANT_READ);
> -             case SSL_ERROR_WANT_WRITE:
> -                     return (IOBUF_WANT_WRITE);
> -             case SSL_ERROR_SYSCALL:
> -                     if (ERR_peek_last_error())
> -                             return (IOBUF_TLSERROR);
> -                     return (IOBUF_ERROR);
> -             default:
> -                     return (IOBUF_TLSERROR);
> -             }
> -     } else if (n == 0)
> +     n = tls_read(tls, io->buf + io->wpos, iobuf_left(io));
> +     if (n == TLS_WANT_POLLIN)
> +             return (IOBUF_WANT_READ);
> +     else if (n == TLS_WANT_POLLOUT)
> +             return (IOBUF_WANT_WRITE);
> +     else if (n == 0)
>               return (IOBUF_CLOSED);
> +     else if (n == -1)
> +             return (IOBUF_ERROR);
> 
>       io->wpos += n;
> 
> Index: iobuf.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/iobuf.h,v
> retrieving revision 1.5
> diff -u -p -r1.5 iobuf.h
> --- iobuf.h   12 Jun 2019 17:42:53 -0000      1.5
> +++ iobuf.h   25 Jan 2021 11:14:33 -0000
> @@ -35,11 +35,12 @@ struct iobuf {
>       struct ioqbuf   *outqlast;
> };
> 
> +struct tls;
> +
> #define IOBUF_WANT_READ               -1
> #define IOBUF_WANT_WRITE      -2
> #define IOBUF_CLOSED          -3
> #define IOBUF_ERROR           -4
> -#define IOBUF_TLSERROR               -5
> 
> int   iobuf_init(struct iobuf *, size_t, size_t);
> void  iobuf_clear(struct iobuf *);
> @@ -53,7 +54,7 @@ size_t      iobuf_left(struct iobuf *);
> char   *iobuf_data(struct iobuf *);
> char   *iobuf_getline(struct iobuf *, size_t *);
> ssize_t       iobuf_read(struct iobuf *, int);
> -ssize_t      iobuf_read_tls(struct iobuf *, void *);
> +ssize_t      iobuf_read_tls(struct iobuf *, struct tls *);
> 
> size_t  iobuf_queued(struct iobuf *);
> void*   iobuf_reserve(struct iobuf *, size_t);
> @@ -62,6 +63,6 @@ int iobuf_queuev(struct iobuf *, const s
> int   iobuf_fqueue(struct iobuf *, const char *, ...);
> int   iobuf_vfqueue(struct iobuf *, const char *, va_list);
> int   iobuf_flush(struct iobuf *, int);
> -int  iobuf_flush_tls(struct iobuf *, void *);
> +int  iobuf_flush_tls(struct iobuf *, struct tls *);
> ssize_t       iobuf_write(struct iobuf *, int);
> -ssize_t      iobuf_write_tls(struct iobuf *, void *);
> +ssize_t      iobuf_write_tls(struct iobuf *, struct tls *);
> Index: ioev.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/ioev.c,v
> retrieving revision 1.43
> diff -u -p -r1.43 ioev.c
> --- ioev.c    23 Jan 2021 16:11:11 -0000      1.43
> +++ ioev.c    25 Jan 2021 11:16:47 -0000
> @@ -27,16 +27,14 @@
> #include <stdlib.h>
> #include <string.h>
> #include <stdio.h>
> +#ifdef IO_TLS
> +#include <tls.h>
> +#endif
> #include <unistd.h>
> 
> #include "ioev.h"
> #include "iobuf.h"
> 
> -#ifdef IO_TLS
> -#include <openssl/err.h>
> -#include <openssl/ssl.h>
> -#endif
> -
> enum {
>       IO_STATE_NONE,
>       IO_STATE_CONNECT,
> @@ -65,7 +63,9 @@ struct io {
>       int              flags;
>       int              state;
>       struct event     ev;
> -     void            *tls;
> +     struct tls      *tls;
> +     char            *name;
> +
>       const char      *error; /* only valid immediately on callback */
> };
> 
> @@ -85,9 +85,7 @@ void        io_frame_enter(const char *, struct
> void  io_frame_leave(struct io *);
> 
> #ifdef IO_TLS
> -void ssl_error(const char *); /* XXX external */
> -
> -static const char* io_tls_error(void);
> +void io_dispatch_handshake_tls(int, short, void *);
> void  io_dispatch_accept_tls(int, short, void *);
> void  io_dispatch_connect_tls(int, short, void *);
> void  io_dispatch_read_tls(int, short, void *);
> @@ -111,10 +109,9 @@ io_strio(struct io *io)
>       ssl[0] = '\0';
> #ifdef IO_TLS
>       if (io->tls) {
> -             (void)snprintf(ssl, sizeof ssl, " tls=%s:%s:%d",
> -                 SSL_get_version(io->tls),
> -                 SSL_get_cipher_name(io->tls),
> -                 SSL_get_cipher_bits(io->tls, NULL));
> +             (void)snprintf(ssl, sizeof ssl, " tls=%s:%s",
> +                 tls_conn_version(io->tls),
> +                 tls_conn_cipher(io->tls));
>       }
> #endif
> 
> @@ -272,7 +269,7 @@ io_free(struct io *io)
>               current = NULL;
> 
> #ifdef IO_TLS
> -     SSL_free(io->tls);
> +     tls_free(io->tls);
>       io->tls = NULL;
> #endif
> 
> @@ -283,6 +280,7 @@ io_free(struct io *io)
>               io->sock = -1;
>       }
> 
> +     free(io->name);
>       iobuf_clear(&io->iobuf);
>       free(io);
> }
> @@ -397,7 +395,7 @@ io_error(struct io *io)
>       return io->error;
> }
> 
> -void *
> +struct tls *
> io_tls(struct io *io)
> {
>       return io->tls;
> @@ -807,57 +805,85 @@ io_dispatch_connect(int fd, short ev, vo
> }
> 
> #ifdef IO_TLS
> -
> -static const char*
> -io_tls_error(void)
> +int
> +io_connect_tls(struct io *io, struct tls *tls, const char *hostname)
> {
> -     static char     buf[128];
> -     unsigned long   e;
> +     int     mode;
> +
> +     mode = io->flags & IO_RW;
> +     if (mode != IO_WRITE)
> +             errx(1, "io_connect_tls: expect IO_WRITE mode");
> +
> +     if (io->tls)
> +             errx(1, "io_connect_tls: TLS already started");
> 
> -     e = ERR_peek_last_error();
> -     if (e) {
> -             ERR_error_string(e, buf);
> -             return (buf);
> +     if (hostname) {
> +             if ((io->name = strdup(hostname)) == NULL)
> +                     err(1, "io_connect_tls");
>       }
> 
> -     return ("No TLS error");
> +     io->tls = tls;
> +     io->state = IO_STATE_CONNECT_TLS;
> +     io_reset(io, EV_WRITE, io_dispatch_connect_tls);
> +
> +     return (0);
> }
> 
> int
> -io_start_tls(struct io *io, void *tls)
> +io_accept_tls(struct io *io, struct tls *tls)
> {
>       int     mode;
> 
>       mode = io->flags & IO_RW;
> -     if (mode == 0 || mode == IO_RW)
> -             errx(1, "io_start_tls(): full-duplex or unset");
> +     if (mode != IO_READ)
> +             errx(1, "io_connect_tls: expect IO_READ mode");
> 
>       if (io->tls)
>               errx(1, "io_start_tls(): TLS already started");
>       io->tls = tls;
> +     io->state = IO_STATE_ACCEPT_TLS;
> +     io_reset(io, EV_READ, io_dispatch_accept_tls);
> +
> +     return (0);
> +}
> 
> -     if (SSL_set_fd(io->tls, io->sock) == 0) {
> -             ssl_error("io_start_tls:SSL_set_fd");
> -             return (-1);
> +void
> +io_dispatch_handshake_tls(int fd, short event, void *humppa)
> +{
> +     struct io       *io = humppa;
> +     int             ret;
> +
> +     io_frame_enter("io_dispatch_handshake_tls", io, event);
> +
> +     if (event == EV_TIMEOUT) {
> +             io_callback(io, IO_TIMEOUT);
> +             goto leave;
>       }
> 
> -     if (mode == IO_WRITE) {
> -             io->state = IO_STATE_CONNECT_TLS;
> -             SSL_set_connect_state(io->tls);
> -             io_reset(io, EV_WRITE, io_dispatch_connect_tls);
> -     } else {
> -             io->state = IO_STATE_ACCEPT_TLS;
> -             SSL_set_accept_state(io->tls);
> -             io_reset(io, EV_READ, io_dispatch_accept_tls);
> +     if ((ret = tls_handshake(io->tls)) == 0) {
> +             io->state = IO_STATE_UP;
> +             io_callback(io, IO_TLSREADY);
> +             goto leave;
> +     }
> +     if (ret == TLS_WANT_POLLIN)
> +             io_reset(io, EV_READ, io_dispatch_handshake_tls);
> +     else if (ret == TLS_WANT_POLLOUT)
> +             io_reset(io, EV_WRITE, io_dispatch_handshake_tls);
> +     else {
> +             io->error = tls_error(io->tls);
> +             io_callback(io, IO_ERROR);
>       }
> 
> -     return (0);
> + leave:
> +     io_frame_leave(io);
> +     return;
> }
> 
> void
> io_dispatch_accept_tls(int fd, short event, void *humppa)
> {
>       struct io       *io = humppa;
> +     struct tls      *cctx = NULL;
>       int              ret;
> 
>       io_frame_enter("io_dispatch_accept_tls", io, event);
> @@ -867,28 +893,17 @@ io_dispatch_accept_tls(int fd, short eve
>               goto leave;
>       }
> 
> -     if ((ret = SSL_accept(io->tls)) > 0) {
> -             io->state = IO_STATE_UP;
> -             io_callback(io, IO_TLSREADY);
> +     if ((ret = tls_accept_socket(io->tls, &cctx, io->sock)) == 0) {
> +             io->tls = cctx;
> +             io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls);
>               goto leave;
>       }
> +     io->error = tls_error(io->tls);
> +     io_callback(io, IO_ERROR);
> 
> -     switch (SSL_get_error(io->tls, ret)) {
> -     case SSL_ERROR_WANT_READ:
> -             io_reset(io, EV_READ, io_dispatch_accept_tls);
> -             break;
> -     case SSL_ERROR_WANT_WRITE:
> -             io_reset(io, EV_WRITE, io_dispatch_accept_tls);
> -             break;
> -     default:
> -             io->error = io_tls_error();
> -             ssl_error("io_dispatch_accept_tls:SSL_accept");
> -             io_callback(io, IO_ERROR);
> -             break;
> -     }
> -
> -    leave:
> + leave:
>       io_frame_leave(io);
> +     return;
> }
> 
> void
> @@ -904,27 +919,15 @@ io_dispatch_connect_tls(int fd, short ev
>               goto leave;
>       }
> 
> -     if ((ret = SSL_connect(io->tls)) > 0) {
> -             io->state = IO_STATE_UP;
> -             io_callback(io, IO_TLSREADY);
> +     if ((ret = tls_connect_socket(io->tls, io->sock, io->name)) == 0) {
> +             io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls);
>               goto leave;
>       }
> 
> -     switch (SSL_get_error(io->tls, ret)) {
> -     case SSL_ERROR_WANT_READ:
> -             io_reset(io, EV_READ, io_dispatch_connect_tls);
> -             break;
> -     case SSL_ERROR_WANT_WRITE:
> -             io_reset(io, EV_WRITE, io_dispatch_connect_tls);
> -             break;
> -     default:
> -             io->error = io_tls_error();
> -             ssl_error("io_dispatch_connect_ssl:SSL_connect");
> -             io_callback(io, IO_TLSERROR);
> -             break;
> -     }
> +     io->error = tls_error(io->tls);
> +     io_callback(io, IO_ERROR);
> 
> -    leave:
> + leave:
>       io_frame_leave(io);
> }
> 
> @@ -932,7 +935,7 @@ void
> io_dispatch_read_tls(int fd, short event, void *humppa)
> {
>       struct io       *io = humppa;
> -     int              n, saved_errno;
> +     int              n;
> 
>       io_frame_enter("io_dispatch_read_tls", io, event);
> 
> @@ -943,7 +946,7 @@ io_dispatch_read_tls(int fd, short event
> 
> again:
>       iobuf_normalize(&io->iobuf);
> -     switch ((n = iobuf_read_tls(&io->iobuf, (SSL*)io->tls))) {
> +     switch ((n = iobuf_read_tls(&io->iobuf, io->tls))) {
>       case IOBUF_WANT_READ:
>               io_reset(io, EV_READ, io_dispatch_read_tls);
>               break;
> @@ -954,20 +957,13 @@ again:
>               io_callback(io, IO_DISCONNECTED);
>               break;
>       case IOBUF_ERROR:
> -             saved_errno = errno;
> -             io->error = strerror(errno);
> -             errno = saved_errno;
> -             io_callback(io, IO_ERROR);
> -             break;
> -     case IOBUF_TLSERROR:
> -             io->error = io_tls_error();
> -             ssl_error("io_dispatch_read_tls:SSL_read");
> +             io->error = tls_error(io->tls);
>               io_callback(io, IO_ERROR);
>               break;
>       default:
>               io_debug("io_dispatch_read_tls(...) -> r=%d\n", n);
>               io_callback(io, IO_DATAIN);
> -             if (current == io && IO_READING(io) && SSL_pending(io->tls))
> +             if (current == io && IO_READING(io))
>                       goto again;
>       }
> 
> @@ -979,7 +975,7 @@ void
> io_dispatch_write_tls(int fd, short event, void *humppa)
> {
>       struct io       *io = humppa;
> -     int              n, saved_errno;
> +     int              n;
>       size_t           w2, w;
> 
>       io_frame_enter("io_dispatch_write_tls", io, event);
> @@ -990,7 +986,7 @@ io_dispatch_write_tls(int fd, short even
>       }
> 
>       w = io_queued(io);
> -     switch ((n = iobuf_write_tls(&io->iobuf, (SSL*)io->tls))) {
> +     switch ((n = iobuf_write_tls(&io->iobuf, io->tls))) {
>       case IOBUF_WANT_READ:
>               io_reset(io, EV_READ, io_dispatch_write_tls);
>               break;
> @@ -1001,14 +997,7 @@ io_dispatch_write_tls(int fd, short even
>               io_callback(io, IO_DISCONNECTED);
>               break;
>       case IOBUF_ERROR:
> -             saved_errno = errno;
> -             io->error = strerror(errno);
> -             errno = saved_errno;
> -             io_callback(io, IO_ERROR);
> -             break;
> -     case IOBUF_TLSERROR:
> -             io->error = io_tls_error();
> -             ssl_error("io_dispatch_write_tls:SSL_write");
> +             io->error = tls_error(io->tls);
>               io_callback(io, IO_ERROR);
>               break;
>       default:
> Index: ioev.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/ioev.h,v
> retrieving revision 1.18
> diff -u -p -r1.18 ioev.h
> --- ioev.h    11 Sep 2019 04:19:19 -0000      1.18
> +++ ioev.h    18 Jan 2021 19:58:19 -0000
> @@ -18,7 +18,6 @@
> enum {
>       IO_CONNECTED = 0,       /* connection successful        */
>       IO_TLSREADY,            /* TLS started successfully     */
> -     IO_TLSERROR,            /* XXX - needs more work        */
>       IO_DATAIN,              /* new data in input buffer     */
>       IO_LOWAT,               /* output queue running low     */
>       IO_DISCONNECTED,        /* error?                       */
> @@ -30,6 +29,7 @@ enum {
> #define IO_OUT                0x02
> 
> struct io;
> +struct tls;
> 
> void io_set_nonblocking(int);
> void io_set_nolinger(int);
> @@ -46,11 +46,12 @@ void io_pause(struct io *, int);
> void io_resume(struct io *, int);
> void io_reload(struct io *);
> int io_connect(struct io *, const struct sockaddr *, const struct sockaddr *);
> -int io_start_tls(struct io *, void *);
> +int io_connect_tls(struct io *, struct tls *, const char *);
> +int io_accept_tls(struct io *, struct tls *);
> const char* io_strio(struct io *);
> const char* io_strevent(int);
> const char* io_error(struct io *);
> -void* io_tls(struct io *);
> +struct tls* io_tls(struct io *);
> int io_fileno(struct io *);
> int io_paused(struct io *, int);
> 
> Index: mta.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/mta.c,v
> retrieving revision 1.234
> diff -u -p -r1.234 mta.c
> --- mta.c     21 Dec 2019 10:34:07 -0000      1.234
> +++ mta.c     22 Jan 2021 09:00:21 -0000
> @@ -38,10 +38,12 @@
> #include <stdlib.h>
> #include <string.h>
> #include <time.h>
> +#include <tls.h>
> #include <unistd.h>
> 
> #include "smtpd.h"
> #include "log.h"
> +#include "ssl.h"
> 
> #define MAXERROR_PER_ROUTE    4
> 
> @@ -57,6 +59,7 @@
> #define RELAY_ONHOLD          0x01
> #define RELAY_HOLDQ           0x02
> 
> +static void mta_setup_dispatcher(struct dispatcher *);
> static void mta_handle_envelope(struct envelope *, const char *);
> static void mta_query_smarthost(struct envelope *);
> static void mta_on_smarthost(struct envelope *, const char *);
> @@ -138,6 +141,12 @@ int mta_is_blocked(struct mta_source *, 
> static int mta_block_cmp(const struct mta_block *, const struct mta_block *);
> SPLAY_PROTOTYPE(mta_block_tree, mta_block, entry, mta_block_cmp);
> 
> +/*
> + * This function is not publicy exported because it is a hack until libtls
> + * has a proper privsep setup
> + */
> +void tls_config_use_fake_private_key(struct tls_config *config);
> +
> static struct mta_relay_tree          relays;
> static struct mta_domain_tree         domains;
> static struct mta_host_tree           hosts;
> @@ -463,6 +472,70 @@ mta_imsg(struct mproc *p, struct imsg *i
> void
> mta_postfork(void)
> {
> +     struct dispatcher *dispatcher;
> +     const char *key;
> +     void *iter;
> +
> +     iter = NULL;
> +     while (dict_iter(env->sc_dispatchers, &iter, &key, (void 
> **)&dispatcher)) {
> +             log_debug("%s: %s", __func__, key);
> +             mta_setup_dispatcher(dispatcher);
> +     }
> +}
> +
> +static void
> +mta_setup_dispatcher(struct dispatcher *dispatcher)
> +{
> +     struct dispatcher_remote *remote;
> +     static const char *dheparams[] = { "none", "auto", "legacy" };
> +     struct tls_config *config;
> +     struct pki *pki;
> +     struct ca *ca;
> +
> +     if (dispatcher->type != DISPATCHER_REMOTE)
> +             return;
> +
> +     remote = &dispatcher->u.remote;
> +
> +     if ((config = tls_config_new()) == NULL)
> +             fatal("smtpd: tls_config_new");
> +
> +     if (env->sc_tls_ciphers) {
> +             if (tls_config_set_ciphers(config, env->sc_tls_ciphers) == -1)
> +                     err(1, "%s", tls_config_error(config));
> +     }
> +
> +     if (remote->pki) {
> +             pki = dict_get(env->sc_pki_dict, remote->pki);
> +             if (pki == NULL)
> +                     err(1, "client pki \"%s\" not found ", remote->pki);
> +
> +             tls_config_set_dheparams(config, dheparams[pki->pki_dhe]);
> +             tls_config_use_fake_private_key(config);
> +             if (tls_config_set_keypair_mem(config, pki->pki_cert,
> +                 pki->pki_cert_len, NULL, 0) == -1)
> +             fatal("tls_config_set_keypair_mem");
> +     }
> +
> +     if (remote->ca) {
> +             ca = dict_get(env->sc_ca_dict, remote->ca);
> +             if (tls_config_set_ca_mem(config, ca->ca_cert, ca->ca_cert_len)
> +                 == -1)
> +                     fatal("tls_config_set_ca_mem");
> +     }
> +     else if (tls_config_set_ca_file(config, tls_default_ca_cert_file())
> +         == -1)
> +             fatal("tls_config_set_ca_file");
> +
> +     if (remote->tls_noverify) {
> +             tls_config_insecure_noverifycert(config);
> +             tls_config_insecure_noverifyname(config);
> +             tls_config_insecure_noverifytime(config);
> +     }
> +     else
> +             tls_config_verify(config);
> +
> +     remote->tls_config = config;
> }
> 
> void
> Index: mta_session.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/mta_session.c,v
> retrieving revision 1.138
> diff -u -p -r1.138 mta_session.c
> --- mta_session.c     21 Dec 2020 11:44:07 -0000      1.138
> +++ mta_session.c     19 Jan 2021 10:09:32 -0000
> @@ -43,6 +43,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <time.h>
> +#include <tls.h>
> #include <unistd.h>
> 
> #include "smtpd.h"
> @@ -153,11 +154,8 @@ static void mta_send(struct mta_session 
> static ssize_t mta_queue_data(struct mta_session *);
> static void mta_response(struct mta_session *, char *);
> static const char * mta_strstate(int);
> -static void mta_cert_init(struct mta_session *);
> -static void mta_cert_init_cb(void *, int, const char *, const void *, 
> size_t);
> -static void mta_cert_verify(struct mta_session *);
> -static void mta_cert_verify_cb(void *, int);
> -static void mta_tls_verified(struct mta_session *);
> +static void mta_tls_init(struct mta_session *);
> +static void mta_tls_started(struct mta_session *);
> static struct mta_session *mta_tree_pop(struct tree *, uint64_t);
> static const char * dsn_strret(enum dsn_ret);
> static const char * dsn_strnotify(uint8_t);
> @@ -974,7 +972,7 @@ mta_response(struct mta_session *s, char
>                       return;
>               }
> 
> -             mta_cert_init(s);
> +             mta_tls_init(s);
>               break;
> 
>       case MTA_AUTH_PLAIN:
> @@ -1229,7 +1227,7 @@ mta_io(struct io *io, int evt, void *arg
> 
>               if (s->use_smtps) {
>                       io_set_write(io);
> -                     mta_cert_init(s);
> +                     mta_tls_init(s);
>               }
>               else {
>                       mta_enter_state(s, MTA_BANNER);
> @@ -1239,13 +1237,14 @@ mta_io(struct io *io, int evt, void *arg
> 
>       case IO_TLSREADY:
>               log_info("%016"PRIx64" mta tls ciphers=%s",
> -                 s->id, ssl_to_text(io_tls(s->io)));
> +                 s->id, tls_to_text(io_tls(s->io)));
>               s->flags |= MTA_TLS;
> +             if (!s->relay->dispatcher->u.remote.tls_noverify)
> +                     s->flags |= MTA_TLS_VERIFIED;
> 
> +             mta_tls_started(s);
>               mta_report_link_tls(s,
> -                 ssl_to_text(io_tls(s->io)));
> -
> -             mta_cert_verify(s);
> +                 tls_to_text(io_tls(s->io)));
>               break;
> 
>       case IO_DATAIN:
> @@ -1378,7 +1377,6 @@ mta_io(struct io *io, int evt, void *arg
>               break;
> 
>       case IO_ERROR:
> -     case IO_TLSERROR:
>               log_debug("debug: mta: %p: IO error: %s", s, io_error(io));
> 
>               if (s->state == MTA_STARTTLS && s->use_smtp_tls) {
> @@ -1579,152 +1577,42 @@ mta_error(struct mta_session *s, const c
> }
> 
> static void
> -mta_cert_init(struct mta_session *s)
> -{
> -     const char *name;
> -     int fallback;
> -
> -     if (s->relay->pki_name) {
> -             name = s->relay->pki_name;
> -             fallback = 0;
> -     }
> -     else {
> -             name = s->helo;
> -             fallback = 1;
> -     }
> -
> -     if (cert_init(name, fallback, mta_cert_init_cb, s)) {
> -             tree_xset(&wait_tls_init, s->id, s);
> -             s->flags |= MTA_WAIT;
> -     }
> -}
> -
> -static void
> -mta_cert_init_cb(void *arg, int status, const char *name, const void *cert,
> -    size_t cert_len)
> +mta_tls_init(struct mta_session *s)
> {
> -     struct mta_session *s = arg;
> -     void *ssl;
> -     char *xname = NULL, *xcert = NULL;
> -     union {
> -             struct in_addr in4;
> -             struct in6_addr in6;
> -     } addrbuf;
> -
> -     if (s->flags & MTA_WAIT)
> -             mta_tree_pop(&wait_tls_init, s->id);
> +     struct tls_config *tls_config;
> +     struct tls *tls;
> 
> -     if (status == CA_FAIL && s->relay->pki_name) {
> -             log_info("%016"PRIx64" mta closing reason=ca-failure", s->id);
> +     if ((tls = tls_client()) == NULL) {
> +             log_info("%016"PRIx64" mta closing reason=tls-failure", s->id);
>               mta_free(s);
>               return;
>       }
> 
> -     if (name)
> -             xname = xstrdup(name);
> -     if (cert)
> -             xcert = xmemdup(cert, cert_len);
> -     ssl = ssl_mta_init(xname, xcert, cert_len, env->sc_tls_ciphers);
> -     free(xname);
> -     free(xcert);
> -     if (ssl == NULL)
> -             fatal("mta: ssl_mta_init");
> -
> -     /*
> -      * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not
> -      * permitted in "HostName".
> -      */
> -     if (s->relay->domain->as_host == 1) {
> -             if (inet_pton(AF_INET, s->relay->domain->name, &addrbuf) != 1 &&
> -                 inet_pton(AF_INET6, s->relay->domain->name, &addrbuf) != 1) 
> {
> -                     log_debug("%016"PRIx64" mta tls setting SNI name=%s",
> -                         s->id, s->relay->domain->name);
> -                     if (SSL_set_tlsext_host_name(ssl, 
> s->relay->domain->name) == 0)
> -                             log_warnx("%016"PRIx64" mta tls setting SNI 
> failed",
> -                                s->id);
> -             }
> -     }
> -
> -     io_start_tls(s->io, ssl);
> -}
> -
> -static void
> -mta_cert_verify(struct mta_session *s)
> -{
> -     const char *name;
> -     int fallback;
> -
> -     if (s->relay->ca_name) {
> -             name = s->relay->ca_name;
> -             fallback = 0;
> -     }
> -     else {
> -             name = s->helo;
> -             fallback = 1;
> -     }
> -
> -     if (cert_verify(io_tls(s->io), name, fallback, mta_cert_verify_cb, s)) {
> -             tree_xset(&wait_tls_verify, s->id, s);
> -             io_pause(s->io, IO_IN);
> -             s->flags |= MTA_WAIT;
> -     }
> -}
> -
> -static void
> -mta_cert_verify_cb(void *arg, int status)
> -{
> -     struct mta_session *s = arg;
> -     int match, resume = 0;
> -     X509 *cert;
> -
> -     if (s->flags & MTA_WAIT) {
> -             mta_tree_pop(&wait_tls_verify, s->id);
> -             resume = 1;
> -     }
> -
> -     if (status == CERT_OK) {
> -             cert = SSL_get_peer_certificate(io_tls(s->io));
> -             if (!cert)
> -                     status = CERT_NOCERT;
> -             else {
> -                     match = 0;
> -                     (void)ssl_check_name(cert, s->mxname, &match);
> -                     X509_free(cert);
> -                     if (!match) {
> -                             log_info("%016"PRIx64" mta "
> -                                 "ssl_check_name: no match for '%s' in cert",
> -                                 s->id, s->mxname);
> -                             status = CERT_INVALID;
> -                     }
> -             }
> -     }
> -
> -     if (status == CERT_OK)
> -             s->flags |= MTA_TLS_VERIFIED;
> -     else if (s->relay->flags & RELAY_TLS_VERIFY) {
> -             errno = 0;
> -             mta_error(s, "SSL certificate check failed");
> +     tls_config = s->relay->dispatcher->u.remote.tls_config;
> +     if (tls_configure(tls, tls_config) == -1) {
> +             log_info("%016"PRIx64" mta closing reason=tls-failure", s->id);
> +             tls_free(tls);
>               mta_free(s);
>               return;
>       }
> 
> -     mta_tls_verified(s);
> -     if (resume)
> -             io_resume(s->io, IO_IN);
> +     io_connect_tls(s->io, tls, s->route->dst->ptrname);
> }
> 
> static void
> -mta_tls_verified(struct mta_session *s)
> +mta_tls_started(struct mta_session *s)
> {
> -     X509 *x;
> -
> -     x = SSL_get_peer_certificate(io_tls(s->io));
> -     if (x) {
> -       log_info("%016"PRIx64" mta "
> -                "server-cert-check result=\"%s\"",
> -                s->id,
> -                (s->flags & MTA_TLS_VERIFIED) ? "success" : "failure");
> -             X509_free(x);
> +     if (tls_peer_cert_provided(io_tls(s->io))) {
> +             log_info("%016"PRIx64" mta "
> +                 "cert-check result=\"%s\" fingerprint=\"%s\"",
> +                 s->id,
> +                 (s->flags & MTA_TLS_VERIFIED) ? "valid" : "unverified",
> +                 tls_peer_cert_hash(io_tls(s->io)));
> +     }
> +     else {
> +             log_info("%016"PRIx64" smtp "
> +                 "cert-check result=\"no certificate presented\"",
> +                 s->id);
>       }
> 
>       if (s->use_smtps) {
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
> retrieving revision 1.284
> diff -u -p -r1.284 parse.y
> --- parse.y   23 Jan 2021 16:11:11 -0000      1.284
> +++ parse.y   25 Jan 2021 07:19:15 -0000
> @@ -128,13 +128,15 @@ enum listen_options {
>       LO_PROXY        = 0x008000,
> };
> 
> +#define PKI_MAX      32
> static struct listen_opts {
>       char           *ifx;
>       int             family;
>       in_port_t       port;
>       uint16_t        ssl;
>       char           *filtername;
> -     char           *pki;
> +     char           *pki[PKI_MAX];
> +     int             pkicount;
>       char           *ca;
>       uint16_t        auth;
>       struct table   *authtable;
> @@ -2316,12 +2318,11 @@ opt_if_listen : INET4 {
>                       listen_opts.ssl = 
> F_STARTTLS|F_STARTTLS_REQUIRE|F_TLS_VERIFY;
>               }
>               | PKI STRING                    {
> -                     if (listen_opts.options & LO_PKI) {
> -                             yyerror("pki already specified");
> +                     if (listen_opts.pkicount == PKI_MAX) {
> +                             yyerror("too many pki specified");
>                               YYERROR;
>                       }
> -                     listen_opts.options |= LO_PKI;
> -                     listen_opts.pki = $2;
> +                     listen_opts.pki[listen_opts.pkicount++] = $2;
>               }
>               | CA STRING                     {
>                       if (listen_opts.options & LO_CA) {
> @@ -3221,8 +3222,10 @@ create_if_listener(struct listen_opts *l
>       if (lo->auth != 0 && !lo->ssl)
>               errx(1, "invalid listen option: auth requires tls/smtps");
> 
> -     if (lo->pki && !lo->ssl)
> +     if (lo->pkicount && !lo->ssl)
>               errx(1, "invalid listen option: pki requires tls/smtps");
> +     if (lo->pkicount == 0 && lo->ssl)
> +             errx(1, "invalid listen option: pki required for tls/smtps");
> 
>       flags = lo->flags;
> 
> @@ -3259,6 +3262,8 @@ create_if_listener(struct listen_opts *l
> static void
> config_listener(struct listener *h,  struct listen_opts *lo)
> {
> +     int i;
> +
>       h->fd = -1;
>       h->port = lo->port;
>       h->flags = lo->flags;
> @@ -3273,17 +3278,19 @@ config_listener(struct listener *h,  str
>                   sizeof(h->filter_name));
>       }
> 
> -     h->pki_name[0] = '\0';
> -
>       if (lo->authtable != NULL)
>               (void)strlcpy(h->authtable, lo->authtable->t_name, 
> sizeof(h->authtable));
> -     if (lo->pki != NULL) {
> -             if (!lowercase(h->pki_name, lo->pki, sizeof(h->pki_name))) {
> -                     log_warnx("pki name too long: %s", lo->pki);
> -                     fatalx(NULL);
> -             }
> -             if (dict_get(conf->sc_pki_dict, h->pki_name) == NULL) {
> -                     log_warnx("pki name not found: %s", lo->pki);
> +
> +     h->pkicount = lo->pkicount;
> +     if (h->pkicount) {
> +             h->pki = calloc(h->pkicount, sizeof(*h->pki));
> +             if (h->pki == NULL)
> +                     fatal("calloc");
> +     }
> +     for (i = 0; i < lo->pkicount; i++) {
> +             h->pki[i] = dict_get(conf->sc_pki_dict, lo->pki[i]);
> +             if (h->pki[i] == NULL) {
> +                     log_warnx("pki name not found: %s", lo->pki[i]);
>                       fatalx(NULL);
>               }
>       }
> Index: smtp.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtp.c,v
> retrieving revision 1.166
> diff -u -p -r1.166 smtp.c
> --- smtp.c    10 Aug 2019 16:07:01 -0000      1.166
> +++ smtp.c    22 Jan 2021 09:00:46 -0000
> @@ -34,6 +34,7 @@
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> +#include <tls.h>
> #include <unistd.h>
> 
> #include <openssl/ssl.h>
> @@ -50,7 +51,7 @@ static void smtp_dropped(struct listener
> static int smtp_enqueue(void);
> static int smtp_can_accept(void);
> static void smtp_setup_listeners(void);
> -static int smtp_sni_callback(SSL *, int *, void *);
> +static void smtp_setup_listener_tls(struct listener *);
> 
> int
> proxy_session(struct listener *listener, int sock,
> @@ -62,6 +63,11 @@ proxy_session(struct listener *listener,
> 
> static void smtp_accepted(struct listener *, int, const struct 
> sockaddr_storage *, struct io *);
> 
> +/*
> + * This function are not publicy exported because it is a hack until libtls
> + * has a proper privsep setup
> + */
> +void tls_config_use_fake_private_key(struct tls_config *config);
> 
> #define       SMTP_FD_RESERVE 5
> static size_t sessions;
> @@ -145,6 +151,10 @@ smtp_setup_listeners(void)
>                       }
>                       fatal("smtpd: socket");
>               }
> +
> +             if (l->flags & F_SSL)
> +                     smtp_setup_listener_tls(l);
> +
>               opt = 1;
>               if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt,
>                   sizeof(opt)) == -1)
> @@ -155,19 +165,77 @@ smtp_setup_listeners(void)
> }
> 
> static void
> +smtp_setup_listener_tls(struct listener *l)
> +{
> +     static const char *dheparams[] = { "none", "auto", "legacy" };
> +     struct tls_config *config;
> +     struct pki *pki;
> +     struct ca *ca;
> +     int i;
> +
> +     if ((config = tls_config_new()) == NULL)
> +             fatal("smtpd: tls_config_new");
> +
> +     if (env->sc_tls_ciphers &&
> +         tls_config_set_ciphers(config, env->sc_tls_ciphers) == -1)
> +                     err(1, "%s", tls_config_error(config));
> +
> +     pki = l->pki[0];
> +     if (pki == NULL)
> +             fatal("no pki defined");
> +
> +     if (tls_config_set_dheparams(config, dheparams[pki->pki_dhe]) == -1)
> +             fatal("tls_config_set_dheparams");
> +
> +     tls_config_use_fake_private_key(config);
> +     for (i = 0; i < l->pkicount; i++) {
> +             pki = l->pki[i];
> +             if (i == 0) {
> +                     if (tls_config_set_keypair_mem(config, pki->pki_cert,
> +                         pki->pki_cert_len, NULL, 0) == -1)
> +                             fatal("tls_config_set_keypair_mem");
> +             } else {
> +                     if (tls_config_add_keypair_mem(config, pki->pki_cert,
> +                         pki->pki_cert_len, NULL, 0) == -1)
> +                             fatal("tls_config_add_keypair_mem");
> +             }
> +     }
> +     free(l->pki);
> +     l->pkicount = 0;
> +
> +     if (l->ca_name[0]) {
> +             ca = dict_get(env->sc_ca_dict, l->ca_name);
> +             if (tls_config_set_ca_mem(config, ca->ca_cert, ca->ca_cert_len)
> +                 == -1)
> +                     fatal("tls_config_set_ca_mem");
> +     }
> +     else if (tls_config_set_ca_file(config, tls_default_ca_cert_file())
> +         == -1)
> +             fatal("tls_config_set_ca_file");
> +
> +     if (l->flags & F_TLS_VERIFY)
> +             tls_config_verify_client(config);
> +     else
> +             tls_config_verify_client_optional(config);
> +
> +     l->tls = tls_server();
> +     if (l->tls == NULL)
> +             fatal("tls_server");
> +     if (tls_configure(l->tls, config) == -1) {
> +             fatal("tls_configure: %s", tls_error(l->tls));
> +     }
> +     tls_config_free(config);
> +}
> +
> +
> +static void
> smtp_setup_events(void)
> {
>       struct listener *l;
> -     struct pki      *pki;
> -     SSL_CTX         *ssl_ctx;
> -     void            *iter;
> -     const char      *k;
> 
>       TAILQ_FOREACH(l, env->sc_listeners, entry) {
> -             log_debug("debug: smtp: listen on %s port %d flags 0x%01x"
> -                 " pki \"%s\""
> -                 " ca \"%s\"", ss_to_text(&l->ss), ntohs(l->port),
> -                 l->flags, l->pki_name, l->ca_name);
> +             log_debug("debug: smtp: listen on %s port %d flags 0x%01x",
> +                 ss_to_text(&l->ss), ntohs(l->port), l->flags);
> 
>               io_set_nonblocking(l->fd);
>               if (listen(l->fd, SMTPD_BACKLOG) == -1)
> @@ -178,14 +246,6 @@ smtp_setup_events(void)
>                       event_add(&l->ev, NULL);
>       }
> 
> -     iter = NULL;
> -     while (dict_iter(env->sc_pki_dict, &iter, &k, (void **)&pki)) {
> -             if (!ssl_setup((SSL_CTX **)&ssl_ctx, pki, smtp_sni_callback,
> -                     env->sc_tls_ciphers))
> -                     fatal("smtp_setup_events: ssl_setup failure");
> -             dict_xset(env->sc_ssl_dict, k, ssl_ctx);
> -     }
> -
>       purge_config(PURGE_PKI_KEYS);
> 
>       maxsessions = (getdtablesize() - getdtablecount()) / 2 - 
> SMTP_FD_RESERVE;
> @@ -317,22 +377,6 @@ smtp_collect(void)
>               env->sc_flags &= ~SMTPD_SMTP_DISABLED;
>               smtp_resume();
>       }
> -}
> -
> -static int
> -smtp_sni_callback(SSL *ssl, int *ad, void *arg)
> -{
> -     const char              *sn;
> -     void                    *ssl_ctx;
> -
> -     sn = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
> -     if (sn == NULL)
> -             return SSL_TLSEXT_ERR_NOACK;
> -     ssl_ctx = dict_get(env->sc_ssl_dict, sn);
> -     if (ssl_ctx == NULL)
> -             return SSL_TLSEXT_ERR_NOACK;
> -     SSL_set_SSL_CTX(ssl, ssl_ctx);
> -     return SSL_TLSEXT_ERR_OK;
> }
> 
> static void
> Index: smtp.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtp.h,v
> retrieving revision 1.3
> diff -u -p -r1.3 smtp.h
> --- smtp.h    2 Sep 2019 20:05:21 -0000       1.3
> +++ smtp.h    19 Jan 2021 09:41:16 -0000
> @@ -46,6 +46,7 @@ struct smtp_params {
>       /* TLS options */
>       int                      tls_req;       /* requested TLS mode */
>       int                      tls_verify;    /* need valid server 
> certificate */
> +     const char              *tls_servname;  /* SNI */
> 
>       /* SMTP options */
>       int                      lmtp;          /* use LMTP protocol */
> Index: smtp_client.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtp_client.c,v
> retrieving revision 1.14
> diff -u -p -r1.14 smtp_client.c
> --- smtp_client.c     24 Apr 2020 11:34:07 -0000      1.14
> +++ smtp_client.c     19 Jan 2021 09:44:34 -0000
> @@ -187,7 +187,7 @@ smtp_cert_verified(struct smtp_client *p
> void
> smtp_set_tls(struct smtp_client *proto, void *ctx)
> {
> -     io_start_tls(proto->io, ctx);
> +     io_connect_tls(proto->io, ctx, proto->params.tls_servname);
> }
> 
> void
> @@ -624,8 +624,13 @@ smtp_client_io(struct io *io, int evt, v
> 
>       case IO_TLSREADY:
>               proto->flags |= FLAG_TLS;
> -             io_pause(proto->io, IO_IN);
> -             smtp_verify_server_cert(proto->tag, proto, io_tls(proto->io));
> +             if (proto->state == STATE_INIT)
> +                     smtp_client_state(proto, STATE_BANNER);
> +             else {
> +                     /* Clear extensions before re-issueing an EHLO command. 
> */
> +                     proto->ext = 0;
> +                     smtp_client_state(proto, STATE_EHLO);
> +             }
>               break;
> 
>       case IO_DATAIN:
> @@ -646,10 +651,6 @@ smtp_client_io(struct io *io, int evt, v
>               break;
> 
>       case IO_ERROR:
> -             smtp_client_abort(proto, FAIL_CONN, io_error(io));
> -             break;
> -
> -     case IO_TLSERROR:
>               smtp_client_abort(proto, FAIL_CONN, io_error(io));
>               break;
> 
> Index: smtp_session.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtp_session.c,v
> retrieving revision 1.428
> diff -u -p -r1.428 smtp_session.c
> --- smtp_session.c    21 Dec 2020 11:44:07 -0000      1.428
> +++ smtp_session.c    19 Jan 2021 11:06:22 -0000
> @@ -38,6 +38,7 @@
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> +#include <tls.h>
> #include <unistd.h>
> #include <vis.h>
> 
> @@ -184,7 +185,8 @@ static void smtp_getnameinfo_cb(void *, 
> static void smtp_getaddrinfo_cb(void *, int, struct addrinfo *);
> static void smtp_connected(struct smtp_session *);
> static void smtp_send_banner(struct smtp_session *);
> -static void smtp_tls_verified(struct smtp_session *);
> +static void smtp_tls_init(struct smtp_session *);
> +static void smtp_tls_started(struct smtp_session *);
> static void smtp_io(struct io *, int, void *);
> static void smtp_enter_state(struct smtp_session *, int);
> static void smtp_reply(struct smtp_session *, char *, ...);
> @@ -193,10 +195,6 @@ static void smtp_rfc4954_auth_plain(stru
> static void smtp_rfc4954_auth_login(struct smtp_session *, char *);
> static void smtp_free(struct smtp_session *, const char *);
> static const char *smtp_strstate(int);
> -static void smtp_cert_init(struct smtp_session *);
> -static void smtp_cert_init_cb(void *, int, const char *, const void *, 
> size_t);
> -static void smtp_cert_verify(struct smtp_session *);
> -static void smtp_cert_verify_cb(void *, int);
> static void smtp_auth_failure_pause(struct smtp_session *);
> static void smtp_auth_failure_resume(int, short, void *);
> 
> @@ -1066,17 +1064,26 @@ smtp_session_imsg(struct mproc *p, struc
> }
> 
> static void
> -smtp_tls_verified(struct smtp_session *s)
> +smtp_tls_init(struct smtp_session *s)
> {
> -     X509 *x;
> +     io_set_read(s->io);
> +     io_accept_tls(s->io, s->listener->tls);
> +}
> 
> -     x = SSL_get_peer_certificate(io_tls(s->io));
> -     if (x) {
> +static void
> +smtp_tls_started(struct smtp_session *s)
> +{
> +     if (tls_peer_cert_provided(io_tls(s->io))) {
>               log_info("%016"PRIx64" smtp "
> -                 "client-cert-check result=\"%s\"",
> +                 "cert-check result=\"%s\" fingerprint=\"%s\"",
>                   s->id,
> -                 (s->flags & SF_VERIFIED) ? "success" : "failure");
> -             X509_free(x);
> +                 (s->flags & SF_VERIFIED) ? "verified" : "unchecked",
> +                 tls_peer_cert_hash(io_tls(s->io)));
> +     }
> +     else {
> +             log_info("%016"PRIx64" smtp "
> +                 "cert-check result=\"no certificate presented\"",
> +                 s->id);
>       }
> 
>       if (s->listener->flags & F_SMTPS) {
> @@ -1105,14 +1112,16 @@ smtp_io(struct io *io, int evt, void *ar
> 
>       case IO_TLSREADY:
>               log_info("%016"PRIx64" smtp tls ciphers=%s",
> -                 s->id, ssl_to_text(io_tls(s->io)));
> +                 s->id, tls_to_text(io_tls(s->io)));
> 
> -             smtp_report_link_tls(s, ssl_to_text(io_tls(s->io)));
> +             smtp_report_link_tls(s, tls_to_text(io_tls(s->io)));
> 
>               s->flags |= SF_SECURE;
> +             if (s->listener->flags & F_TLS_VERIFY)
> +                     s->flags |= SF_VERIFIED;
>               s->helo[0] = '\0';
> 
> -             smtp_cert_verify(s);
> +             smtp_tls_started(s);
>               break;
> 
>       case IO_DATAIN:
> @@ -1193,7 +1202,7 @@ smtp_io(struct io *io, int evt, void *ar
> 
>               /* Wait for the client to start tls */
>               if (s->state == STATE_TLS) {
> -                     smtp_cert_init(s);
> +                     smtp_tls_init(s);
>                       break;
>               }
> 
> @@ -2071,7 +2080,7 @@ static void
> smtp_proceed_connected(struct smtp_session *s)
> {
>       if (s->listener->flags & F_SMTPS)
> -             smtp_cert_init(s);
> +             smtp_tls_init(s);
>       else
>               smtp_send_banner(s);
> }
> @@ -2261,112 +2270,6 @@ smtp_mailaddr(struct mailaddr *maddr, ch
> }
> 
> static void
> -smtp_cert_init(struct smtp_session *s)
> -{
> -     const char *name;
> -     int fallback;
> -
> -     if (s->listener->pki_name[0]) {
> -             name = s->listener->pki_name;
> -             fallback = 0;
> -     }
> -     else {
> -             name = s->smtpname;
> -             fallback = 1;
> -     }
> -
> -     if (cert_init(name, fallback, smtp_cert_init_cb, s))
> -             tree_xset(&wait_ssl_init, s->id, s);
> -}
> -
> -static void
> -smtp_cert_init_cb(void *arg, int status, const char *name, const void *cert,
> -    size_t cert_len)
> -{
> -     struct smtp_session *s = arg;
> -     void *ssl, *ssl_ctx;
> -
> -     tree_pop(&wait_ssl_init, s->id);
> -
> -     if (status == CA_FAIL) {
> -             log_info("%016"PRIx64" smtp disconnected "
> -                 "reason=ca-failure",
> -                 s->id);
> -             smtp_free(s, "CA failure");
> -             return;
> -     }
> -
> -     ssl_ctx = dict_get(env->sc_ssl_dict, name);
> -     ssl = ssl_smtp_init(ssl_ctx, s->listener->flags & F_TLS_VERIFY);
> -     io_set_read(s->io);
> -     io_start_tls(s->io, ssl);
> -}
> -
> -static void
> -smtp_cert_verify(struct smtp_session *s)
> -{
> -     const char *name;
> -     int fallback;
> -
> -     if (s->listener->ca_name[0]) {
> -             name = s->listener->ca_name;
> -             fallback = 0;
> -     }
> -     else {
> -             name = s->smtpname;
> -             fallback = 1;
> -     }
> -
> -     if (cert_verify(io_tls(s->io), name, fallback, smtp_cert_verify_cb, s)) 
> {
> -             tree_xset(&wait_ssl_verify, s->id, s);
> -             io_pause(s->io, IO_IN);
> -     }
> -}
> -
> -static void
> -smtp_cert_verify_cb(void *arg, int status)
> -{
> -     struct smtp_session *s = arg;
> -     const char *reason = NULL;
> -     int resume;
> -
> -     resume = tree_pop(&wait_ssl_verify, s->id) != NULL;
> -
> -     switch (status) {
> -     case CERT_OK:
> -             reason = "cert-ok";
> -             s->flags |= SF_VERIFIED;
> -             break;
> -     case CERT_NOCA:
> -             reason = "no-ca";
> -             break;
> -     case CERT_NOCERT:
> -             reason = "no-client-cert";
> -             break;
> -     case CERT_INVALID:
> -             reason = "cert-invalid";
> -             break;
> -     default:
> -             reason = "cert-check-failed";
> -             break;
> -     }
> -
> -     log_debug("smtp: %p: smtp_cert_verify_cb: %s", s, reason);
> -
> -     if (!(s->flags & SF_VERIFIED) && (s->listener->flags & F_TLS_VERIFY)) {
> -             log_info("%016"PRIx64" smtp disconnected "
> -                 " reason=%s", s->id,
> -                 reason);
> -             smtp_free(s, "SSL certificate check failed");
> -             return;
> -     }
> -
> -     smtp_tls_verified(s);
> -     if (resume)
> -             io_resume(s->io, IO_IN);
> -}
> -
> -static void
> smtp_auth_failure_resume(int fd, short event, void *p)
> {
>       struct smtp_session *s = p;
> @@ -2844,7 +2747,6 @@ static void
> smtp_message_begin(struct smtp_tx *tx)
> {
>       struct smtp_session *s;
> -     X509 *x;
>       int     (*m_printf)(struct smtp_tx *, const char *, ...);
> 
>       m_printf = smtp_message_printf;
> @@ -2879,13 +2781,11 @@ smtp_message_begin(struct smtp_tx *tx)
>           tx->msgid);
> 
>       if (s->flags & SF_SECURE) {
> -             x = SSL_get_peer_certificate(io_tls(s->io));
>               m_printf(tx, " (%s:%s:%d:%s)",
> -                 SSL_get_version(io_tls(s->io)),
> -                 SSL_get_cipher_name(io_tls(s->io)),
> -                 SSL_get_cipher_bits(io_tls(s->io), NULL),
> -                 (s->flags & SF_VERIFIED) ? "YES" : (x ? "FAIL" : "NO"));
> -             X509_free(x);
> +                 tls_conn_version(io_tls(s->io)),
> +                 tls_conn_cipher(io_tls(s->io)),
> +                 tls_conn_cipher_strength(io_tls(s->io)),
> +                 (s->flags & SF_VERIFIED) ? "YES" : "NO");
> 
>               if (s->listener->flags & F_RECEIVEDAUTH) {
>                       m_printf(tx, " auth=%s",
> Index: smtpc.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtpc.c,v
> retrieving revision 1.13
> diff -u -p -r1.13 smtpc.c
> --- smtpc.c   29 Dec 2020 12:17:54 -0000      1.13
> +++ smtpc.c   4 Feb 2021 19:56:51 -0000
> @@ -29,6 +29,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <syslog.h>
> +#include <tls.h>
> #include <unistd.h>
> 
> #include <openssl/ssl.h>
> @@ -48,8 +49,7 @@ static struct addrinfo *res0, *ai;
> static struct smtp_params params;
> static struct smtp_mail mail;
> static const char *servname = NULL;
> -
> -static SSL_CTX *ssl_ctx;
> +static struct tls_config *tls_config;
> 
> static void
> usage(void)
> @@ -156,16 +156,20 @@ main(int argc, char **argv)
>               mail.rcptcount = argc;
>       }
> 
> -     ssl_init();
> +     tls_init();
>       event_init();
> 
> -     ssl_ctx = ssl_ctx_create(NULL, NULL, 0, NULL);
> -     if (!SSL_CTX_load_verify_locations(ssl_ctx,
> -         X509_get_default_cert_file(), NULL))
> -             fatal("SSL_CTX_load_verify_locations");
> -     if (!SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_client_method()))
> -             fatal("SSL_CTX_set_ssl_version");
> -     SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE , NULL);
> +     tls_config = tls_config_new();
> +     if (tls_config == NULL)
> +             fatal("tls_config_new");
> +     if (tls_config_set_ca_file(tls_config, tls_default_ca_cert_file()) == 
> -1)
> +             fatal("tls_set_ca_file");
> +     if (!params.tls_verify) {
> +             tls_config_insecure_noverifycert(tls_config);
> +             tls_config_insecure_noverifyname(tls_config);
> +             tls_config_insecure_noverifytime(tls_config);
> +     } else
> +             tls_config_verify(tls_config);
> 
>       if (pledge("stdio inet dns tmppath", NULL) == -1)
>               fatal("pledge");
> @@ -282,6 +286,7 @@ parse_server(char *server)
> 
>       if (servname == NULL)
>               servname = host;
> +     params.tls_servname = servname;
> 
>       memset(&hints, 0, sizeof(hints));
>       hints.ai_family = AF_UNSPEC;
> @@ -399,11 +404,16 @@ smtp_verify_server_cert(void *tag, struc
> void
> smtp_require_tls(void *tag, struct smtp_client *proto)
> {
> -     SSL *ssl = NULL;
> +     struct tls *tls;
> +
> +     tls = tls_client();
> +     if (tls == NULL)
> +             fatal("tls_client");
> +
> +     if (tls_configure(tls, tls_config) == -1)
> +             fatal("tls_configure");
> 
> -     if ((ssl = SSL_new(ssl_ctx)) == NULL)
> -             fatal("SSL_new");
> -     smtp_set_tls(proto, ssl);
> +     smtp_set_tls(proto, tls);
> }
> 
> void
> Index: smtpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtpd.c,v
> retrieving revision 1.336
> diff -u -p -r1.336 smtpd.c
> --- smtpd.c   31 Dec 2020 08:27:15 -0000      1.336
> +++ smtpd.c   19 Jan 2021 09:45:44 -0000
> @@ -49,6 +49,7 @@
> #include <string.h>
> #include <sysexits.h>
> #include <time.h>
> +#include <tls.h>
> #include <unistd.h>
> 
> #include <openssl/ssl.h>
> @@ -609,7 +610,7 @@ main(int argc, char *argv[])
> 
>       env->sc_opts |= opts;
> 
> -     ssl_init();
> +     tls_init();
> 
>       if (parse_config(conf, conffile, opts))
>               exit(1);
> Index: smtpd.conf.5
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtpd.conf.5,v
> retrieving revision 1.256
> diff -u -p -r1.256 smtpd.conf.5
> --- smtpd.conf.5      27 Jan 2021 14:59:10 -0000      1.256
> +++ smtpd.conf.5      5 Feb 2021 08:24:11 -0000
> @@ -345,17 +345,9 @@ sending a single warning after four hour
> .It Ic ca Ar caname Cm cert Ar cafile
> Associate the Certificate Authority (CA) certificate file
> .Ar cafile
> -with host
> -.Ar caname ,
> -and use that file as the CA certificate for that host.
> -.Ar caname
> -is the server's name,
> -derived from the default hostname
> -or set using either
> -.Pa /etc/mail/mailname
> -or using the
> -.Ic hostname
> -directive.
> +with ca entry
> +.Ar caname .
> +The ca entry can be referenced in listener rules and relay actions.
> .It Ic filter Ar chain-name Ic chain Brq Ar filter-name Op , Ar ...
> Register a chain of filters
> .Ar chain-name ,
> @@ -479,6 +471,8 @@ use the certificate associated with
> .Ic pki
> directive)
> to prove a mail server's identity.
> +This option can be used multiple times to provide alternate
> +certificates for SNI.
> .It Cm port Op Ar port
> Listen on the given
> .Ar port
> @@ -800,21 +794,10 @@ The default is 100.
> .It Ic pki Ar pkiname Cm cert Ar certfile
> Associate certificate file
> .Ar certfile
> -with host
> -.Ar pkiname ,
> -and use that file to prove the identity of the mail server to clients.
> -.Ar pkiname
> -is the server's name,
> -derived from the default hostname
> -or set using either
> -.Pa /etc/mail/mailname
> -or using the
> -.Ic hostname
> -directive.
> -If a fallback certificate or SNI is wanted, the
> -.Sq *
> -wildcard may be used as
> +with pki entry
> .Ar pkiname .
> +The pki entry defines a keypair configuration that can be referenced
> +in listener rules and relay actions.
> .Pp
> A certificate chain may be created by appending one or many certificates,
> including a Certificate Authority certificate,
> @@ -825,10 +808,10 @@ The creation of certificates is document
> .It Ic pki Ar pkiname Cm key Ar keyfile
> Associate the key located in
> .Ar keyfile
> -with host
> +with pki entry
> .Ar pkiname .
> .It Ic pki Ar pkiname Cm dhe Ar params
> -Specify the DHE parameters to use for DHE cipher suites with host
> +Specify the DHE parameters to use for DHE cipher suites with pki entry
> .Ar pkiname .
> Valid parameter values are
> .Cm none ,
> Index: smtpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
> retrieving revision 1.661
> diff -u -p -r1.661 smtpd.h
> --- smtpd.h   19 Jan 2021 09:16:20 -0000      1.661
> +++ smtpd.h   19 Jan 2021 11:47:07 -0000
> @@ -542,6 +542,10 @@ struct listener {
>       TAILQ_ENTRY(listener)    entry;
> 
>       int                      local;         /* there must be a better way */
> +
> +     struct tls              *tls;
> +     struct pki              **pki;
> +     int                      pkicount;
> };
> 
> struct smtpd {
> @@ -1176,6 +1180,7 @@ struct dispatcher_remote {
> 
>       char    *source;
> 
> +     struct tls_config *tls_config;
>       char    *ca;
>       char    *pki;
> 
> @@ -1690,6 +1695,7 @@ const char *rule_to_text(struct rule *);
> const char *sockaddr_to_text(const struct sockaddr *);
> const char *mailaddr_to_text(const struct mailaddr *);
> const char *expandnode_to_text(struct expandnode *);
> +const char *tls_to_text(struct tls *);
> 
> 
> /* util.c */
> Index: ssl.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/ssl.c,v
> retrieving revision 1.93
> diff -u -p -r1.93 ssl.c
> --- ssl.c     5 Jun 2019 06:40:13 -0000       1.93
> +++ ssl.c     19 Jan 2021 08:41:42 -0000
> @@ -450,3 +450,59 @@ ssl_ctx_fake_private_key(SSL_CTX *ctx, c
> 
>       return (ret);
> }
> +
> +static void
> +hash_x509(X509 *cert, char *hash, size_t hashlen)
> +{
> +     static const char       hex[] = "0123456789abcdef";
> +     size_t                  off;
> +     char                    digest[EVP_MAX_MD_SIZE];
> +     int                     dlen, i;
> +
> +     if (X509_pubkey_digest(cert, EVP_sha256(), digest, &dlen) != 1)
> +             fatalx("%s: X509_pubkey_digest failed", __func__);
> +
> +     if (hashlen < 2 * dlen + sizeof("SHA256:"))
> +             fatalx("%s: hash buffer to small", __func__);
> +
> +     off = strlcpy(hash, "SHA256:", hashlen);
> +
> +     for (i = 0; i < dlen; i++) {
> +             hash[off++] = hex[(digest[i] >> 4) & 0x0f];
> +             hash[off++] = hex[digest[i] & 0x0f];
> +     }
> +     hash[off] = 0;
> +}
> +
> +char *
> +ssl_pubkey_hash(const char *buf, off_t len)
> +{
> +#define TLS_CERT_HASH_SIZE   128
> +     BIO             *in;
> +     X509            *x509 = NULL;
> +     char            *hash = NULL;
> +
> +     if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
> +             log_warnx("%s: BIO_new_mem_buf failed", __func__);
> +             return NULL;
> +     }
> +
> +     if ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) {
> +             log_warnx("%s: PEM_read_bio_X509 failed", __func__);
> +             goto fail;
> +     }
> +
> +     if ((hash = malloc(TLS_CERT_HASH_SIZE)) == NULL) {
> +             log_warn("%s: malloc", __func__);
> +             goto fail;
> +     }
> +     hash_x509(x509, hash, TLS_CERT_HASH_SIZE);
> +
> +fail:
> +     BIO_free(in);
> +
> +     if (x509)
> +             X509_free(x509);
> +
> +     return hash;
> +}
> Index: ssl.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/ssl.h,v
> retrieving revision 1.21
> diff -u -p -r1.21 ssl.h
> --- ssl.h     18 Sep 2019 11:26:30 -0000      1.21
> +++ ssl.h     19 Jan 2021 09:06:14 -0000
> @@ -15,6 +15,8 @@
>  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  */
> 
> +#include <openssl/ssl.h>
> +
> #define SSL_CIPHERS           "HIGH:!aNULL:!MD5"
> #define       SSL_SESSION_TIMEOUT     300
> 
> @@ -62,6 +64,7 @@ int         ssl_load_pkey(const void *, size_t,
>                   X509 **, EVP_PKEY **);
> int           ssl_ctx_fake_private_key(SSL_CTX *, const void *, size_t,
>                   char *, off_t, X509 **, EVP_PKEY **);
> +char *ssl_pubkey_hash(const char *, off_t);
> 
> /* ssl_privsep.c */
> int           ssl_by_mem_ctrl(X509_LOOKUP *, int, const char *, long, char 
> **);
> Index: to.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/to.c,v
> retrieving revision 1.45
> diff -u -p -r1.45 to.c
> --- to.c      19 Jan 2021 09:16:20 -0000      1.45
> +++ to.c      19 Jan 2021 11:47:07 -0000
> @@ -43,6 +43,9 @@
> #include <stdlib.h>
> #include <string.h>
> #include <time.h>
> +#if IO_TLS
> +#include <tls.h>
> +#endif
> #include <unistd.h>
> 
> #include "smtpd.h"
> @@ -795,3 +798,18 @@ alias_is_error(struct expandnode *alias,
>       alias->type = EXPAND_ERROR;
>       return 1;
> }
> +
> +#if IO_TLS
> +const char *
> +tls_to_text(struct tls *tls)
> +{
> +     static char buf[256];
> +
> +     (void)snprintf(buf, sizeof buf, "%s:%s:%d",
> +         tls_conn_version(tls),
> +         tls_conn_cipher(tls),
> +         tls_conn_cipher_strength(tls));
> +
> +     return (buf);
> +}
> +#endif
> Index: smtp/Makefile
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtp/Makefile,v
> retrieving revision 1.3
> diff -u -p -r1.3 Makefile
> --- smtp/Makefile     18 Sep 2019 11:26:30 -0000      1.3
> +++ smtp/Makefile     19 Jan 2021 09:08:22 -0000
> @@ -17,7 +17,7 @@ SRCS+=      ssl_verify.c
> 
> CPPFLAGS+= -DIO_TLS
> 
> -LDADD+=      -levent -lutil -lssl -lcrypto -lm -lz
> -DPADD+=      ${LIBEVENT} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBM} ${LIBZ}
> +LDADD+=      -levent -lutil -ltls -lssl -lcrypto -lm -lz
> +DPADD+=      ${LIBEVENT} ${LIBUTIL} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} ${LIBM} 
> ${LIBZ}
> 
> .include <bsd.prog.mk>
> Index: smtpd/Makefile
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/smtpd/Makefile,v
> retrieving revision 1.110
> diff -u -p -r1.110 Makefile
> --- smtpd/Makefile    31 Dec 2020 08:27:15 -0000      1.110
> +++ smtpd/Makefile    19 Jan 2021 08:36:15 -0000
> @@ -82,8 +82,8 @@ SRCS+=              stat_ramstat.c
> MAN=          sendmail.8 smtpd.8 smtpd.conf.5 table.5
> BINDIR=               /usr/sbin
> 
> -LDADD+=              -levent -lutil -lssl -lcrypto -lm -lz
> -DPADD+=              ${LIBEVENT} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBM} 
> ${LIBZ}
> +LDADD+=              -levent -lutil -ltls -lssl -lcrypto -lm -lz
> +DPADD+=              ${LIBEVENT} ${LIBUTIL} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} 
> ${LIBM} ${LIBZ}
> 
> CFLAGS+=      -fstack-protector-all
> CFLAGS+=      -I${.CURDIR}/..

Reply via email to