diff options
author | Gilles Chehade <gilles@poolp.org> | 2019-06-13 10:16:16 +0200 |
---|---|---|
committer | Gilles Chehade <gilles@poolp.org> | 2019-06-13 10:16:16 +0200 |
commit | 2c7dc9dbf2cb4de87523123aae072aab81e74349 (patch) | |
tree | 8666e9e7d928161589685ebca36d810915ee1326 | |
parent | Merge branch 'master' into portable (diff) | |
parent | sync with openbsd (diff) | |
download | OpenSMTPD-2c7dc9dbf2cb4de87523123aae072aab81e74349.tar.xz OpenSMTPD-2c7dc9dbf2cb4de87523123aae072aab81e74349.zip |
Merge branch 'master' into portable
-rw-r--r-- | smtpd/ca.c | 324 | ||||
-rw-r--r-- | smtpd/iobuf.c | 32 | ||||
-rw-r--r-- | smtpd/iobuf.h | 10 | ||||
-rw-r--r-- | smtpd/ioev.c | 168 | ||||
-rw-r--r-- | smtpd/ioev.h | 4 | ||||
-rw-r--r-- | smtpd/mta_session.c | 8 | ||||
-rw-r--r-- | smtpd/smtp_client.c | 4 | ||||
-rw-r--r-- | smtpd/smtp_session.c | 18 | ||||
-rw-r--r-- | smtpd/smtpd.c | 7 | ||||
-rw-r--r-- | smtpd/smtpd.h | 7 | ||||
-rw-r--r-- | smtpd/ssl.c | 14 |
11 files changed, 415 insertions, 181 deletions
@@ -1,4 +1,4 @@ -/* $OpenBSD: ca.c,v 1.32 2019/05/24 15:34:05 gilles Exp $ */ +/* $OpenBSD: ca.c,v 1.34 2019/06/05 16:24:54 gilles Exp $ */ /* * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org> @@ -37,6 +37,7 @@ #include <openssl/ssl.h> #include <openssl/pem.h> #include <openssl/evp.h> +#include <openssl/ecdsa.h> #include <openssl/rsa.h> #include <openssl/engine.h> #include <openssl/err.h> @@ -64,7 +65,14 @@ static int rsae_init(RSA *); static int rsae_finish(RSA *); static int rsae_keygen(RSA *, int, BIGNUM *, BN_GENCB *); -static uint64_t rsae_reqid = 0; +static ECDSA_SIG *ecdsae_do_sign(const unsigned char *, int, const BIGNUM *, + const BIGNUM *, EC_KEY *); +static int ecdsae_sign_setup(EC_KEY *, BN_CTX *, BIGNUM **, BIGNUM **); +static int ecdsae_do_verify(const unsigned char *, int, const ECDSA_SIG *, + EC_KEY *); + + +static uint64_t reqid = 0; static void ca_shutdown(void) @@ -218,12 +226,14 @@ end: void ca_imsg(struct mproc *p, struct imsg *imsg) { - RSA *rsa; + RSA *rsa = NULL; + EC_KEY *ecdsa = NULL; const void *from = NULL; unsigned char *to = NULL; struct msg m; const char *pkiname; size_t flen, tlen, padding; + int buf_len; struct pki *pki; int ret = 0; uint64_t id; @@ -256,8 +266,8 @@ ca_imsg(struct mproc *p, struct imsg *imsg) profiling = v; return; - case IMSG_CA_PRIVENC: - case IMSG_CA_PRIVDEC: + case IMSG_CA_RSA_PRIVENC: + case IMSG_CA_RSA_PRIVDEC: m_msg(&m, imsg); m_get_id(&m, &id); m_get_string(&m, &pkiname); @@ -275,11 +285,11 @@ ca_imsg(struct mproc *p, struct imsg *imsg) fatalx("ca_imsg: calloc"); switch (imsg->hdr.type) { - case IMSG_CA_PRIVENC: + case IMSG_CA_RSA_PRIVENC: ret = RSA_private_encrypt(flen, from, to, rsa, padding); break; - case IMSG_CA_PRIVDEC: + case IMSG_CA_RSA_PRIVDEC: ret = RSA_private_decrypt(flen, from, to, rsa, padding); break; @@ -294,7 +304,32 @@ ca_imsg(struct mproc *p, struct imsg *imsg) free(to); RSA_free(rsa); + return; + + case IMSG_CA_ECDSA_SIGN: + m_msg(&m, imsg); + m_get_id(&m, &id); + m_get_string(&m, &pkiname); + 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"); + buf_len = ECDSA_size(ecdsa); + if ((to = calloc(1, buf_len)) == NULL) + fatalx("ca_imsg: calloc"); + ret = ECDSA_sign(0, from, flen, to, &buf_len, ecdsa); + m_create(p, imsg->hdr.type, 0, 0, -1); + m_add_id(p, id); + m_add_int(p, ret); + if (ret > 0) + m_add_data(p, to, (size_t)buf_len); + m_close(p); + free(to); + EC_KEY_free(ecdsa); return; } @@ -331,8 +366,8 @@ rsae_send_imsg(int flen, const unsigned char *from, unsigned char *to, * operation in OpenSSL's engine layer. */ m_create(p_ca, cmd, 0, 0, -1); - rsae_reqid++; - m_add_id(p_ca, rsae_reqid); + reqid++; + m_add_id(p_ca, reqid); m_add_string(p_ca, pkiname); m_add_data(p_ca, (const void *)from, (size_t)flen); m_add_size(p_ca, (size_t)RSA_size(rsa)); @@ -356,8 +391,8 @@ rsae_send_imsg(int flen, const unsigned char *from, unsigned char *to, log_imsg(PROC_PONY, PROC_CA, &imsg); switch (imsg.hdr.type) { - case IMSG_CA_PRIVENC: - case IMSG_CA_PRIVDEC: + case IMSG_CA_RSA_PRIVENC: + case IMSG_CA_RSA_PRIVDEC: break; default: /* Another imsg is queued up in the buffer */ @@ -368,7 +403,7 @@ rsae_send_imsg(int flen, const unsigned char *from, unsigned char *to, m_msg(&m, &imsg); m_get_id(&m, &id); - if (id != rsae_reqid) + if (id != reqid) fatalx("invalid response id"); m_get_int(&m, &ret); if (ret > 0) @@ -392,7 +427,7 @@ rsae_pub_enc(int flen,const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - return (rsa_default->rsa_pub_enc(flen, from, to, rsa, padding)); + return (RSA_meth_get_pub_enc(rsa_default)(flen, from, to, rsa, padding)); } static int @@ -400,7 +435,7 @@ rsae_pub_dec(int flen,const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - return (rsa_default->rsa_pub_dec(flen, from, to, rsa, padding)); + return (RSA_meth_get_pub_dec(rsa_default)(flen, from, to, rsa, padding)); } static int @@ -408,11 +443,10 @@ rsae_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - if (RSA_get_ex_data(rsa, 0) != NULL) { + if (RSA_get_ex_data(rsa, 0) != NULL) return (rsae_send_imsg(flen, from, to, rsa, padding, - IMSG_CA_PRIVENC)); - } - return (rsa_default->rsa_priv_enc(flen, from, to, rsa, padding)); + IMSG_CA_RSA_PRIVENC)); + return (RSA_meth_get_priv_enc(rsa_default)(flen, from, to, rsa, padding)); } static int @@ -420,18 +454,18 @@ rsae_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - if (RSA_get_ex_data(rsa, 0) != NULL) { + if (RSA_get_ex_data(rsa, 0) != NULL) return (rsae_send_imsg(flen, from, to, rsa, padding, - IMSG_CA_PRIVDEC)); - } - return (rsa_default->rsa_priv_dec(flen, from, to, rsa, padding)); + IMSG_CA_RSA_PRIVDEC)); + + return (RSA_meth_get_priv_dec(rsa_default)(flen, from, to, rsa, padding)); } static int rsae_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - return (rsa_default->rsa_mod_exp(r0, I, rsa, ctx)); + return (RSA_meth_get_mod_exp(rsa_default)(r0, I, rsa, ctx)); } static int @@ -439,36 +473,166 @@ rsae_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - return (rsa_default->bn_mod_exp(r, a, p, m, ctx, m_ctx)); + return (RSA_meth_get_bn_mod_exp(rsa_default)(r, a, p, m, ctx, m_ctx)); } static int rsae_init(RSA *rsa) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - if (rsa_default->init == NULL) + if (RSA_meth_get_init(rsa_default) == NULL) return (1); - return (rsa_default->init(rsa)); + return (RSA_meth_get_init(rsa_default)(rsa)); } static int rsae_finish(RSA *rsa) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - if (rsa_default->finish == NULL) + if (RSA_meth_get_finish(rsa_default) == NULL) return (1); - return (rsa_default->finish(rsa)); + return (RSA_meth_get_finish(rsa_default)(rsa)); } static int rsae_keygen(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) { log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); - return (rsa_default->rsa_keygen(rsa, bits, e, cb)); + return (RSA_meth_get_keygen(rsa_default)(rsa, bits, e, cb)); } -void -ca_engine_init(void) + +/* + * ECDSA privsep engine (called from unprivileged processes) + */ + +const ECDSA_METHOD *ecdsa_default = NULL; + +static ECDSA_METHOD *ecdsae_method = NULL; + +ECDSA_METHOD * +ECDSA_METHOD_new_temporary(const char *name, int); + +ECDSA_METHOD * +ECDSA_METHOD_new_temporary(const char *name, int flags) +{ + ECDSA_METHOD *ecdsa; + + if ((ecdsa = calloc(1, sizeof (*ecdsa))) == NULL) + return NULL; + + if ((ecdsa->name = strdup(name)) == NULL) { + free(ecdsa); + return NULL; + } + + ecdsa->flags = flags; + return ecdsa; +} + +static ECDSA_SIG * +ecdsae_send_enc_imsg(const unsigned char *dgst, int dgst_len, + const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey) +{ + int ret = 0; + struct imsgbuf *ibuf; + struct imsg imsg; + int n, done = 0; + const void *toptr; + char *pkiname; + size_t tlen; + struct msg m; + uint64_t id; + ECDSA_SIG *sig = NULL; + + if ((pkiname = ECDSA_get_ex_data(eckey, 0)) == NULL) + return (0); + + /* + * Send a synchronous imsg because we cannot defer the ECDSA + * operation in OpenSSL's engine layer. + */ + 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_data(p_ca, (const void *)dgst, (size_t)dgst_len); + m_flush(p_ca); + + ibuf = &p_ca->imsgbuf; + + while (!done) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatalx("imsg_read"); + if (n == 0) + fatalx("pipe closed"); + while (!done) { + if ((n = imsg_get(ibuf, &imsg)) == -1) + fatalx("imsg_get error"); + if (n == 0) + break; + + log_imsg(PROC_PONY, PROC_CA, &imsg); + + switch (imsg.hdr.type) { + case IMSG_CA_ECDSA_SIGN: + break; + default: + /* Another imsg is queued up in the buffer */ + pony_imsg(p_ca, &imsg); + imsg_free(&imsg); + continue; + } + + m_msg(&m, &imsg); + m_get_id(&m, &id); + if (id != reqid) + fatalx("invalid response id"); + m_get_int(&m, &ret); + if (ret > 0) + m_get_data(&m, &toptr, &tlen); + m_end(&m); + done = 1; + + if (ret > 0) + d2i_ECDSA_SIG(&sig, (const unsigned char **)&toptr, tlen); + imsg_free(&imsg); + } + } + mproc_event_add(p_ca); + + return (sig); +} + +ECDSA_SIG * +ecdsae_do_sign(const unsigned char *dgst, int dgst_len, + const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + if (ECDSA_get_ex_data(eckey, 0) != NULL) + return (ecdsae_send_enc_imsg(dgst, dgst_len, inv, rp, eckey)); + return (ecdsa_default->ecdsa_do_sign(dgst, dgst_len, inv, rp, eckey)); +} + +int +ecdsae_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, + BIGNUM **r) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + return (ecdsa_default->ecdsa_sign_setup(eckey, ctx, kinv, r)); +} + +int +ecdsae_do_verify(const unsigned char *dgst, int dgst_len, + const ECDSA_SIG *sig, EC_KEY *eckey) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + return (ecdsa_default->ecdsa_do_verify(dgst, dgst_len, sig, eckey)); +} + + +static void +rsa_engine_init(void) { ENGINE *e; const char *errstr, *name; @@ -476,22 +640,22 @@ ca_engine_init(void) if ((rsae_method = RSA_meth_new("RSA privsep engine", 0)) == NULL) goto fail; - rsae_method->rsa_pub_enc = rsae_pub_enc; - rsae_method->rsa_pub_dec = rsae_pub_dec; - rsae_method->rsa_priv_enc = rsae_priv_enc; - rsae_method->rsa_priv_dec = rsae_priv_dec; - rsae_method->rsa_mod_exp = rsae_mod_exp; - rsae_method->bn_mod_exp = rsae_bn_mod_exp; - rsae_method->init = rsae_init; - rsae_method->finish = rsae_finish; - rsae_method->rsa_keygen = rsae_keygen; + RSA_meth_set_pub_enc(rsae_method, rsae_pub_enc); + RSA_meth_set_pub_dec(rsae_method, rsae_pub_dec); + RSA_meth_set_priv_enc(rsae_method, rsae_priv_enc); + RSA_meth_set_priv_dec(rsae_method, rsae_priv_dec); + RSA_meth_set_mod_exp(rsae_method, rsae_mod_exp); + RSA_meth_set_bn_mod_exp(rsae_method, rsae_bn_mod_exp); + RSA_meth_set_init(rsae_method, rsae_init); + RSA_meth_set_finish(rsae_method, rsae_finish); + RSA_meth_set_keygen(rsae_method, rsae_keygen); if ((e = ENGINE_get_default_RSA()) == NULL) { if ((e = ENGINE_new()) == NULL) { errstr = "ENGINE_new"; goto fail; } - if (!ENGINE_set_name(e, rsae_method->name)) { + if (!ENGINE_set_name(e, RSA_meth_get0_name(rsae_method))) { errstr = "ENGINE_set_name"; goto fail; } @@ -509,15 +673,16 @@ ca_engine_init(void) log_debug("debug: %s: using %s", __func__, name); - if (rsa_default->rsa_mod_exp == NULL) - rsae_method->rsa_mod_exp = NULL; - if (rsa_default->bn_mod_exp == NULL) - rsae_method->bn_mod_exp = NULL; - if (rsa_default->rsa_keygen == NULL) - rsae_method->rsa_keygen = NULL; - rsae_method->flags = rsa_default->flags | - RSA_METHOD_FLAG_NO_CHECK; - rsae_method->app_data = rsa_default->app_data; + if (RSA_meth_get_mod_exp(rsa_default) == NULL) + RSA_meth_set_mod_exp(rsae_method, NULL); + if (RSA_meth_get_bn_mod_exp(rsa_default) == NULL) + RSA_meth_set_bn_mod_exp(rsae_method, NULL); + if (RSA_meth_get_keygen(rsa_default) == NULL) + RSA_meth_set_keygen(rsae_method, NULL); + RSA_meth_set_flags(rsae_method, + RSA_meth_get_flags(rsa_default) | RSA_METHOD_FLAG_NO_CHECK); + RSA_meth_set0_app_data(rsae_method, + RSA_meth_get0_app_data(rsa_default)); if (!ENGINE_set_RSA(e, rsae_method)) { errstr = "ENGINE_set_RSA"; @@ -534,3 +699,62 @@ ca_engine_init(void) ssl_error(errstr); fatalx("%s", errstr); } + +static void +ecdsa_engine_init(void) +{ + ENGINE *e; + const char *errstr, *name; + + if ((ecdsae_method = ECDSA_METHOD_new_temporary("ECDSA privsep engine", 0)) == NULL) + goto fail; + + ecdsae_method->ecdsa_do_sign = ecdsae_do_sign; + ecdsae_method->ecdsa_sign_setup = ecdsae_sign_setup; + ecdsae_method->ecdsa_do_verify = ecdsae_do_verify; + + if ((e = ENGINE_get_default_ECDSA()) == NULL) { + if ((e = ENGINE_new()) == NULL) { + errstr = "ENGINE_new"; + goto fail; + } + if (!ENGINE_set_name(e, ecdsae_method->name)) { + errstr = "ENGINE_set_name"; + goto fail; + } + if ((ecdsa_default = ECDSA_get_default_method()) == NULL) { + errstr = "ECDSA_get_default_method"; + goto fail; + } + } else if ((ecdsa_default = ENGINE_get_ECDSA(e)) == NULL) { + errstr = "ENGINE_get_ECDSA"; + goto fail; + } + + if ((name = ENGINE_get_name(e)) == NULL) + name = "unknown ECDSA engine"; + + log_debug("debug: %s: using %s", __func__, name); + + if (!ENGINE_set_ECDSA(e, ecdsae_method)) { + errstr = "ENGINE_set_ECDSA"; + goto fail; + } + if (!ENGINE_set_default_ECDSA(e)) { + errstr = "ENGINE_set_default_ECDSA"; + goto fail; + } + + return; + + fail: + ssl_error(errstr); + fatalx("%s", errstr); +} + +void +ca_engine_init(void) +{ + rsa_engine_init(); + ecdsa_engine_init(); +} diff --git a/smtpd/iobuf.c b/smtpd/iobuf.c index 46d8ef04..31a410c1 100644 --- a/smtpd/iobuf.c +++ b/smtpd/iobuf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iobuf.c,v 1.10 2017/03/17 20:56:04 eric Exp $ */ +/* $OpenBSD: iobuf.c,v 1.11 2019/06/12 17:42:53 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -28,7 +28,7 @@ #include <string.h> #include <unistd.h> -#ifdef IO_SSL +#ifdef IO_TLS #include <openssl/err.h> #include <openssl/ssl.h> #endif @@ -388,31 +388,31 @@ iobuf_flush(struct iobuf *io, int fd) return (0); } -#ifdef IO_SSL +#ifdef IO_TLS int -iobuf_flush_ssl(struct iobuf *io, void *ssl) +iobuf_flush_tls(struct iobuf *io, void *tls) { ssize_t s; while (io->queued) - if ((s = iobuf_write_ssl(io, ssl)) < 0) + if ((s = iobuf_write_tls(io, tls)) < 0) return (s); return (0); } ssize_t -iobuf_write_ssl(struct iobuf *io, void *ssl) +iobuf_write_tls(struct iobuf *io, void *tls) { struct ioqbuf *q; int r; ssize_t n; q = io->outq; - n = SSL_write(ssl, q->buf + q->rpos, q->wpos - q->rpos); + n = SSL_write(tls, q->buf + q->rpos, q->wpos - q->rpos); if (n <= 0) { - switch ((r = SSL_get_error(ssl, n))) { + switch ((r = SSL_get_error(tls, n))) { case SSL_ERROR_WANT_READ: return (IOBUF_WANT_READ); case SSL_ERROR_WANT_WRITE: @@ -421,12 +421,12 @@ iobuf_write_ssl(struct iobuf *io, void *ssl) return (IOBUF_CLOSED); case SSL_ERROR_SYSCALL: if (ERR_peek_last_error()) - return (IOBUF_SSLERROR); + return (IOBUF_TLSERROR); if (r == 0) errno = EPIPE; return (IOBUF_ERROR); default: - return (IOBUF_SSLERROR); + return (IOBUF_TLSERROR); } } iobuf_drain(io, n); @@ -435,26 +435,26 @@ iobuf_write_ssl(struct iobuf *io, void *ssl) } ssize_t -iobuf_read_ssl(struct iobuf *io, void *ssl) +iobuf_read_tls(struct iobuf *io, void *tls) { ssize_t n; int r; - n = SSL_read(ssl, io->buf + io->wpos, iobuf_left(io)); + n = SSL_read(tls, io->buf + io->wpos, iobuf_left(io)); if (n < 0) { - switch ((r = SSL_get_error(ssl, n))) { + switch ((r = 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_SSLERROR); + return (IOBUF_TLSERROR); if (r == 0) errno = EPIPE; return (IOBUF_ERROR); default: - return (IOBUF_SSLERROR); + return (IOBUF_TLSERROR); } } else if (n == 0) return (IOBUF_CLOSED); @@ -464,4 +464,4 @@ iobuf_read_ssl(struct iobuf *io, void *ssl) return (n); } -#endif /* IO_SSL */ +#endif /* IO_TLS */ diff --git a/smtpd/iobuf.h b/smtpd/iobuf.h index e1f27454..c454d0a1 100644 --- a/smtpd/iobuf.h +++ b/smtpd/iobuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iobuf.h,v 1.4 2015/01/20 17:37:54 deraadt Exp $ */ +/* $OpenBSD: iobuf.h,v 1.5 2019/06/12 17:42:53 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -39,7 +39,7 @@ struct iobuf { #define IOBUF_WANT_WRITE -2 #define IOBUF_CLOSED -3 #define IOBUF_ERROR -4 -#define IOBUF_SSLERROR -5 +#define IOBUF_TLSERROR -5 int iobuf_init(struct iobuf *, size_t, size_t); void iobuf_clear(struct iobuf *); @@ -53,7 +53,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_ssl(struct iobuf *, void *); +ssize_t iobuf_read_tls(struct iobuf *, void *); size_t iobuf_queued(struct iobuf *); void* iobuf_reserve(struct iobuf *, size_t); @@ -62,6 +62,6 @@ int iobuf_queuev(struct iobuf *, const struct iovec *, int); 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_ssl(struct iobuf *, void *); +int iobuf_flush_tls(struct iobuf *, void *); ssize_t iobuf_write(struct iobuf *, int); -ssize_t iobuf_write_ssl(struct iobuf *, void *); +ssize_t iobuf_write_tls(struct iobuf *, void *); diff --git a/smtpd/ioev.c b/smtpd/ioev.c index 28de5c7b..e0a8a096 100644 --- a/smtpd/ioev.c +++ b/smtpd/ioev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ioev.c,v 1.41 2017/05/17 14:00:06 deraadt Exp $ */ +/* $OpenBSD: ioev.c,v 1.42 2019/06/12 17:42:53 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -34,7 +34,7 @@ #include "ioev.h" #include "iobuf.h" -#ifdef IO_SSL +#ifdef IO_TLS #include <openssl/err.h> #include <openssl/ssl.h> #endif @@ -42,8 +42,8 @@ enum { IO_STATE_NONE, IO_STATE_CONNECT, - IO_STATE_CONNECT_SSL, - IO_STATE_ACCEPT_SSL, + IO_STATE_CONNECT_TLS, + IO_STATE_ACCEPT_TLS, IO_STATE_UP, IO_STATE_MAX, @@ -67,7 +67,7 @@ struct io { int flags; int state; struct event ev; - void *ssl; + void *tls; const char *error; /* only valid immediately on callback */ }; @@ -86,15 +86,15 @@ void io_reset(struct io *, short, void (*)(int, short, void*)); void io_frame_enter(const char *, struct io *, int); void io_frame_leave(struct io *); -#ifdef IO_SSL +#ifdef IO_TLS void ssl_error(const char *); /* XXX external */ -static const char* io_ssl_error(void); -void io_dispatch_accept_ssl(int, short, void *); -void io_dispatch_connect_ssl(int, short, void *); -void io_dispatch_read_ssl(int, short, void *); -void io_dispatch_write_ssl(int, short, void *); -void io_reload_ssl(struct io *io); +static const char* io_tls_error(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 *); +void io_dispatch_write_tls(int, short, void *); +void io_reload_tls(struct io *io); #endif static struct io *current = NULL; @@ -111,12 +111,12 @@ io_strio(struct io *io) char ssl[128]; ssl[0] = '\0'; -#ifdef IO_SSL - if (io->ssl) { - (void)snprintf(ssl, sizeof ssl, " ssl=%s:%s:%d", - SSL_get_version(io->ssl), - SSL_get_cipher_name(io->ssl), - SSL_get_cipher_bits(io->ssl, NULL)); +#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)); } #endif @@ -273,9 +273,9 @@ io_free(struct io *io) if (io == current) current = NULL; -#ifdef IO_SSL - SSL_free(io->ssl); - io->ssl = NULL; +#ifdef IO_TLS + SSL_free(io->tls); + io->tls = NULL; #endif if (event_initialized(&io->ev)) @@ -400,9 +400,9 @@ io_error(struct io *io) } void * -io_ssl(struct io *io) +io_tls(struct io *io) { - return io->ssl; + return io->tls; } int @@ -533,9 +533,9 @@ io_reload(struct io *io) iobuf_normalize(&io->iobuf); -#ifdef IO_SSL - if (io->ssl) { - io_reload_ssl(io); +#ifdef IO_TLS + if (io->tls) { + io_reload_tls(io); return; } #endif @@ -808,10 +808,10 @@ io_dispatch_connect(int fd, short ev, void *humppa) io_frame_leave(io); } -#ifdef IO_SSL +#ifdef IO_TLS static const char* -io_ssl_error(void) +io_tls_error(void) { static char buf[128]; unsigned long e; @@ -822,11 +822,11 @@ io_ssl_error(void) return (buf); } - return ("No SSL error"); + return ("No TLS error"); } int -io_start_tls(struct io *io, void *ssl) +io_start_tls(struct io *io, void *tls) { int mode; @@ -834,57 +834,57 @@ io_start_tls(struct io *io, void *ssl) if (mode == 0 || mode == IO_RW) errx(1, "io_start_tls(): full-duplex or unset"); - if (io->ssl) - errx(1, "io_start_tls(): SSL already started"); - io->ssl = ssl; + if (io->tls) + errx(1, "io_start_tls(): TLS already started"); + io->tls = tls; - if (SSL_set_fd(io->ssl, io->sock) == 0) { - ssl_error("io_start_ssl:SSL_set_fd"); + if (SSL_set_fd(io->tls, io->sock) == 0) { + ssl_error("io_start_tls:SSL_set_fd"); return (-1); } if (mode == IO_WRITE) { - io->state = IO_STATE_CONNECT_SSL; - SSL_set_connect_state(io->ssl); - io_reset(io, EV_WRITE, io_dispatch_connect_ssl); + 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_SSL; - SSL_set_accept_state(io->ssl); - io_reset(io, EV_READ, io_dispatch_accept_ssl); + io->state = IO_STATE_ACCEPT_TLS; + SSL_set_accept_state(io->tls); + io_reset(io, EV_READ, io_dispatch_accept_tls); } return (0); } void -io_dispatch_accept_ssl(int fd, short event, void *humppa) +io_dispatch_accept_tls(int fd, short event, void *humppa) { struct io *io = humppa; int e, ret; - io_frame_enter("io_dispatch_accept_ssl", io, event); + io_frame_enter("io_dispatch_accept_tls", io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); goto leave; } - if ((ret = SSL_accept(io->ssl)) > 0) { + if ((ret = SSL_accept(io->tls)) > 0) { io->state = IO_STATE_UP; io_callback(io, IO_TLSREADY); goto leave; } - switch ((e = SSL_get_error(io->ssl, ret))) { + switch ((e = SSL_get_error(io->tls, ret))) { case SSL_ERROR_WANT_READ: - io_reset(io, EV_READ, io_dispatch_accept_ssl); + io_reset(io, EV_READ, io_dispatch_accept_tls); break; case SSL_ERROR_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_accept_ssl); + io_reset(io, EV_WRITE, io_dispatch_accept_tls); break; default: - io->error = io_ssl_error(); - ssl_error("io_dispatch_accept_ssl:SSL_accept"); + io->error = io_tls_error(); + ssl_error("io_dispatch_accept_tls:SSL_accept"); io_callback(io, IO_ERROR); break; } @@ -894,33 +894,33 @@ io_dispatch_accept_ssl(int fd, short event, void *humppa) } void -io_dispatch_connect_ssl(int fd, short event, void *humppa) +io_dispatch_connect_tls(int fd, short event, void *humppa) { struct io *io = humppa; int e, ret; - io_frame_enter("io_dispatch_connect_ssl", io, event); + io_frame_enter("io_dispatch_connect_tls", io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); goto leave; } - if ((ret = SSL_connect(io->ssl)) > 0) { + if ((ret = SSL_connect(io->tls)) > 0) { io->state = IO_STATE_UP; io_callback(io, IO_TLSREADY); goto leave; } - switch ((e = SSL_get_error(io->ssl, ret))) { + switch ((e = SSL_get_error(io->tls, ret))) { case SSL_ERROR_WANT_READ: - io_reset(io, EV_READ, io_dispatch_connect_ssl); + io_reset(io, EV_READ, io_dispatch_connect_tls); break; case SSL_ERROR_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_connect_ssl); + io_reset(io, EV_WRITE, io_dispatch_connect_tls); break; default: - io->error = io_ssl_error(); + io->error = io_tls_error(); ssl_error("io_dispatch_connect_ssl:SSL_connect"); io_callback(io, IO_TLSERROR); break; @@ -931,12 +931,12 @@ io_dispatch_connect_ssl(int fd, short event, void *humppa) } void -io_dispatch_read_ssl(int fd, short event, void *humppa) +io_dispatch_read_tls(int fd, short event, void *humppa) { struct io *io = humppa; int n, saved_errno; - io_frame_enter("io_dispatch_read_ssl", io, event); + io_frame_enter("io_dispatch_read_tls", io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); @@ -945,12 +945,12 @@ io_dispatch_read_ssl(int fd, short event, void *humppa) again: iobuf_normalize(&io->iobuf); - switch ((n = iobuf_read_ssl(&io->iobuf, (SSL*)io->ssl))) { + switch ((n = iobuf_read_tls(&io->iobuf, (SSL*)io->tls))) { case IOBUF_WANT_READ: - io_reset(io, EV_READ, io_dispatch_read_ssl); + io_reset(io, EV_READ, io_dispatch_read_tls); break; case IOBUF_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_read_ssl); + io_reset(io, EV_WRITE, io_dispatch_read_tls); break; case IOBUF_CLOSED: io_callback(io, IO_DISCONNECTED); @@ -961,15 +961,15 @@ again: errno = saved_errno; io_callback(io, IO_ERROR); break; - case IOBUF_SSLERROR: - io->error = io_ssl_error(); - ssl_error("io_dispatch_read_ssl:SSL_read"); + case IOBUF_TLSERROR: + io->error = io_tls_error(); + ssl_error("io_dispatch_read_tls:SSL_read"); io_callback(io, IO_ERROR); break; default: - io_debug("io_dispatch_read_ssl(...) -> r=%d\n", n); + io_debug("io_dispatch_read_tls(...) -> r=%d\n", n); io_callback(io, IO_DATAIN); - if (current == io && IO_READING(io) && SSL_pending(io->ssl)) + if (current == io && IO_READING(io) && SSL_pending(io->tls)) goto again; } @@ -978,13 +978,13 @@ again: } void -io_dispatch_write_ssl(int fd, short event, void *humppa) +io_dispatch_write_tls(int fd, short event, void *humppa) { struct io *io = humppa; int n, saved_errno; size_t w2, w; - io_frame_enter("io_dispatch_write_ssl", io, event); + io_frame_enter("io_dispatch_write_tls", io, event); if (event == EV_TIMEOUT) { io_callback(io, IO_TIMEOUT); @@ -992,12 +992,12 @@ io_dispatch_write_ssl(int fd, short event, void *humppa) } w = io_queued(io); - switch ((n = iobuf_write_ssl(&io->iobuf, (SSL*)io->ssl))) { + switch ((n = iobuf_write_tls(&io->iobuf, (SSL*)io->tls))) { case IOBUF_WANT_READ: - io_reset(io, EV_READ, io_dispatch_write_ssl); + io_reset(io, EV_READ, io_dispatch_write_tls); break; case IOBUF_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_write_ssl); + io_reset(io, EV_WRITE, io_dispatch_write_tls); break; case IOBUF_CLOSED: io_callback(io, IO_DISCONNECTED); @@ -1008,13 +1008,13 @@ io_dispatch_write_ssl(int fd, short event, void *humppa) errno = saved_errno; io_callback(io, IO_ERROR); break; - case IOBUF_SSLERROR: - io->error = io_ssl_error(); - ssl_error("io_dispatch_write_ssl:SSL_write"); + case IOBUF_TLSERROR: + io->error = io_tls_error(); + ssl_error("io_dispatch_write_tls:SSL_write"); io_callback(io, IO_ERROR); break; default: - io_debug("io_dispatch_write_ssl(...) -> w=%d\n", n); + io_debug("io_dispatch_write_tls(...) -> w=%d\n", n); w2 = io_queued(io); if (w > io->lowat && w2 <= io->lowat) io_callback(io, IO_LOWAT); @@ -1026,39 +1026,39 @@ io_dispatch_write_ssl(int fd, short event, void *humppa) } void -io_reload_ssl(struct io *io) +io_reload_tls(struct io *io) { short ev = 0; void (*dispatch)(int, short, void*) = NULL; switch (io->state) { - case IO_STATE_CONNECT_SSL: + case IO_STATE_CONNECT_TLS: ev = EV_WRITE; - dispatch = io_dispatch_connect_ssl; + dispatch = io_dispatch_connect_tls; break; - case IO_STATE_ACCEPT_SSL: + case IO_STATE_ACCEPT_TLS: ev = EV_READ; - dispatch = io_dispatch_accept_ssl; + dispatch = io_dispatch_accept_tls; break; case IO_STATE_UP: ev = 0; if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) { ev = EV_READ; - dispatch = io_dispatch_read_ssl; + dispatch = io_dispatch_read_tls; } else if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io)) { ev = EV_WRITE; - dispatch = io_dispatch_write_ssl; + dispatch = io_dispatch_write_tls; } if (!ev) return; /* paused */ break; default: - errx(1, "io_reload_ssl(): bad state"); + errx(1, "io_reload_tls(): bad state"); } io_reset(io, ev, dispatch); } -#endif /* IO_SSL */ +#endif /* IO_TLS */ diff --git a/smtpd/ioev.h b/smtpd/ioev.h index f1c39848..015340c2 100644 --- a/smtpd/ioev.h +++ b/smtpd/ioev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ioev.h,v 1.16 2016/11/30 17:43:32 eric Exp $ */ +/* $OpenBSD: ioev.h,v 1.17 2019/06/12 17:42:53 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -50,7 +50,7 @@ int io_start_tls(struct io *, void *); const char* io_strio(struct io *); const char* io_strevent(int); const char* io_error(struct io *); -void* io_ssl(struct io *); +void* io_tls(struct io *); int io_fileno(struct io *); int io_paused(struct io *, int); diff --git a/smtpd/mta_session.c b/smtpd/mta_session.c index 628b0ed1..4d78d740 100644 --- a/smtpd/mta_session.c +++ b/smtpd/mta_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta_session.c,v 1.115 2018/12/23 16:37:53 eric Exp $ */ +/* $OpenBSD: mta_session.c,v 1.116 2019/06/12 17:42:53 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -1105,7 +1105,7 @@ 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_ssl(s->io))); + s->id, ssl_to_text(io_tls(s->io))); s->flags |= MTA_TLS; mta_cert_verify(s); @@ -1514,7 +1514,7 @@ mta_cert_verify(struct mta_session *s) fallback = 1; } - if (cert_verify(io_ssl(s->io), name, fallback, mta_cert_verify_cb, s)) { + if (cert_verify(io_tls(s->io), name, fallback, mta_cert_verify_cb, s)) { tree_xset(&wait_ssl_verify, s->id, s); io_pause(s->io, IO_IN); s->flags |= MTA_WAIT; @@ -1551,7 +1551,7 @@ mta_tls_verified(struct mta_session *s) { X509 *x; - x = SSL_get_peer_certificate(io_ssl(s->io)); + x = SSL_get_peer_certificate(io_tls(s->io)); if (x) { log_info("smtp-out: Server certificate verification %s " "on session %016"PRIx64, diff --git a/smtpd/smtp_client.c b/smtpd/smtp_client.c index a6e70de5..ac707a12 100644 --- a/smtpd/smtp_client.c +++ b/smtpd/smtp_client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp_client.c,v 1.9 2019/05/14 12:08:54 eric Exp $ */ +/* $OpenBSD: smtp_client.c,v 1.10 2019/06/12 17:42:53 eric Exp $ */ /* * Copyright (c) 2018 Eric Faurot <eric@openbsd.org> @@ -619,7 +619,7 @@ smtp_client_io(struct io *io, int evt, void *arg) case IO_TLSREADY: proto->flags |= FLAG_TLS; io_pause(proto->io, IO_IN); - smtp_verify_server_cert(proto->tag, proto, io_ssl(proto->io)); + smtp_verify_server_cert(proto->tag, proto, io_tls(proto->io)); break; case IO_DATAIN: diff --git a/smtpd/smtp_session.c b/smtpd/smtp_session.c index e5063348..b14aaef6 100644 --- a/smtpd/smtp_session.c +++ b/smtpd/smtp_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp_session.c,v 1.390 2019/05/15 11:56:19 eric Exp $ */ +/* $OpenBSD: smtp_session.c,v 1.391 2019/06/12 17:42:53 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -1037,7 +1037,7 @@ smtp_tls_verified(struct smtp_session *s) { X509 *x; - x = SSL_get_peer_certificate(io_ssl(s->io)); + x = SSL_get_peer_certificate(io_tls(s->io)); if (x) { log_info("%016"PRIx64" smtp " "client-cert-check result=\"%s\"", @@ -1072,9 +1072,9 @@ smtp_io(struct io *io, int evt, void *arg) case IO_TLSREADY: log_info("%016"PRIx64" smtp tls ciphers=%s", - s->id, ssl_to_text(io_ssl(s->io))); + s->id, ssl_to_text(io_tls(s->io))); - report_smtp_link_tls("smtp-in", s->id, ssl_to_text(io_ssl(s->io))); + report_smtp_link_tls("smtp-in", s->id, ssl_to_text(io_tls(s->io))); s->flags |= SF_SECURE; s->helo[0] = '\0'; @@ -2246,7 +2246,7 @@ smtp_cert_verify(struct smtp_session *s) fallback = 1; } - if (cert_verify(io_ssl(s->io), name, fallback, smtp_cert_verify_cb, s)) { + 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); } @@ -2795,11 +2795,11 @@ smtp_message_begin(struct smtp_tx *tx) tx->msgid); if (s->flags & SF_SECURE) { - x = SSL_get_peer_certificate(io_ssl(s->io)); + x = SSL_get_peer_certificate(io_tls(s->io)); m_printf(tx, " (%s:%s:%d:%s)", - SSL_get_version(io_ssl(s->io)), - SSL_get_cipher_name(io_ssl(s->io)), - SSL_get_cipher_bits(io_ssl(s->io), NULL), + 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); diff --git a/smtpd/smtpd.c b/smtpd/smtpd.c index 56eadeca..40252e85 100644 --- a/smtpd/smtpd.c +++ b/smtpd/smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.c,v 1.318 2019/03/31 03:36:18 yasuoka Exp $ */ +/* $OpenBSD: smtpd.c,v 1.319 2019/06/05 06:40:13 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -2076,8 +2076,9 @@ imsg_to_str(int type) CASE(IMSG_FILTER_SMTP_DATA_BEGIN); CASE(IMSG_FILTER_SMTP_DATA_END); - CASE(IMSG_CA_PRIVENC); - CASE(IMSG_CA_PRIVDEC); + CASE(IMSG_CA_RSA_PRIVENC); + CASE(IMSG_CA_RSA_PRIVDEC); + CASE(IMSG_CA_ECDSA_SIGN); default: (void)snprintf(buf, sizeof(buf), "IMSG_??? (%d)", type); diff --git a/smtpd/smtpd.h b/smtpd/smtpd.h index 8631cba3..8914ec56 100644 --- a/smtpd/smtpd.h +++ b/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.621 2019/04/08 08:22:32 eric Exp $ */ +/* $OpenBSD: smtpd.h,v 1.622 2019/06/05 06:40:13 gilles Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -354,8 +354,9 @@ enum imsg_type { IMSG_FILTER_SMTP_DATA_BEGIN, IMSG_FILTER_SMTP_DATA_END, - IMSG_CA_PRIVENC, - IMSG_CA_PRIVDEC + IMSG_CA_RSA_PRIVENC, + IMSG_CA_RSA_PRIVDEC, + IMSG_CA_ECDSA_SIGN, }; enum smtp_proc_type { diff --git a/smtpd/ssl.c b/smtpd/ssl.c index 166160fa..76305020 100644 --- a/smtpd/ssl.c +++ b/smtpd/ssl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl.c,v 1.92 2019/05/24 16:29:41 gilles Exp $ */ +/* $OpenBSD: ssl.c,v 1.93 2019/06/05 06:40:13 gilles Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -41,6 +41,7 @@ #include <openssl/engine.h> #include <openssl/err.h> #include <openssl/rsa.h> +#include <openssl/ecdsa.h> #include <openssl/dh.h> #include <openssl/bn.h> @@ -363,6 +364,7 @@ ssl_load_pkey(const void *data, size_t datalen, char *buf, off_t len, X509 *x509 = NULL; EVP_PKEY *pkey = NULL; RSA *rsa = NULL; + EC_KEY *eckey = NULL; void *exdata = NULL; if ((in = BIO_new_mem_buf(buf, len)) == NULL) { @@ -385,15 +387,20 @@ ssl_load_pkey(const void *data, size_t datalen, char *buf, off_t len, in = NULL; if (data != NULL && datalen) { - if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL || + if (((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL && + (eckey = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) || (exdata = malloc(datalen)) == NULL) { SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_EVP_LIB); goto fail; } memcpy(exdata, data, datalen); - RSA_set_ex_data(rsa, 0, exdata); + if (rsa) + RSA_set_ex_data(rsa, 0, exdata); + if (eckey) + ECDSA_set_ex_data(eckey, 0, exdata); RSA_free(rsa); /* dereference, will be cleaned up with pkey */ + EC_KEY_free(eckey); /* dereference, will be cleaned up with pkey */ } *x509ptr = x509; @@ -403,6 +410,7 @@ ssl_load_pkey(const void *data, size_t datalen, char *buf, off_t len, fail: RSA_free(rsa); + EC_KEY_free(eckey); BIO_free(in); EVP_PKEY_free(pkey); X509_free(x509); |