Hi.

The diff seems to work for the few people who tested it (thanks).
Anyone wants to ok this?

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.257
diff -u -p -r1.257 smtpd.conf.5
--- smtpd.conf.5        13 Feb 2021 07:59:54 -0000      1.257
+++ smtpd.conf.5        13 Feb 2021 13:21:35 -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