summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/ca.c333
-rw-r--r--usr.sbin/smtpd/config.c28
-rw-r--r--usr.sbin/smtpd/lka.c15
-rw-r--r--usr.sbin/smtpd/mproc.c37
-rw-r--r--usr.sbin/smtpd/mta_session.c18
-rw-r--r--usr.sbin/smtpd/pony.c4
-rw-r--r--usr.sbin/smtpd/smtp.c4
-rw-r--r--usr.sbin/smtpd/smtp_session.c15
-rw-r--r--usr.sbin/smtpd/smtpd.c6
-rw-r--r--usr.sbin/smtpd/smtpd.h22
-rw-r--r--usr.sbin/smtpd/ssl.c99
-rw-r--r--usr.sbin/smtpd/ssl.h16
-rw-r--r--usr.sbin/smtpd/ssl_privsep.c33
-rw-r--r--usr.sbin/smtpd/ssl_smtpd.c6
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;