Hi,
relayd uses privsep to mitigate the risk of potential attacks.
OpenSSL's SSL code wasn't designed with privsep in mind. We already
have a hack to load the keys and certificates in the parent process
and to send them via imsg to the chroot'ed relays; OpenSSL normally
wants to load them from files.
This diff goes a bit further by moving the private keys to a new
separate process instead of copying them to the relays. A custom RSA
engine is used by the SSL/TLS code of the relay processes to send RSA
private key encryption/decryption requests to the new "ca" process (I
used the name "ca" because something similar exists in iked) instead
of operating on the private key directly.
The diff is still experimental, misses support for the SSL inspection,
probably client mode and hasn't been tested very well. The following
configuration has been tested:
relay wwwssl {
listen on $ext_addr port 443 ssl
forward to 127.0.0.1 port 80
}
It may impact performance because it adds a little for the RSA
communication between the processes, but SSL only does it once to get
the session keys and RSA is already slow.
I would like to get some first thoughts / feedback.
Reyk
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/Makefile,v
retrieving revision 1.24
diff -u -p -u -p -r1.24 Makefile
--- Makefile 18 Jan 2014 05:54:51 -0000 1.24
+++ Makefile 9 Apr 2014 14:02:37 -0000
@@ -1,10 +1,12 @@
# $OpenBSD: Makefile,v 1.24 2014/01/18 05:54:51 martynas Exp $
PROG= relayd
-SRCS= parse.y log.c control.c ssl.c ssl_privsep.c \
- relayd.c pfe.c pfe_filter.c pfe_route.c hce.c relay.c \
- relay_http.c relay_udp.c carp.c check_icmp.c check_tcp.c \
- check_script.c name2id.c snmp.c shuffle.c proc.c config.c
+SRCS= parse.y
+SRCS+= ca.c carp.c check_icmp.c check_script.c check_tcp.c \
+ config.c control.c hce.c log.c name2id.c \
+ pfe.c pfe_filter.c pfe_route.c proc.c \
+ relay.c relay_http.c relay_udp.c relayd.c \
+ shuffle.c snmp.c ssl.c ssl_privsep.c
MAN= relayd.8 relayd.conf.5
LDADD= -levent -lssl -lcrypto -lutil
Index: ca.c
===================================================================
RCS file: ca.c
diff -N ca.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ca.c 9 Apr 2014 14:02:37 -0000
@@ -0,0 +1,414 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2014 Reyk Floeter <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <limits.h>
+#include <event.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+
+#include "relayd.h"
+
+void ca_init(struct privsep *, struct privsep_proc *p, void *);
+
+int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *);
+int ca_dispatch_relay(int, struct privsep_proc *, struct imsg *);
+
+int rsae_pub_enc(int, const u_char *, u_char *, RSA *, int);
+int rsae_pub_dec(int,const u_char *, u_char *, RSA *, int);
+int rsae_priv_enc(int, const u_char *, u_char *, RSA *, int);
+int rsae_priv_dec(int, const u_char *, u_char *, RSA *, int);
+int rsae_mod_exp(BIGNUM *, const BIGNUM *, RSA *, BN_CTX *);
+int rsae_bn_mod_exp(BIGNUM *, const BIGNUM *, const BIGNUM *,
+ const BIGNUM *, BN_CTX *, BN_MONT_CTX *);
+int rsae_init(RSA *);
+int rsae_finish(RSA *);
+int rsae_sign(int, const u_char *, u_int,
+ u_char *, u_int *, const RSA *);
+int rsae_verify(int dtype, const u_char *m, u_int,
+ const u_char *, u_int, const RSA *);
+int rsae_keygen(RSA *, int, BIGNUM *, BN_GENCB *);
+
+static struct relayd *env = NULL;
+extern int proc_id;
+
+static struct privsep_proc procs[] = {
+ { "parent", PROC_PARENT, ca_dispatch_parent },
+ { "relay", PROC_RELAY, ca_dispatch_relay },
+};
+
+pid_t
+ca(struct privsep *ps, struct privsep_proc *p)
+{
+ env = ps->ps_env;
+
+ return (proc_run(ps, p, procs, nitems(procs), ca_init, NULL));
+}
+
+void
+ca_init(struct privsep *ps, struct privsep_proc *p, void *arg)
+{
+ if (config_init(ps->ps_env) == -1)
+ fatal("failed to initialize configuration");
+
+ env->sc_id = getpid() & 0xffff;
+}
+
+int
+ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+ switch (imsg->hdr.type) {
+ case IMSG_CFG_RELAY:
+ config_getrelay(env, imsg);
+ break;
+ case IMSG_CFG_DONE:
+ config_getcfg(env, imsg);
+ break;
+ case IMSG_CTL_START:
+ break;
+ case IMSG_CTL_RESET:
+ config_getreset(env, imsg);
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+static EVP_PKEY *
+ca_get_key(objid_t id)
+{
+ BIO *in = NULL;
+ EVP_PKEY *pkey = NULL;
+ struct relay *rlay;
+
+ if ((rlay = relay_find(env, id)) == NULL)
+ goto end;
+
+ if ((in = BIO_new_mem_buf(rlay->rl_ssl_key,
+ rlay->rl_conf.ssl_key_len)) == NULL)
+ goto end;
+
+ if ((pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL)) == NULL)
+ goto end;
+
+end:
+ if (in != NULL)
+ BIO_free(in);
+
+ return (pkey);
+}
+
+int
+ca_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+ struct ctl_keyop cko;
+ EVP_PKEY *pkey;
+ RSA *rsa;
+ u_char *from = NULL, *to = NULL;
+ struct iovec iov[2];
+ int c = 0;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CA_PRIVENC:
+ case IMSG_CA_PRIVDEC:
+ IMSG_SIZE_CHECK(imsg, (&cko));
+ bcopy(imsg->data, &cko, sizeof(cko));
+ if (cko.cko_proc > env->sc_prefork_relay)
+ fatalx("ca_dispatch_relay: "
+ "invalid relay proc");
+ if (IMSG_DATA_SIZE(imsg) != (sizeof(cko) + cko.cko_flen))
+ fatalx("ca_dispatch_relay: "
+ "invalid key operation");
+ if ((pkey = ca_get_key(cko.cko_id)) == NULL ||
+ (rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+ fatalx("ca_dispatch_relay: "
+ "invalid relay key or id");
+
+ from = (u_char *)imsg->data + sizeof(cko);
+ if ((to = calloc(1, cko.cko_tlen)) == NULL)
+ fatalx("ca_dispatch_relay: calloc");
+
+ switch (imsg->hdr.type) {
+ case IMSG_CA_PRIVENC:
+ cko.cko_tlen = RSA_private_encrypt(cko.cko_flen,
+ from, to, rsa, cko.cko_padding);
+ break;
+ case IMSG_CA_PRIVDEC:
+ cko.cko_tlen = RSA_private_decrypt(cko.cko_flen,
+ from, to, rsa, cko.cko_padding);
+ break;
+ }
+
+ iov[c].iov_base = &cko;
+ iov[c++].iov_len = sizeof(cko);
+ if (cko.cko_tlen) {
+ iov[c].iov_base = to;
+ iov[c++].iov_len = cko.cko_tlen;
+ }
+
+ proc_composev_imsg(env->sc_ps, PROC_RELAY, cko.cko_proc,
+ imsg->hdr.type, -1, iov, c);
+
+ if (to != NULL)
+ free(to);
+ EVP_PKEY_free(pkey);
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * 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, int cmd)
+{
+ struct ctl_keyop cko;
+ int ret = 0;
+ u_int32_t *id;
+ struct iovec iov[2];
+ struct imsgbuf *ibuf;
+ struct imsgev *iev;
+ struct imsg imsg;
+ int n, done = 0;
+ u_char *toptr;
+
+ if ((id = RSA_get_app_data(rsa)) == NULL)
+ return (0);
+
+ iev = proc_iev(env->sc_ps, PROC_CA, -1);
+ ibuf = &iev->ibuf;
+
+ /*
+ * XXX this could be nicer...
+ */
+
+ cko.cko_id = *id;
+ cko.cko_proc = proc_id;
+ cko.cko_flen = flen;
+ cko.cko_tlen = RSA_size(rsa);
+ cko.cko_padding = padding;
+
+ iov[0].iov_base = &cko;
+ iov[0].iov_len = sizeof(cko);
+ iov[1].iov_base = from;
+ iov[1].iov_len = flen;
+
+ /*
+ * Send a synchronous imsg because we cannot defer the RSA
+ * operation in OpenSSL's engine layer.
+ */
+ imsg_composev(ibuf, cmd, 0, 0, -1, iov, 2);
+ imsg_flush(ibuf);
+
+ 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");
+
+ IMSG_SIZE_CHECK(&imsg, (&cko));
+ memcpy(&cko, imsg.data, sizeof(cko));
+ if (IMSG_DATA_SIZE(&imsg) !=
+ (sizeof(cko) + cko.cko_tlen))
+ fatalx("data size");
+
+ ret = cko.cko_tlen;
+ if (ret) {
+ toptr = (u_char *)imsg.data + sizeof(cko);
+ memcpy(to, toptr, ret);
+ }
+ done = 1;
+
+ imsg_free(&imsg);
+ }
+ }
+ imsg_event_add(iev);
+
+ return (ret);
+}
+
+int
+rsae_pub_enc(int flen,const u_char *from,
+ u_char *to, RSA *rsa,int padding)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsa_default->rsa_pub_enc(flen, from, to, rsa, padding));
+}
+
+int
+rsae_pub_dec(int flen,const u_char *from, u_char
+ *to, RSA *rsa,int padding)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsa_default->rsa_pub_dec(flen, from, to, rsa, padding));
+}
+
+int
+rsae_priv_enc(int flen, const u_char *from, u_char *to,
+ RSA *rsa, int padding)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsae_send_imsg(flen, from, to, rsa, padding,
+ IMSG_CA_PRIVENC));
+}
+
+int
+rsae_priv_dec(int flen, const u_char *from, u_char *to,
+ RSA *rsa, int padding)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsae_send_imsg(flen, from, to, rsa, padding,
+ IMSG_CA_PRIVDEC));
+}
+
+int
+rsae_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsa_default->rsa_mod_exp(r0, I, rsa, ctx));
+}
+
+int
+rsae_bn_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const
+ BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsa_default->bn_mod_exp(r, a, p, m, ctx, m_ctx));
+}
+
+int
+rsae_init(RSA *rsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ if (rsa_default->init == NULL)
+ return (1);
+ return (rsa_default->init(rsa));
+}
+
+int
+rsae_finish(RSA *rsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ if (rsa_default->finish == NULL)
+ return (1);
+ return (rsa_default->finish(rsa));
+}
+
+int
+rsae_sign(int type, const u_char *m, u_int
+ m_length, u_char *sigret, u_int *siglen, const RSA *rsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsa_default->rsa_sign(type, m, m_length, sigret, siglen, rsa));
+}
+
+int
+rsae_verify(int dtype, const u_char *m, u_int m_length,
+ const u_char *sigbuf, u_int siglen, const RSA *rsa)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsa_default->rsa_verify(dtype, m, m_length, sigbuf, siglen,
rsa));
+}
+
+int
+rsae_keygen(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb)
+{
+ DPRINTF("%s:%d", __func__, __LINE__);
+ return (rsa_default->rsa_keygen(rsa, bits, e, cb));
+}
+
+int
+ca_engine_init(struct relayd *x_env)
+{
+ ENGINE *e;
+
+ if (env == NULL)
+ env = x_env;
+
+ if ((e = ENGINE_get_default_RSA()) == NULL ||
+ (rsa_default = ENGINE_get_RSA(e)) == NULL)
+ return (-1);
+
+ 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);
+}
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/config.c,v
retrieving revision 1.11
diff -u -p -u -p -r1.11 config.c
--- config.c 24 Feb 2014 06:55:11 -0000 1.11
+++ config.c 9 Apr 2014 14:02:38 -0000
@@ -1,7 +1,7 @@
/* $OpenBSD: config.c,v 1.11 2014/02/24 06:55:11 jsg Exp $ */
/*
- * Copyright (c) 2011 Reyk Floeter <[email protected]>
+ * Copyright (c) 2011 - 2014 Reyk Floeter <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -64,8 +64,9 @@ config_init(struct relayd *env)
ps->ps_what[PROC_PARENT] = CONFIG_ALL;
ps->ps_what[PROC_PFE] = CONFIG_ALL & ~CONFIG_PROTOS;
ps->ps_what[PROC_HCE] = CONFIG_TABLES;
- ps->ps_what[PROC_RELAY] =
- CONFIG_TABLES|CONFIG_RELAYS|CONFIG_PROTOS;
+ ps->ps_what[PROC_CA] = CONFIG_RELAYS;
+ ps->ps_what[PROC_RELAY] = CONFIG_RELAYS|
+ CONFIG_TABLES|CONFIG_PROTOS|CONFIG_CA_ENGINE;
}
/* Other configuration */
@@ -245,6 +246,7 @@ config_getcfg(struct relayd *env, struct
struct table *tb;
struct host *h, *ph;
struct ctl_flags cf;
+ u_int what;
if (IMSG_DATA_SIZE(imsg) != sizeof(cf))
return (0); /* ignore */
@@ -254,7 +256,9 @@ config_getcfg(struct relayd *env, struct
env->sc_opts = cf.cf_opts;
env->sc_flags = cf.cf_flags;
- if (ps->ps_what[privsep_process] & CONFIG_TABLES) {
+ what = ps->ps_what[privsep_process];
+
+ if (what & CONFIG_TABLES) {
/* Update the tables */
TAILQ_FOREACH(tb, env->sc_tables, entry) {
TAILQ_FOREACH(h, &tb->hosts, entry) {
@@ -267,8 +271,12 @@ config_getcfg(struct relayd *env, struct
}
}
- if (env->sc_flags & (F_SSL|F_SSLCLIENT))
+ if (env->sc_flags & (F_SSL|F_SSLCLIENT)) {
ssl_init(env);
+ if ((what & CONFIG_CA_ENGINE) &&
+ (ca_engine_init(env)) == -1)
+ fatal("CA engine failed");
+ }
if (privsep_process != PROC_PARENT)
proc_compose_imsg(env->sc_ps, PROC_PARENT, -1,
@@ -802,45 +810,52 @@ config_setrelay(struct relayd *env, stru
struct privsep *ps = env->sc_ps;
struct ctl_relaytable crt;
struct relay_table *rlt;
+ struct relay_config rl;
int id;
int fd, n, m;
struct iovec iov[6];
size_t c;
+ u_int what;
/* opens listening sockets etc. */
if (relay_privinit(rlay) == -1)
return (-1);
for (id = 0; id < PROC_MAX; id++) {
- if ((ps->ps_what[id] & CONFIG_RELAYS) == 0 ||
- id == privsep_process)
+ what = ps->ps_what[id];
+
+ if ((what & CONFIG_RELAYS) == 0 || id == privsep_process)
continue;
DPRINTF("%s: sending relay %s to %s fd %d", __func__,
rlay->rl_conf.name, ps->ps_title[id], rlay->rl_s);
+ memcpy(&rl, &rlay->rl_conf, sizeof(rl));
+
c = 0;
- iov[c].iov_base = &rlay->rl_conf;
- iov[c++].iov_len = sizeof(rlay->rl_conf);
- if (rlay->rl_conf.ssl_cert_len) {
+ iov[c].iov_base = &rl;
+ iov[c++].iov_len = sizeof(rl);
+ if (rl.ssl_cert_len) {
iov[c].iov_base = rlay->rl_ssl_cert;
- iov[c++].iov_len = rlay->rl_conf.ssl_cert_len;
+ iov[c++].iov_len = rl.ssl_cert_len;
}
- if (rlay->rl_conf.ssl_key_len) {
+ if ((what & CONFIG_CA_ENGINE) == 0 &&
+ rl.ssl_key_len) {
iov[c].iov_base = rlay->rl_ssl_key;
- iov[c++].iov_len = rlay->rl_conf.ssl_key_len;
- }
- if (rlay->rl_conf.ssl_ca_len) {
+ iov[c++].iov_len = rl.ssl_key_len;
+ } else
+ rl.ssl_key_len = 0;
+ if (rl.ssl_ca_len) {
iov[c].iov_base = rlay->rl_ssl_ca;
- iov[c++].iov_len = rlay->rl_conf.ssl_ca_len;
+ iov[c++].iov_len = rl.ssl_ca_len;
}
- if (rlay->rl_conf.ssl_cacert_len) {
+ if (rl.ssl_cacert_len) {
iov[c].iov_base = rlay->rl_ssl_cacert;
- iov[c++].iov_len = rlay->rl_conf.ssl_cacert_len;
+ iov[c++].iov_len = rl.ssl_cacert_len;
}
- if (rlay->rl_conf.ssl_cakey_len) {
+ if (rl.ssl_cakey_len) {
iov[c].iov_base = rlay->rl_ssl_cakey;
- iov[c++].iov_len = rlay->rl_conf.ssl_cakey_len;
+ iov[c++].iov_len = rl.ssl_cakey_len;
}
if (id == PROC_RELAY) {
@@ -857,6 +872,9 @@ config_setrelay(struct relayd *env, stru
proc_composev_imsg(ps, id, -1, IMSG_CFG_RELAY, -1,
iov, c);
}
+
+ if ((what & CONFIG_TABLES) == 0)
+ continue;
/* Now send the tables associated to this relay */
TAILQ_FOREACH(rlt, &rlay->rl_tables, rlt_entry) {
Index: proc.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/proc.c,v
retrieving revision 1.7
diff -u -p -u -p -r1.7 proc.c
--- proc.c 14 Feb 2014 10:21:00 -0000 1.7
+++ proc.c 9 Apr 2014 14:02:38 -0000
@@ -1,7 +1,7 @@
/* $OpenBSD: proc.c,v 1.7 2014/02/14 10:21:00 benno Exp $ */
/*
- * Copyright (c) 2010,2011 Reyk Floeter <[email protected]>
+ * Copyright (c) 2010 - 2014 Reyk Floeter <[email protected]>
* Copyright (c) 2008 Pierre-Yves Ritschard <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -595,4 +595,13 @@ proc_ibuf(struct privsep *ps, enum privs
proc_range(ps, id, &n, &m);
return (&ps->ps_ievs[id][n].ibuf);
+}
+
+struct imsgev *
+proc_iev(struct privsep *ps, enum privsep_procid id, int n)
+{
+ int m;
+
+ proc_range(ps, id, &n, &m);
+ return (&ps->ps_ievs[id][n]);
}
Index: relay.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relay.c,v
retrieving revision 1.167
diff -u -p -u -p -r1.167 relay.c
--- relay.c 9 Sep 2013 17:57:44 -0000 1.167
+++ relay.c 9 Apr 2014 14:02:38 -0000
@@ -1,7 +1,7 @@
/* $OpenBSD: relay.c,v 1.167 2013/09/09 17:57:44 reyk Exp $ */
/*
- * Copyright (c) 2006 - 2013 Reyk Floeter <[email protected]>
+ * Copyright (c) 2006 - 2014 Reyk Floeter <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -52,6 +52,8 @@ int relay_dispatch_parent(int, struct
struct imsg *);
int relay_dispatch_pfe(int, struct privsep_proc *,
struct imsg *);
+int relay_dispatch_ca(int, struct privsep_proc *,
+ struct imsg *);
void relay_shutdown(void);
void relay_nodedebug(const char *, struct protonode *);
@@ -96,6 +98,7 @@ int proc_id;
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, relay_dispatch_parent },
{ "pfe", PROC_PFE, relay_dispatch_pfe },
+ { "ca", PROC_CA, relay_dispatch_ca }
};
pid_t
@@ -1782,6 +1785,12 @@ relay_dispatch_pfe(int fd, struct privse
}
int
+relay_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+ return (-1);
+}
+
+int
relay_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
{
struct rsession *con;
@@ -1904,8 +1913,9 @@ relay_ssl_ctx_create(struct relay *rlay)
goto err;
log_debug("%s: loading private key", __func__);
- if (!ssl_ctx_use_private_key(ctx, rlay->rl_ssl_key,
- rlay->rl_conf.ssl_key_len))
+ if (!ssl_ctx_fake_private_key(ctx,
+ &rlay->rl_conf.id, rlay->rl_ssl_cert,
+ rlay->rl_conf.ssl_cert_len))
goto err;
if (!SSL_CTX_check_private_key(ctx))
goto err;
Index: relayd.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.c,v
retrieving revision 1.119
diff -u -p -u -p -r1.119 relayd.c
--- relayd.c 16 Mar 2014 18:38:30 -0000 1.119
+++ relayd.c 9 Apr 2014 14:02:38 -0000
@@ -1,7 +1,7 @@
/* $OpenBSD: relayd.c,v 1.119 2014/03/16 18:38:30 guenther Exp $ */
/*
- * Copyright (c) 2007, 2008 Reyk Floeter <[email protected]>
+ * Copyright (c) 2007 - 2014 Reyk Floeter <[email protected]>
* Copyright (c) 2006 Pierre-Yves Ritschard <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -57,6 +57,8 @@ int parent_dispatch_pfe(int, struct pr
int parent_dispatch_hce(int, struct privsep_proc *, struct imsg *);
int parent_dispatch_relay(int, struct privsep_proc *,
struct imsg *);
+int parent_dispatch_ca(int, struct privsep_proc *,
+ struct imsg *);
int bindany(struct ctl_bindany *);
struct relayd *relayd_env;
@@ -64,7 +66,8 @@ struct relayd *relayd_env;
static struct privsep_proc procs[] = {
{ "pfe", PROC_PFE, parent_dispatch_pfe, pfe },
{ "hce", PROC_HCE, parent_dispatch_hce, hce },
- { "relay", PROC_RELAY, parent_dispatch_relay, relay }
+ { "relay", PROC_RELAY, parent_dispatch_relay, relay },
+ { "ca", PROC_CA, parent_dispatch_ca, ca }
};
void
@@ -326,7 +329,7 @@ parent_configure(struct relayd *env)
ret = 0;
done:
- config_purge(env, CONFIG_ALL);
+ config_purge(env, CONFIG_ALL & ~CONFIG_RELAYS);
return (ret);
}
@@ -503,6 +506,22 @@ parent_dispatch_relay(int fd, struct pri
proc_compose_imsg(ps, PROC_RELAY, bnd.bnd_proc,
IMSG_BINDANY, s, &bnd.bnd_id, sizeof(bnd.bnd_id));
break;
+ case IMSG_CFG_DONE:
+ parent_configure_done(env);
+ break;
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+parent_dispatch_ca(int fd, struct privsep_proc *p, struct imsg *imsg)
+{
+ struct relayd *env = p->p_env;
+
+ switch (imsg->hdr.type) {
case IMSG_CFG_DONE:
parent_configure_done(env);
break;
Index: relayd.h
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v
retrieving revision 1.172
diff -u -p -u -p -r1.172 relayd.h
--- relayd.h 14 Feb 2014 10:21:00 -0000 1.172
+++ relayd.h 9 Apr 2014 14:02:38 -0000
@@ -1,7 +1,7 @@
/* $OpenBSD: relayd.h,v 1.172 2014/02/14 10:21:00 benno Exp $ */
/*
- * Copyright (c) 2006 - 2012 Reyk Floeter <[email protected]>
+ * Copyright (c) 2006 - 2014 Reyk Floeter <[email protected]>
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <[email protected]>
* Copyright (c) 2003, 2004 Henning Brauer <[email protected]>
*
@@ -69,6 +69,7 @@
#define CONFIG_PROTOS 0x08
#define CONFIG_ROUTES 0x10
#define CONFIG_RTS 0x20
+#define CONFIG_CA_ENGINE 0x40
#define CONFIG_ALL 0xff
#define SMALL_READ_BUF_SIZE 1024
@@ -229,6 +230,14 @@ struct ctl_bindany {
int bnd_proto;
};
+struct ctl_keyop {
+ objid_t cko_id;
+ int cko_proc;
+ int cko_flen;
+ int cko_tlen;
+ int cko_padding;
+};
+
struct ctl_stats {
objid_t id;
int proc;
@@ -828,7 +837,9 @@ enum imsg_type {
IMSG_CFG_PROTONODE,
IMSG_CFG_RELAY,
IMSG_CFG_RELAY_TABLE,
- IMSG_CFG_DONE
+ IMSG_CFG_DONE,
+ IMSG_CA_PRIVENC,
+ IMSG_CA_PRIVDEC
};
enum privsep_procid {
@@ -837,6 +848,7 @@ enum privsep_procid {
PROC_HCE,
PROC_RELAY,
PROC_PFE,
+ PROC_CA,
PROC_MAX
} privsep_process;
@@ -1068,10 +1080,14 @@ X509 *ssl_update_certificate(X509 *, cha
char *, off_t, char *, off_t);
/* ssl_privsep.c */
-int ssl_ctx_use_private_key(SSL_CTX *, char *, off_t);
+int ssl_ctx_fake_private_key(SSL_CTX *, void *, 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);
+/* ca.c */
+pid_t ca(struct privsep *, struct privsep_proc *);
+int ca_engine_init(struct relayd *);
+
/* relayd.c */
struct host *host_find(struct relayd *, objid_t);
struct table *table_find(struct relayd *, objid_t);
@@ -1166,6 +1182,8 @@ int proc_forward_imsg(struct privsep *,
enum privsep_procid, int);
struct imsgbuf *
proc_ibuf(struct privsep *, enum privsep_procid, int);
+struct imsgev *
+ proc_iev(struct privsep *, enum privsep_procid, int);
void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
pid_t, int, void *, u_int16_t);
Index: ssl_privsep.c
===================================================================
RCS file: /cvs/src/usr.sbin/relayd/ssl_privsep.c,v
retrieving revision 1.9
diff -u -p -u -p -r1.9 ssl_privsep.c
--- ssl_privsep.c 4 Oct 2012 20:53:30 -0000 1.9
+++ ssl_privsep.c 9 Apr 2014 14:02:38 -0000
@@ -76,7 +76,7 @@
#include <openssl/pem.h>
#include <openssl/ssl.h>
-int ssl_ctx_use_private_key(SSL_CTX *, char *, off_t);
+int ssl_ctx_fake_private_key(SSL_CTX *, void *, 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 **);
@@ -97,35 +97,51 @@ 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)
+ssl_ctx_fake_private_key(SSL_CTX *ctx, void *data, char *buf, off_t len)
{
- int ret;
+ int ret = 0;
BIO *in;
- EVP_PKEY *pkey;
-
- ret = 0;
+ X509 *x = NULL;
+ EVP_PKEY *pkey = NULL;
+ RSA *rsa;
if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
- SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB);
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_BUF_LIB);
return 0;
}
- pkey = PEM_read_bio_PrivateKey(in, NULL,
+ if ((x = PEM_read_bio_X509(in, NULL,
ctx->default_passwd_callback,
- ctx->default_passwd_callback_userdata);
+ ctx->default_passwd_callback_userdata)) == NULL) {
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PEM_LIB);
+ goto end;
+ }
- if (pkey == NULL) {
- SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB);
+ if ((pkey = X509_get_pubkey(x)) == NULL) {
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_X509_LIB);
goto end;
}
+
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ RSA_set_app_data(rsa, data);
+
+ /*
+ * 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);
- EVP_PKEY_free(pkey);
+
end:
+ if (pkey != NULL)
+ EVP_PKEY_free(pkey);
+ if (x != NULL)
+ X509_free(x);
if (in != NULL)
BIO_free(in);
return ret;
}
-
int
ssl_ctx_use_certificate_chain(SSL_CTX *ctx, char *buf, off_t len)