diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/smtpd/ca.c | 333 | ||||
-rw-r--r-- | usr.sbin/smtpd/config.c | 28 | ||||
-rw-r--r-- | usr.sbin/smtpd/lka.c | 15 | ||||
-rw-r--r-- | usr.sbin/smtpd/mproc.c | 37 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta_session.c | 18 | ||||
-rw-r--r-- | usr.sbin/smtpd/pony.c | 4 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp.c | 4 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp_session.c | 15 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.c | 6 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 22 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl.c | 99 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl.h | 16 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl_privsep.c | 33 | ||||
-rw-r--r-- | usr.sbin/smtpd/ssl_smtpd.c | 6 |
14 files changed, 538 insertions, 98 deletions
diff --git a/usr.sbin/smtpd/ca.c b/usr.sbin/smtpd/ca.c index 32fb84c00c5..36fbd22b9b7 100644 --- a/usr.sbin/smtpd/ca.c +++ b/usr.sbin/smtpd/ca.c @@ -1,6 +1,7 @@ -/* $OpenBSD: ca.c,v 1.3 2013/11/21 08:36:51 eric Exp $ */ +/* $OpenBSD: ca.c,v 1.4 2014/04/29 19:13:13 reyk Exp $ */ /* + * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org> * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> * * Permission to use, copy, modify, and distribute this software for any @@ -17,16 +18,75 @@ */ #include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> -#include <openssl/err.h> -#include <openssl/ssl.h> +#include <string.h> +#include <stdlib.h> +#include <imsg.h> +#include <openssl/pem.h> +#include <openssl/evp.h> +#include <openssl/rsa.h> +#include <openssl/engine.h> + +#include "smtpd.h" #include "log.h" +#include "ssl.h" + +static int ca_verify_cb(int, X509_STORE_CTX *); + +static int rsae_send_imsg(int, const u_char *, u_char *, RSA *, + int, u_int); +static int rsae_pub_enc(int, const u_char *, u_char *, RSA *, int); +static int rsae_pub_dec(int,const u_char *, u_char *, RSA *, int); +static int rsae_priv_enc(int, const u_char *, u_char *, RSA *, int); +static int rsae_priv_dec(int, const u_char *, u_char *, RSA *, int); +static int rsae_mod_exp(BIGNUM *, const BIGNUM *, RSA *, BN_CTX *); +static int rsae_bn_mod_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, BN_CTX *, BN_MONT_CTX *); +static int rsae_init(RSA *); +static int rsae_finish(RSA *); +static int rsae_sign(int, const u_char *, u_int, u_char *, u_int *, + const RSA *); +static int rsae_verify(int dtype, const u_char *m, u_int, const u_char *, + u_int, const RSA *); +static int rsae_keygen(RSA *, int, BIGNUM *, BN_GENCB *); + +void +ca_init(void) +{ + BIO *in = NULL; + EVP_PKEY *pkey = NULL; + struct pki *pki; + const char *k; + void *iter_dict; + + log_debug("debug: init private ssl-tree"); + 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"); -int ca_X509_verify(X509 *, STACK_OF(X509) *, const char *, const char *, const char **); + if ((pkey = PEM_read_bio_PrivateKey(in, + NULL, NULL, NULL)) == NULL) + fatalx("ca_launch: PEM"); + BIO_free(in); + + pki->pki_pkey = pkey; + + explicit_bzero(pki->pki_key, pki->pki_key_len); + free(pki->pki_key); + pki->pki_key = NULL; + } +} static int -verify_cb(int ok, X509_STORE_CTX *ctx) +ca_verify_cb(int ok, X509_STORE_CTX *ctx) { switch (X509_STORE_CTX_get_error(ctx)) { case X509_V_OK: @@ -50,7 +110,7 @@ verify_cb(int ok, X509_STORE_CTX *ctx) } int -ca_X509_verify(X509 *certificate, STACK_OF(X509) *chain, const char *CAfile, +ca_X509_verify(void *certificate, void *chain, const char *CAfile, const char *CRLfile, const char **errstr) { X509_STORE *store = NULL; @@ -72,7 +132,7 @@ ca_X509_verify(X509 *certificate, STACK_OF(X509) *chain, const char *CAfile, if (X509_STORE_CTX_init(xsc, store, certificate, chain) != 1) goto end; - X509_STORE_CTX_set_verify_cb(xsc, verify_cb); + X509_STORE_CTX_set_verify_cb(xsc, ca_verify_cb); ret = X509_verify_cert(xsc); @@ -92,3 +152,262 @@ end: return ret > 0 ? 1 : 0; } + +void +ca_imsg(struct mproc *p, struct imsg *imsg) +{ + RSA *rsa; + const void *from = NULL; + u_char *to = NULL; + struct msg m; + const char *pkiname; + size_t flen, tlen, padding; + struct pki *pki; + int ret = 0; + + m_msg(&m, imsg); + m_get_string(&m, &pkiname); + 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"); + + if ((to = calloc(1, tlen)) == NULL) + fatalx("ca_imsg: calloc"); + + switch (imsg->hdr.type) { + case IMSG_CA_PRIVENC: + ret = RSA_private_encrypt(flen, from, to, rsa, + padding); + break; + case IMSG_CA_PRIVDEC: + ret = RSA_private_decrypt(flen, from, to, rsa, + padding); + break; + } + + m_create(p, imsg->hdr.type, 0, 0, -1); + m_add_int(p, ret); + if (ret > 0) + m_add_data(p, to, (size_t)ret); + m_close(p); + + free(to); + RSA_free(rsa); +} + +/* + * RSA privsep engine (called from unprivileged processes) + */ + +const RSA_METHOD *rsa_default = NULL; + +static RSA_METHOD rsae_method = { + "RSA privsep engine", + rsae_pub_enc, + rsae_pub_dec, + rsae_priv_enc, + rsae_priv_dec, + rsae_mod_exp, + rsae_bn_mod_exp, + rsae_init, + rsae_finish, + 0, + NULL, + rsae_sign, + rsae_verify, + rsae_keygen +}; + +static int +rsae_send_imsg(int flen, const u_char *from, u_char *to, RSA *rsa, + int padding, u_int cmd) +{ + int ret = 0; + struct imsgbuf *ibuf; + struct imsg imsg; + int n, done = 0; + const void *toptr; + char *pkiname; + size_t tlen; + struct msg m; + + if ((pkiname = RSA_get_ex_data(rsa, 0)) == NULL) + return (0); + + /* + * Send a synchronous imsg because we cannot defer the RSA + * operation in OpenSSL's engine layer. + */ + m_create(p_lka, cmd, 0, 0, -1); + m_add_string(p_lka, pkiname); + m_add_data(p_lka, (const void *)from, (size_t)flen); + m_add_size(p_lka, (size_t)RSA_size(rsa)); + m_add_size(p_lka, (size_t)padding); + m_flush(p_lka); + + ibuf = &p_lka->imsgbuf; + + while (!done) { + if ((n = imsg_read(ibuf)) == -1) + 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; + if (imsg.hdr.type != cmd) + fatalx("invalid response"); + + m_msg(&m, &imsg); + m_get_int(&m, &ret); + if (ret > 0) + m_get_data(&m, &toptr, &tlen); + m_end(&m); + + if (ret > 0) + memcpy(to, toptr, tlen); + done = 1; + + imsg_free(&imsg); + } + } + mproc_event_add(p_lka); + + return (ret); +} + +static int +rsae_pub_enc(int flen,const u_char *from, u_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)); +} + +static int +rsae_pub_dec(int flen,const u_char *from, u_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)); +} + +static int +rsae_priv_enc(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + 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)); +} + +static int +rsae_priv_dec(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + 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)); +} + +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)); +} + +static int +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)); +} + +static int +rsae_init(RSA *rsa) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + if (rsa_default->init == NULL) + return (1); + return (rsa_default->init(rsa)); +} + +static int +rsae_finish(RSA *rsa) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + if (rsa_default->finish == NULL) + return (1); + return (rsa_default->finish(rsa)); +} + +static int +rsae_sign(int type, const u_char *m, u_int m_length, u_char *sigret, + u_int *siglen, const RSA *rsa) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + return (rsa_default->rsa_sign(type, m, m_length, + sigret, siglen, rsa)); +} + +static int +rsae_verify(int dtype, const u_char *m, u_int m_length, const u_char *sigbuf, + u_int siglen, const RSA *rsa) +{ + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + return (rsa_default->rsa_verify(dtype, m, m_length, + sigbuf, siglen, 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)); +} + +int +ca_engine_init(void) +{ + ENGINE *e; + + log_debug("debug: %s: %s", proc_name(smtpd_process), __func__); + + if ((e = ENGINE_get_default_RSA()) == NULL || + (rsa_default = ENGINE_get_RSA(e)) == NULL) + return (-1); + + if (rsa_default->flags & RSA_FLAG_SIGN_VER) + fatalx("unsupported RSA engine"); + + if (rsa_default->rsa_mod_exp == NULL) + rsae_method.rsa_mod_exp = NULL; + 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 (!ENGINE_set_RSA(e, &rsae_method) || + !ENGINE_set_default_RSA(e)) + return (-1); + + return (0); +} diff --git a/usr.sbin/smtpd/config.c b/usr.sbin/smtpd/config.c index 9eff839309a..10843ef56f7 100644 --- a/usr.sbin/smtpd/config.c +++ b/usr.sbin/smtpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.29 2014/04/29 10:18:06 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.30 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -46,6 +46,8 @@ purge_config(uint8_t what) struct table *t; struct rule *r; struct pki *p; + const char *k; + void *iter_dict; if (what & PURGE_LISTENERS) { while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) { @@ -72,13 +74,33 @@ purge_config(uint8_t what) if (what & PURGE_PKI) { while (dict_poproot(env->sc_pki_dict, (void **)&p)) { explicit_bzero(p->pki_cert, p->pki_cert_len); - explicit_bzero(p->pki_key, p->pki_key_len); free(p->pki_cert); - free(p->pki_key); + if (p->pki_key) { + explicit_bzero(p->pki_key, p->pki_key_len); + free(p->pki_key); + } + if (p->pki_pkey) + EVP_PKEY_free(p->pki_pkey); free(p); } free(env->sc_pki_dict); env->sc_pki_dict = NULL; + } else if (what & PURGE_PKI_KEYS) { + iter_dict = NULL; + while (dict_iter(env->sc_pki_dict, &iter_dict, &k, + (void **)&p)) { + explicit_bzero(p->pki_cert, p->pki_cert_len); + free(p->pki_cert); + p->pki_cert = NULL; + if (p->pki_key) { + explicit_bzero(p->pki_key, p->pki_key_len); + free(p->pki_key); + p->pki_key = NULL; + } + if (p->pki_pkey) + EVP_PKEY_free(p->pki_pkey); + p->pki_pkey = NULL; + } } } diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c index abfc4ba52fa..dc7f7852924 100644 --- a/usr.sbin/smtpd/lka.c +++ b/usr.sbin/smtpd/lka.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lka.c,v 1.167 2014/04/15 08:32:45 eric Exp $ */ +/* $OpenBSD: lka.c,v 1.168 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -91,6 +91,12 @@ lka_imsg(struct mproc *p, struct imsg *imsg) return; } + if (imsg->hdr.type == IMSG_CA_PRIVENC || + imsg->hdr.type == IMSG_CA_PRIVDEC) { + ca_imsg(p, imsg); + return; + } + if (p->proc == PROC_PONY) { switch (imsg->hdr.type) { case IMSG_SMTP_EXPAND_RCPT: @@ -134,13 +140,10 @@ lka_imsg(struct mproc *p, struct imsg *imsg) } resp_ca_cert.status = CA_OK; resp_ca_cert.cert_len = pki->pki_cert_len; - resp_ca_cert.key_len = pki->pki_key_len; iov[0].iov_base = &resp_ca_cert; iov[0].iov_len = sizeof(resp_ca_cert); iov[1].iov_base = pki->pki_cert; iov[1].iov_len = pki->pki_cert_len; - iov[2].iov_base = pki->pki_key; - iov[2].iov_len = pki->pki_key_len; m_composev(p, IMSG_SMTP_SSL_INIT, 0, 0, -1, iov, nitems(iov)); return; @@ -256,13 +259,10 @@ lka_imsg(struct mproc *p, struct imsg *imsg) } resp_ca_cert.status = CA_OK; resp_ca_cert.cert_len = pki->pki_cert_len; - resp_ca_cert.key_len = pki->pki_key_len; iov[0].iov_base = &resp_ca_cert; iov[0].iov_len = sizeof(resp_ca_cert); iov[1].iov_base = pki->pki_cert; iov[1].iov_len = pki->pki_cert_len; - iov[2].iov_base = pki->pki_key; - iov[2].iov_len = pki->pki_key_len; m_composev(p, IMSG_MTA_SSL_INIT, 0, 0, -1, iov, nitems(iov)); return; @@ -389,6 +389,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) if (verbose & TRACE_TABLES) table_dump_all(); table_open_all(); + ca_init(); /* Start fulfilling requests */ mproc_enable(p_pony); diff --git a/usr.sbin/smtpd/mproc.c b/usr.sbin/smtpd/mproc.c index a5223d61e0c..50e484fd9c6 100644 --- a/usr.sbin/smtpd/mproc.c +++ b/usr.sbin/smtpd/mproc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mproc.c,v 1.8 2014/04/19 17:45:05 gilles Exp $ */ +/* $OpenBSD: mproc.c,v 1.9 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@faurot.net> @@ -38,7 +38,6 @@ #include "smtpd.h" #include "log.h" -static void mproc_event_add(struct mproc *); static void mproc_dispatch(int, short, void *); static ssize_t msgbuf_write2(struct msgbuf *); @@ -117,7 +116,7 @@ mproc_disable(struct mproc *p) mproc_event_add(p); } -static void +void mproc_event_add(struct mproc *p) { short events; @@ -417,6 +416,25 @@ m_close(struct mproc *p) mproc_event_add(p); } +void +m_flush(struct mproc *p) +{ + if (imsg_compose(&p->imsgbuf, p->m_type, p->m_peerid, p->m_pid, p->m_fd, + p->m_buf, p->m_pos) == -1) + fatal("imsg_compose"); + + log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s (flush)", + proc_name(smtpd_process), + proc_name(p->proc), + p->m_pos, + imsg_to_str(p->m_type)); + + p->msg_out += 1; + p->m_pos = 0; + + imsg_flush(&p->imsgbuf); +} + static struct imsg * current; static void @@ -505,6 +523,7 @@ m_add_typed_sized(struct mproc *p, uint8_t type, const void *data, size_t len) enum { M_INT, M_UINT32, + M_SIZET, M_TIME, M_STRING, M_DATA, @@ -529,6 +548,12 @@ m_add_u32(struct mproc *m, uint32_t u32) }; void +m_add_size(struct mproc *m, size_t sz) +{ + m_add_typed(m, M_SIZET, &sz, sizeof sz); +}; + +void m_add_time(struct mproc *m, time_t v) { m_add_typed(m, M_TIME, &v, sizeof v); @@ -605,6 +630,12 @@ m_get_u32(struct msg *m, uint32_t *u32) } void +m_get_size(struct msg *m, size_t *sz) +{ + m_get_typed(m, M_SIZET, sz, sizeof(*sz)); +} + +void m_get_time(struct msg *m, time_t *t) { m_get_typed(m, M_TIME, t, sizeof(*t)); diff --git a/usr.sbin/smtpd/mta_session.c b/usr.sbin/smtpd/mta_session.c index 0be56d71cbb..e3b43b7f50e 100644 --- a/usr.sbin/smtpd/mta_session.c +++ b/usr.sbin/smtpd/mta_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta_session.c,v 1.62 2014/04/29 17:32:42 gilles Exp $ */ +/* $OpenBSD: mta_session.c,v 1.63 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -253,6 +253,7 @@ mta_session_imsg(struct mproc *p, struct imsg *imsg) const char *name; void *ssl; int dnserror, status; + char *pkiname; switch (imsg->hdr.type) { @@ -328,7 +329,7 @@ mta_session_imsg(struct mproc *p, struct imsg *imsg) return; } else { - ssl = ssl_mta_init(NULL, 0, NULL, 0); + ssl = ssl_mta_init(NULL, NULL, 0); if (ssl == NULL) fatal("mta: ssl_mta_init"); io_start_tls(&s->io, ssl); @@ -339,19 +340,18 @@ mta_session_imsg(struct mproc *p, struct imsg *imsg) resp_ca_cert = xmemdup(imsg->data, sizeof *resp_ca_cert, "mta:ca_cert"); resp_ca_cert->cert = xstrdup((char *)imsg->data + sizeof *resp_ca_cert, "mta:ca_cert"); - resp_ca_cert->key = xstrdup((char *)imsg->data + - sizeof *resp_ca_cert + resp_ca_cert->cert_len, - "mta:ca_key"); - ssl = ssl_mta_init(resp_ca_cert->cert, resp_ca_cert->cert_len, - resp_ca_cert->key, resp_ca_cert->key_len); + if (s->relay->pki_name) + pkiname = s->relay->pki_name; + else + pkiname = s->helo; + ssl = ssl_mta_init(pkiname, + resp_ca_cert->cert, resp_ca_cert->cert_len); if (ssl == NULL) fatal("mta: ssl_mta_init"); io_start_tls(&s->io, ssl); explicit_bzero(resp_ca_cert->cert, resp_ca_cert->cert_len); - explicit_bzero(resp_ca_cert->key, resp_ca_cert->key_len); free(resp_ca_cert->cert); - free(resp_ca_cert->key); free(resp_ca_cert); return; diff --git a/usr.sbin/smtpd/pony.c b/usr.sbin/smtpd/pony.c index cd8b353662e..2b3e59226ed 100644 --- a/usr.sbin/smtpd/pony.c +++ b/usr.sbin/smtpd/pony.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pony.c,v 1.2 2014/04/09 18:55:19 eric Exp $ */ +/* $OpenBSD: pony.c,v 1.3 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2014 Gilles Chehade <gilles@poolp.org> @@ -213,6 +213,8 @@ pony(void) config_peer(PROC_CONTROL); config_done(); + ca_engine_init(); + if (event_dispatch() < 0) fatal("event_dispatch"); pony_shutdown(); diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c index 5c673888ddb..5ecb84b53e1 100644 --- a/usr.sbin/smtpd/smtp.c +++ b/usr.sbin/smtpd/smtp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp.c,v 1.136 2014/04/19 13:52:49 gilles Exp $ */ +/* $OpenBSD: smtp.c,v 1.137 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -209,7 +209,7 @@ smtp_setup_events(void) dict_xset(env->sc_ssl_dict, k, ssl_ctx); } - purge_config(PURGE_PKI); + purge_config(PURGE_PKI_KEYS); log_debug("debug: smtp: will accept at most %d clients", (getdtablesize() - getdtablecount())/2 - SMTP_FD_RESERVE); diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c index 1fb2ff7b3d7..ad1842fae84 100644 --- a/usr.sbin/smtpd/smtp_session.c +++ b/usr.sbin/smtpd/smtp_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp_session.c,v 1.209 2014/04/29 12:18:27 reyk Exp $ */ +/* $OpenBSD: smtp_session.c,v 1.210 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -295,6 +295,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) struct smtp_session *s; struct smtp_rcpt *rcpt; void *ssl; + char *pkiname; char user[SMTPD_MAXLOGNAME]; struct msg m; const char *line, *helo; @@ -584,24 +585,18 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) fatal(NULL); resp_ca_cert->cert = xstrdup((char *)imsg->data + sizeof *resp_ca_cert, "smtp:ca_cert"); - - resp_ca_cert->key = xstrdup((char *)imsg->data + - sizeof *resp_ca_cert + resp_ca_cert->cert_len, - "smtp:ca_key"); - if (s->listener->pki_name[0]) - ssl_ctx = dict_get(env->sc_ssl_dict, s->listener->pki_name); + pkiname = s->listener->pki_name; else - ssl_ctx = dict_get(env->sc_ssl_dict, s->smtpname); + pkiname = s->smtpname; + ssl_ctx = dict_get(env->sc_ssl_dict, pkiname); ssl = ssl_smtp_init(ssl_ctx, smtp_sni_callback, s); io_set_read(&s->io); io_start_tls(&s->io, ssl); explicit_bzero(resp_ca_cert->cert, resp_ca_cert->cert_len); - explicit_bzero(resp_ca_cert->key, resp_ca_cert->key_len); free(resp_ca_cert->cert); - free(resp_ca_cert->key); free(resp_ca_cert); return; diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c index 6e4c34835ef..8abf47dda7e 100644 --- a/usr.sbin/smtpd/smtpd.c +++ b/usr.sbin/smtpd/smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.c,v 1.222 2014/04/29 10:18:06 reyk Exp $ */ +/* $OpenBSD: smtpd.c,v 1.223 2014/04/29 19:13:13 reyk Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -47,6 +47,7 @@ #include <util.h> #include <openssl/ssl.h> +#include <openssl/evp.h> #include "smtpd.h" #include "log.h" @@ -1378,6 +1379,9 @@ imsg_to_str(int type) CASE(IMSG_SMTP_EVENT_COMMIT); CASE(IMSG_SMTP_EVENT_ROLLBACK); CASE(IMSG_SMTP_EVENT_DISCONNECT); + + CASE(IMSG_CA_PRIVENC); + CASE(IMSG_CA_PRIVDEC); default: (void)snprintf(buf, sizeof(buf), "IMSG_??? (%d)", type); diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 6ef7ca9e010..670a470a3c7 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.456 2014/04/29 12:18:27 reyk Exp $ */ +/* $OpenBSD: smtpd.h,v 1.457 2014/04/29 19:13:14 reyk Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -284,6 +284,9 @@ enum imsg_type { IMSG_SMTP_EVENT_COMMIT, IMSG_SMTP_EVENT_ROLLBACK, IMSG_SMTP_EVENT_DISCONNECT, + + IMSG_CA_PRIVENC, + IMSG_CA_PRIVDEC }; enum blockmodes { @@ -1032,8 +1035,6 @@ struct ca_cert_resp_msg { enum ca_resp_status status; char *cert; off_t cert_len; - char *key; - off_t key_len; }; struct ca_vrfy_req_msg { @@ -1070,8 +1071,10 @@ void bounce_fd(int); /* ca.c */ -int ca_X509_verify(void *, void *, const char *, const char *, const char **); - +int ca_X509_verify(void *, void *, const char *, const char *, const char **); +void ca_imsg(struct mproc *, struct imsg *); +void ca_init(void); +int ca_engine_init(void); /* compress_backend.c */ struct compress_backend *compress_backend_lookup(const char *); @@ -1085,7 +1088,8 @@ int uncompress_file(FILE *, FILE *); #define PURGE_TABLES 0x02 #define PURGE_RULES 0x04 #define PURGE_PKI 0x08 -#define PURGE_EVERYTHING 0xff +#define PURGE_PKI_KEYS 0x10 +#define PURGE_EVERYTHING 0x0f void purge_config(uint8_t); void init_pipes(void); void config_process(enum smtp_proc_type); @@ -1197,6 +1201,7 @@ void mproc_init(struct mproc *, int); void mproc_clear(struct mproc *); void mproc_enable(struct mproc *); void mproc_disable(struct mproc *); +void mproc_event_add(struct mproc *); void m_compose(struct mproc *, uint32_t, uint32_t, pid_t, int, void *, size_t); void m_composev(struct mproc *, uint32_t, uint32_t, pid_t, int, const struct iovec *, int); @@ -1205,6 +1210,7 @@ void m_create(struct mproc *, uint32_t, uint32_t, pid_t, int); void m_add(struct mproc *, const void *, size_t); void m_add_int(struct mproc *, int); void m_add_u32(struct mproc *, uint32_t); +void m_add_size(struct mproc *, size_t); void m_add_time(struct mproc *, time_t); void m_add_string(struct mproc *, const char *); void m_add_data(struct mproc *, const void *, size_t); @@ -1215,11 +1221,13 @@ void m_add_sockaddr(struct mproc *, const struct sockaddr *); void m_add_mailaddr(struct mproc *, const struct mailaddr *); void m_add_envelope(struct mproc *, const struct envelope *); void m_close(struct mproc *); +void m_flush(struct mproc *); void m_msg(struct msg *, struct imsg *); int m_is_eom(struct msg *); void m_end(struct msg *); void m_get_int(struct msg *, int *); +void m_get_size(struct msg *, size_t *); void m_get_u32(struct msg *, uint32_t *); void m_get_time(struct msg *, time_t *); void m_get_string(struct msg *, const char **); @@ -1320,7 +1328,7 @@ const char *imsg_to_str(int); /* ssl_smtpd.c */ -void *ssl_mta_init(char *, off_t, char *, off_t); +void *ssl_mta_init(void *, char *, off_t); void *ssl_smtp_init(void *, void *, void *); diff --git a/usr.sbin/smtpd/ssl.c b/usr.sbin/smtpd/ssl.c index b636ae0fd38..4387e790dcd 100644 --- a/usr.sbin/smtpd/ssl.c +++ b/usr.sbin/smtpd/ssl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl.c,v 1.62 2014/04/29 10:08:55 reyk Exp $ */ +/* $OpenBSD: ssl.c,v 1.63 2014/04/29 19:13:14 reyk Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -67,8 +67,7 @@ ssl_setup(SSL_CTX **ctxp, struct pki *pki) DH *dh; SSL_CTX *ctx; - ctx = ssl_ctx_create(pki->pki_cert, pki->pki_cert_len, - pki->pki_key, pki->pki_key_len); + ctx = ssl_ctx_create(pki->pki_name, pki->pki_cert, pki->pki_cert_len); if (!SSL_CTX_set_session_id_context(ctx, (const unsigned char *)pki->pki_name, @@ -243,7 +242,7 @@ fail: } SSL_CTX * -ssl_ctx_create(char *cert, off_t cert_len, char *key, off_t key_len) +ssl_ctx_create(void *pkiname, char *cert, off_t cert_len) { SSL_CTX *ctx; @@ -265,13 +264,14 @@ ssl_ctx_create(char *cert, off_t cert_len, char *key, off_t key_len) fatal("ssl_ctx_create: could not set cipher list"); } - if (cert != NULL && key != NULL) { + if (cert != NULL) { if (!ssl_ctx_use_certificate_chain(ctx, cert, cert_len)) { ssl_error("ssl_ctx_create"); fatal("ssl_ctx_create: invalid certificate chain"); - } else if (!ssl_ctx_use_private_key(ctx, key, key_len)) { + } else if (!ssl_ctx_fake_private_key(ctx, + pkiname, cert, cert_len)) { ssl_error("ssl_ctx_create"); - fatal("ssl_ctx_create: could not use private key"); + fatal("ssl_ctx_create: could not fake private key"); } else if (!SSL_CTX_check_private_key(ctx)) { ssl_error("ssl_ctx_create"); fatal("ssl_ctx_create: invalid private key"); @@ -453,3 +453,88 @@ ssl_set_ecdh_curve(SSL_CTX *ctx, const char *curve) SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); EC_KEY_free(ecdh); } + +int +ssl_ctx_load_pkey(SSL_CTX *ctx, void *data, char *buf, off_t len, + X509 **x509ptr, EVP_PKEY **pkeyptr) +{ + int ret = 0; + BIO *in; + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + + if ((in = BIO_new_mem_buf(buf, len)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_BUF_LIB); + return (0); + } + + if ((x509 = PEM_read_bio_X509(in, NULL, + ssl_getpass_cb, NULL)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PEM_LIB); + goto fail; + } + + if ((pkey = X509_get_pubkey(x509)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_X509_LIB); + goto fail; + } + + if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_EVP_LIB); + goto fail; + } + + if (data) + RSA_set_ex_data(rsa, 0, data); + + *x509ptr = x509; + *pkeyptr = pkey; + ret = 1; + + goto done; + + fail: + ssl_error("ssl_ctx_load_pkey"); + + if (pkey != NULL) + EVP_PKEY_free(pkey); + if (x509 != NULL) + X509_free(x509); + + done: + if (in != NULL) + BIO_free(in); + + return ret; +} + +int +ssl_ctx_fake_private_key(SSL_CTX *ctx, void *data, char *buf, off_t len) +{ + int ret = 0; + EVP_PKEY *pkey = NULL; + X509 *x509 = NULL; + + if (!ssl_ctx_load_pkey(ctx, data, buf, len, &x509, &pkey)) + return (0); + + /* + * Use the public key as the "private" key - the secret key + * parameters are hidden in an extra process that will be + * contacted by the RSA engine. The SSL/TLS library needs at + * least the public key parameters in the current process. + */ + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + if (!ret) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_SSL_LIB); + ssl_error("ssl_ctx_fake_private_key"); + } + + if (pkey != NULL) + EVP_PKEY_free(pkey); + if (x509 != NULL) + X509_free(x509); + + return (ret); +} diff --git a/usr.sbin/smtpd/ssl.h b/usr.sbin/smtpd/ssl.h index eb4e65f0550..c2df38a66ab 100644 --- a/usr.sbin/smtpd/ssl.h +++ b/usr.sbin/smtpd/ssl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl.h,v 1.6 2014/04/29 10:08:55 reyk Exp $ */ +/* $OpenBSD: ssl.h,v 1.7 2014/04/29 19:13:14 reyk Exp $ */ /* * Copyright (c) 2013 Gilles Chehade <gilles@poolp.org> * @@ -34,6 +34,8 @@ struct pki { char *pki_key; off_t pki_key_len; + EVP_PKEY *pki_pkey; + char *pki_dhparams_file; char *pki_dhparams; off_t pki_dhparams_len; @@ -42,7 +44,7 @@ struct pki { /* ssl.c */ void ssl_init(void); int ssl_setup(SSL_CTX **, struct pki *); -SSL_CTX *ssl_ctx_create(char *, off_t, char *, off_t); +SSL_CTX *ssl_ctx_create(void *, char *, off_t); int ssl_cmp(struct pki *, struct pki *); DH *get_dh1024(void); DH *get_dh_from_memory(char *, size_t); @@ -60,9 +62,11 @@ int ssl_load_keyfile(struct pki *, const char *, const char *); int ssl_load_cafile(struct pki *, const char *); int ssl_load_dhparams(struct pki *, const char *); +int ssl_ctx_load_pkey(SSL_CTX *, void *, char *, off_t, + X509 **, EVP_PKEY **); +int ssl_ctx_fake_private_key(SSL_CTX *, void *, char *, off_t); /* ssl_privsep.c */ -int ssl_ctx_use_private_key(SSL_CTX *, char *, off_t); -int ssl_ctx_use_certificate_chain(SSL_CTX *, char *, off_t); -int ssl_ctx_load_verify_memory(SSL_CTX *, char *, off_t); -int ssl_by_mem_ctrl(X509_LOOKUP *, int, const char *, long, char **); +int ssl_ctx_use_certificate_chain(SSL_CTX *, char *, off_t); +int ssl_ctx_load_verify_memory(SSL_CTX *, char *, off_t); +int ssl_by_mem_ctrl(X509_LOOKUP *, int, const char *, long, char **); diff --git a/usr.sbin/smtpd/ssl_privsep.c b/usr.sbin/smtpd/ssl_privsep.c index e53fb4f418e..66dd0c9b5f0 100644 --- a/usr.sbin/smtpd/ssl_privsep.c +++ b/usr.sbin/smtpd/ssl_privsep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_privsep.c,v 1.6 2014/02/04 13:44:41 eric Exp $ */ +/* $OpenBSD: ssl_privsep.c,v 1.7 2014/04/29 19:13:14 reyk Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. @@ -97,37 +97,6 @@ X509_LOOKUP_METHOD x509_mem_lookup = { #define X509_L_ADD_MEM 3 int -ssl_ctx_use_private_key(SSL_CTX *ctx, char *buf, off_t len) -{ - int ret; - BIO *in; - EVP_PKEY *pkey; - - ret = 0; - - if ((in = BIO_new_mem_buf(buf, len)) == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB); - return 0; - } - - pkey = PEM_read_bio_PrivateKey(in, NULL, - ctx->default_passwd_callback, - ctx->default_passwd_callback_userdata); - - if (pkey == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB); - goto end; - } - ret = SSL_CTX_use_PrivateKey(ctx, pkey); - EVP_PKEY_free(pkey); -end: - if (in != NULL) - BIO_free(in); - return ret; -} - - -int ssl_ctx_use_certificate_chain(SSL_CTX *ctx, char *buf, off_t len) { int ret; diff --git a/usr.sbin/smtpd/ssl_smtpd.c b/usr.sbin/smtpd/ssl_smtpd.c index 49326b3a4f3..d7181bda243 100644 --- a/usr.sbin/smtpd/ssl_smtpd.c +++ b/usr.sbin/smtpd/ssl_smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_smtpd.c,v 1.6 2014/04/29 12:18:27 reyk Exp $ */ +/* $OpenBSD: ssl_smtpd.c,v 1.7 2014/04/29 19:13:14 reyk Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -44,12 +44,12 @@ void * -ssl_mta_init(char *cert, off_t cert_len, char *key, off_t key_len) +ssl_mta_init(void *pkiname, char *cert, off_t cert_len) { SSL_CTX *ctx = NULL; SSL *ssl = NULL; - ctx = ssl_ctx_create(cert, cert_len, key, key_len); + ctx = ssl_ctx_create(pkiname, cert, cert_len); if ((ssl = SSL_new(ctx)) == NULL) goto err; |