summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2014-04-22 08:04:24 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2014-04-22 08:04:24 +0000
commit5059d0414ab5c579f4735bb139f96ec87e43f3ca (patch)
treeef8f0ebd60a627618b2199dcf3badb928dabd4bc
parent3f54bb0ff4ad1fc49ba1209b6e9a44d4ccffd003 (diff)
Support the CA key for SSL inspection in the ca process. Instead of
looking up the keys by relay id, add all keys to a list and look them up by key id. ok benno@
-rw-r--r--usr.sbin/relayd/ca.c46
-rw-r--r--usr.sbin/relayd/config.c19
-rw-r--r--usr.sbin/relayd/parse.y26
-rw-r--r--usr.sbin/relayd/relay.c20
-rw-r--r--usr.sbin/relayd/relayd.c40
-rw-r--r--usr.sbin/relayd/relayd.h23
-rw-r--r--usr.sbin/relayd/ssl.c84
7 files changed, 185 insertions, 73 deletions
diff --git a/usr.sbin/relayd/ca.c b/usr.sbin/relayd/ca.c
index 48a7c4de312..b478d843e4d 100644
--- a/usr.sbin/relayd/ca.c
+++ b/usr.sbin/relayd/ca.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ca.c,v 1.6 2014/04/21 17:22:06 reyk Exp $ */
+/* $OpenBSD: ca.c,v 1.7 2014/04/22 08:04:23 reyk Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
@@ -109,6 +109,10 @@ ca_launch(void)
rlay->rl_ssl_pkey = pkey;
+ if (pkey_add(env, pkey,
+ rlay->rl_conf.ssl_keyid) == NULL)
+ fatalx("ssl pkey");
+
purge_key(&rlay->rl_ssl_key,
rlay->rl_conf.ssl_key_len);
}
@@ -116,6 +120,29 @@ ca_launch(void)
purge_key(&rlay->rl_ssl_cert,
rlay->rl_conf.ssl_cert_len);
}
+ if (rlay->rl_conf.ssl_cakey_len) {
+ if ((in = BIO_new_mem_buf(rlay->rl_ssl_cakey,
+ rlay->rl_conf.ssl_cakey_len)) == NULL)
+ fatalx("ca_launch: key");
+
+ if ((pkey = PEM_read_bio_PrivateKey(in,
+ NULL, NULL, NULL)) == NULL)
+ fatalx("ca_launch: PEM");
+ BIO_free(in);
+
+ rlay->rl_ssl_capkey = pkey;
+
+ if (pkey_add(env, pkey,
+ rlay->rl_conf.ssl_cakeyid) == NULL)
+ fatalx("ca pkey");
+
+ purge_key(&rlay->rl_ssl_cakey,
+ rlay->rl_conf.ssl_cakey_len);
+ }
+ if (rlay->rl_conf.ssl_cacert_len) {
+ purge_key(&rlay->rl_ssl_cacert,
+ rlay->rl_conf.ssl_cacert_len);
+ }
}
}
@@ -142,17 +169,6 @@ ca_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
return (0);
}
-static EVP_PKEY *
-ca_get_key(objid_t id)
-{
- struct relay *rlay;
-
- if ((rlay = relay_find(env, id)) == NULL)
- return (NULL);
-
- return (rlay->rl_ssl_pkey);
-}
-
int
ca_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
{
@@ -174,11 +190,13 @@ ca_dispatch_relay(int fd, struct privsep_proc *p, struct imsg *imsg)
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 ||
+ if ((pkey = pkey_find(env, cko.cko_id)) == NULL ||
(rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
fatalx("ca_dispatch_relay: "
"invalid relay key or id");
+ DPRINTF("%s:%d: key id %d", __func__, __LINE__, cko.cko_id);
+
from = (u_char *)imsg->data + sizeof(cko);
if ((to = calloc(1, cko.cko_tlen)) == NULL)
fatalx("ca_dispatch_relay: calloc");
@@ -243,7 +261,7 @@ rsae_send_imsg(int flen, const u_char *from, u_char *to, RSA *rsa,
{
struct ctl_keyop cko;
int ret = 0;
- u_int32_t *id;
+ objid_t *id;
struct iovec iov[2];
struct imsgbuf *ibuf;
struct imsgev *iev;
diff --git a/usr.sbin/relayd/config.c b/usr.sbin/relayd/config.c
index c9e45ecb279..609317a5680 100644
--- a/usr.sbin/relayd/config.c
+++ b/usr.sbin/relayd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.12 2014/04/18 13:55:26 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.13 2014/04/22 08:04:23 reyk Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -96,6 +96,10 @@ config_init(struct relayd *env)
calloc(1, sizeof(*env->sc_relays))) == NULL)
return (-1);
TAILQ_INIT(env->sc_relays);
+ if ((env->sc_pkeys =
+ calloc(1, sizeof(*env->sc_pkeys))) == NULL)
+ return (-1);
+ TAILQ_INIT(env->sc_pkeys);
}
if (what & CONFIG_PROTOS) {
if ((env->sc_protos =
@@ -147,6 +151,7 @@ config_purge(struct relayd *env, u_int reset)
struct relay *rlay;
struct netroute *nr;
struct router *rt;
+ struct ca_pkey *pkey;
u_int what;
what = ps->ps_what[privsep_process] & reset;
@@ -167,6 +172,12 @@ config_purge(struct relayd *env, u_int reset)
}
env->sc_rdrcount = 0;
}
+ if (what & CONFIG_RELAYS && env->sc_pkeys != NULL) {
+ while ((pkey = TAILQ_FIRST(env->sc_pkeys)) != NULL) {
+ TAILQ_REMOVE(env->sc_pkeys, pkey, pkey_entry);
+ free(pkey);
+ }
+ }
if (what & CONFIG_RELAYS && env->sc_relays != NULL) {
while ((rlay = TAILQ_FIRST(env->sc_relays)) != NULL)
purge_relay(env, rlay);
@@ -853,10 +864,12 @@ config_setrelay(struct relayd *env, struct relay *rlay)
iov[c].iov_base = rlay->rl_ssl_cacert;
iov[c++].iov_len = rl.ssl_cacert_len;
}
- if (rl.ssl_cakey_len) {
+ if ((what & CONFIG_CA_ENGINE) == 0 &&
+ rl.ssl_cakey_len) {
iov[c].iov_base = rlay->rl_ssl_cakey;
iov[c++].iov_len = rl.ssl_cakey_len;
- }
+ } else
+ rl.ssl_cakey_len = 0;
if (id == PROC_RELAY) {
/* XXX imsg code will close the fd after 1st call */
diff --git a/usr.sbin/relayd/parse.y b/usr.sbin/relayd/parse.y
index 5853d7e5474..f085bddf3d7 100644
--- a/usr.sbin/relayd/parse.y
+++ b/usr.sbin/relayd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.179 2014/04/21 17:33:31 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.180 2014/04/22 08:04:23 reyk Exp $ */
/*
* Copyright (c) 2007-2011 Reyk Floeter <reyk@openbsd.org>
@@ -99,6 +99,7 @@ objid_t last_relay_id = 0;
objid_t last_proto_id = 0;
objid_t last_rt_id = 0;
objid_t last_nr_id = 0;
+objid_t last_key_id = 0;
static struct rdr *rdr = NULL;
static struct table *table = NULL;
@@ -124,6 +125,7 @@ int host(const char *, struct addresslist *,
void host_free(struct addresslist *);
struct table *table_inherit(struct table *);
+int relay_id(struct relay *);
struct relay *relay_inherit(struct relay *, struct relay *);
int getservice(char *);
int is_if_in_group(const char *, const char *);
@@ -1323,7 +1325,11 @@ relay : RELAY STRING {
YYERROR;
}
free($2);
- r->rl_conf.id = ++last_relay_id;
+ if (relay_id(r) == -1) {
+ yyerror("too many relays defined");
+ free(r);
+ YYERROR;
+ }
r->rl_conf.timeout.tv_sec = RELAY_TIMEOUT;
r->rl_proto = NULL;
r->rl_conf.proto = EMPTY_ID;
@@ -2848,6 +2854,19 @@ table_inherit(struct table *tb)
return (NULL);
}
+int
+relay_id(struct relay *rl)
+{
+ rl->rl_conf.id = ++last_relay_id;
+ rl->rl_conf.ssl_keyid = ++last_key_id;
+ rl->rl_conf.ssl_cakeyid = ++last_key_id;
+
+ if (last_relay_id == INT_MAX || last_key_id == INT_MAX)
+ return (-1);
+
+ return (0);
+}
+
struct relay *
relay_inherit(struct relay *ra, struct relay *rb)
{
@@ -2869,8 +2888,7 @@ relay_inherit(struct relay *ra, struct relay *rb)
}
TAILQ_INIT(&rb->rl_tables);
- rb->rl_conf.id = ++last_relay_id;
- if (last_relay_id == INT_MAX) {
+ if (relay_id(rb) == -1) {
yyerror("too many relays defined");
goto err;
}
diff --git a/usr.sbin/relayd/relay.c b/usr.sbin/relayd/relay.c
index ad7b7f86b65..d6d4cf6e43b 100644
--- a/usr.sbin/relayd/relay.c
+++ b/usr.sbin/relayd/relay.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relay.c,v 1.168 2014/04/18 13:55:26 reyk Exp $ */
+/* $OpenBSD: relay.c,v 1.169 2014/04/22 08:04:23 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -1914,13 +1914,23 @@ relay_ssl_ctx_create(struct relay *rlay)
log_debug("%s: loading private key", __func__);
if (!ssl_ctx_fake_private_key(ctx,
- &rlay->rl_conf.id, rlay->rl_ssl_cert, rlay->rl_conf.ssl_cert_len,
+ &rlay->rl_conf.ssl_keyid,
+ rlay->rl_ssl_cert, rlay->rl_conf.ssl_cert_len,
&rlay->rl_ssl_x509, &rlay->rl_ssl_pkey))
goto err;
if (!SSL_CTX_check_private_key(ctx))
goto err;
+ if (rlay->rl_conf.ssl_cacert_len) {
+ log_debug("%s: loading CA private key", __func__);
+ if (!ssl_ctx_load_pkey(ctx,
+ &rlay->rl_conf.ssl_cakeyid, rlay->rl_ssl_cacert,
+ rlay->rl_conf.ssl_cacert_len,
+ &rlay->rl_ssl_cacertx509, &rlay->rl_ssl_capkey))
+ goto err;
+ }
+
/* Set session context to the local relay name */
if (!SSL_CTX_set_session_id_context(ctx, rlay->rl_conf.name,
strlen(rlay->rl_conf.name)))
@@ -1928,6 +1938,7 @@ relay_ssl_ctx_create(struct relay *rlay)
/* The text versions of the keys/certs are not needed anymore */
purge_key(&rlay->rl_ssl_cert, rlay->rl_conf.ssl_cert_len);
+ purge_key(&rlay->rl_ssl_cacert, rlay->rl_conf.ssl_cacert_len);
return (ctx);
@@ -2101,9 +2112,8 @@ relay_ssl_connect(int fd, short event, void *arg)
SSL_get_peer_certificate(con->se_out.ssl)) != NULL) {
con->se_in.sslcert =
ssl_update_certificate(servercert,
- rlay->rl_ssl_pkey,
- rlay->rl_ssl_cakey, rlay->rl_conf.ssl_cakey_len,
- rlay->rl_ssl_cacert, rlay->rl_conf.ssl_cacert_len);
+ rlay->rl_ssl_pkey, rlay->rl_ssl_capkey,
+ rlay->rl_ssl_cacertx509);
} else
con->se_in.sslcert = NULL;
if (servercert != NULL)
diff --git a/usr.sbin/relayd/relayd.c b/usr.sbin/relayd/relayd.c
index afabd002224..2e8cc86051d 100644
--- a/usr.sbin/relayd/relayd.c
+++ b/usr.sbin/relayd/relayd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.c,v 1.121 2014/04/20 14:48:29 reyk Exp $ */
+/* $OpenBSD: relayd.c,v 1.122 2014/04/22 08:04:23 reyk Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -639,6 +639,14 @@ purge_relay(struct relayd *env, struct relay *rlay)
EVP_PKEY_free(rlay->rl_ssl_pkey);
rlay->rl_ssl_pkey = NULL;
}
+ if (rlay->rl_ssl_cacertx509 != NULL) {
+ X509_free(rlay->rl_ssl_cacertx509);
+ rlay->rl_ssl_cacertx509 = NULL;
+ }
+ if (rlay->rl_ssl_capkey != NULL) {
+ EVP_PKEY_free(rlay->rl_ssl_capkey);
+ rlay->rl_ssl_capkey = NULL;
+ }
if (rlay->rl_ssl_ctx != NULL)
SSL_CTX_free(rlay->rl_ssl_ctx);
@@ -833,6 +841,36 @@ relay_findbyaddr(struct relayd *env, struct relay_config *rc)
return (NULL);
}
+EVP_PKEY *
+pkey_find(struct relayd *env, objid_t id)
+{
+ struct ca_pkey *pkey;
+
+ TAILQ_FOREACH(pkey, env->sc_pkeys, pkey_entry)
+ if (pkey->pkey_id == id)
+ return (pkey->pkey);
+ return (NULL);
+}
+
+struct ca_pkey *
+pkey_add(struct relayd *env, EVP_PKEY *pkey, objid_t id)
+{
+ struct ca_pkey *ca_pkey;
+
+ if (env->sc_pkeys == NULL)
+ fatalx("pkeys");
+
+ if ((ca_pkey = calloc(1, sizeof(*ca_pkey))) == NULL)
+ return (NULL);
+
+ ca_pkey->pkey = pkey;
+ ca_pkey->pkey_id = id;
+
+ TAILQ_INSERT_TAIL(env->sc_pkeys, ca_pkey, pkey_entry);
+
+ return (ca_pkey);
+}
+
void
event_again(struct event *ev, int fd, short event,
void (*fn)(int, short, void *),
diff --git a/usr.sbin/relayd/relayd.h b/usr.sbin/relayd/relayd.h
index 559b167deab..23ddafdbee5 100644
--- a/usr.sbin/relayd/relayd.h
+++ b/usr.sbin/relayd/relayd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: relayd.h,v 1.176 2014/04/20 14:48:29 reyk Exp $ */
+/* $OpenBSD: relayd.h,v 1.177 2014/04/22 08:04:23 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -627,6 +627,13 @@ struct relay_table {
};
TAILQ_HEAD(relaytables, relay_table);
+struct ca_pkey {
+ objid_t pkey_id;
+ EVP_PKEY *pkey;
+ TAILQ_ENTRY(ca_pkey) pkey_entry;
+};
+TAILQ_HEAD(ca_pkeylist, ca_pkey);
+
struct relay_config {
objid_t id;
u_int32_t flags;
@@ -643,9 +650,11 @@ struct relay_config {
enum forwardmode fwdmode;
off_t ssl_cert_len;
off_t ssl_key_len;
+ objid_t ssl_keyid;
off_t ssl_ca_len;
off_t ssl_cacert_len;
off_t ssl_cakey_len;
+ objid_t ssl_cakeyid;
};
struct relay {
@@ -674,8 +683,12 @@ struct relay {
EVP_PKEY *rl_ssl_pkey;
char *rl_ssl_ca;
+
char *rl_ssl_cacert;
+ X509 *rl_ssl_cacertx509;
+
char *rl_ssl_cakey;
+ EVP_PKEY *rl_ssl_capkey;
struct ctl_stats rl_stats[RELAY_MAXPROC + 1];
@@ -929,6 +942,7 @@ struct relayd {
struct relaylist *sc_relays;
struct routerlist *sc_rts;
struct netroutelist *sc_routes;
+ struct ca_pkeylist *sc_pkeys;
u_int16_t sc_prefork_relay;
char sc_demote_group[IFNAMSIZ];
u_int16_t sc_id;
@@ -1092,8 +1106,9 @@ void ssl_transaction(struct ctl_tcp_event *);
SSL_CTX *ssl_ctx_create(struct relayd *);
void ssl_error(const char *, const char *);
char *ssl_load_key(struct relayd *, const char *, off_t *, char *);
-X509 *ssl_update_certificate(X509 *, EVP_PKEY *,
- char *, off_t, char *, off_t);
+X509 *ssl_update_certificate(X509 *, EVP_PKEY *, EVP_PKEY *, X509 *);
+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,
X509 **, EVP_PKEY **);
@@ -1123,6 +1138,8 @@ struct protocol *proto_find(struct relayd *, objid_t);
struct rsession *session_find(struct relayd *, objid_t);
struct relay *relay_findbyname(struct relayd *, const char *);
struct relay *relay_findbyaddr(struct relayd *, struct relay_config *);
+EVP_PKEY *pkey_find(struct relayd *, objid_t);
+struct ca_pkey *pkey_add(struct relayd *, EVP_PKEY *, objid_t);
int expand_string(char *, size_t, const char *, const char *);
void translate_string(char *);
void purge_key(char **, off_t);
diff --git a/usr.sbin/relayd/ssl.c b/usr.sbin/relayd/ssl.c
index 35c78b0947b..ffe43d378da 100644
--- a/usr.sbin/relayd/ssl.c
+++ b/usr.sbin/relayd/ssl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl.c,v 1.21 2014/04/21 17:22:06 reyk Exp $ */
+/* $OpenBSD: ssl.c,v 1.22 2014/04/22 08:04:23 reyk Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -359,13 +359,11 @@ ssl_load_key(struct relayd *env, const char *name, off_t *len, char *pass)
}
X509 *
-ssl_update_certificate(X509 *oldcert, EVP_PKEY *pkey,
- char *cakeystr, off_t cakeylen, char *cacertstr, off_t cacertlen)
+ssl_update_certificate(X509 *oldcert, EVP_PKEY *pkey, EVP_PKEY *capkey,
+ X509 *cacert)
{
char name[2][SSL_NAME_SIZE];
- X509 *cert = NULL, *cacert = NULL;
- EVP_PKEY *cakey = NULL;
- BIO *bio = NULL;
+ X509 *cert = NULL;
name[0][0] = name[1][0] = '\0';
if (!X509_NAME_oneline(X509_get_subject_name(oldcert),
@@ -374,22 +372,6 @@ ssl_update_certificate(X509 *oldcert, EVP_PKEY *pkey,
name[1], sizeof(name[1])))
goto done;
- /* Get CA key */
- BIO_free_all(bio);
- if ((bio = BIO_new_mem_buf(cakeystr, cakeylen)) == NULL)
- goto done;
- if ((cakey = PEM_read_bio_PrivateKey(bio, &cakey,
- ssl_password_cb, NULL)) == NULL)
- goto done;
-
- /* Get CA certificate */
- BIO_free_all(bio);
- if ((bio = BIO_new_mem_buf(cacertstr, cacertlen)) == NULL)
- goto done;
- if ((cacert = PEM_read_bio_X509(bio, &cacert,
- ssl_password_cb, NULL)) == NULL)
- goto done;
-
if ((cert = X509_dup(oldcert)) == NULL)
goto done;
@@ -398,7 +380,7 @@ ssl_update_certificate(X509 *oldcert, EVP_PKEY *pkey,
X509_set_issuer_name(cert, X509_get_subject_name(cacert));
/* Sign with our CA */
- if (!X509_sign(cert, cakey, EVP_sha1())) {
+ if (!X509_sign(cert, capkey, EVP_sha1())) {
X509_free(cert);
cert = NULL;
}
@@ -414,18 +396,12 @@ ssl_update_certificate(X509 *oldcert, EVP_PKEY *pkey,
done:
if (cert == NULL)
ssl_error(__func__, name[0]);
- if (bio != NULL)
- BIO_free_all(bio);
- if (cacert != NULL)
- X509_free(cacert);
- if (cakey != NULL)
- EVP_PKEY_free(cakey);
return (cert);
}
int
-ssl_ctx_fake_private_key(SSL_CTX *ctx, void *data, char *buf, off_t len,
+ssl_ctx_load_pkey(SSL_CTX *ctx, void *data, char *buf, off_t len,
X509 **x509ptr, EVP_PKEY **pkeyptr)
{
int ret = 0;
@@ -440,8 +416,7 @@ ssl_ctx_fake_private_key(SSL_CTX *ctx, void *data, char *buf, off_t len,
}
if ((x509 = PEM_read_bio_X509(in, NULL,
- ctx->default_passwd_callback,
- ctx->default_passwd_callback_userdata)) == NULL) {
+ ssl_password_cb, NULL)) == NULL) {
SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PEM_LIB);
goto fail;
}
@@ -458,17 +433,6 @@ ssl_ctx_fake_private_key(SSL_CTX *ctx, void *data, char *buf, off_t len,
RSA_set_ex_data(rsa, 0, 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.
- */
- if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
- SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_SSL_LIB);
- goto fail;
- }
-
*x509ptr = x509;
*pkeyptr = pkey;
ret = 1;
@@ -487,3 +451,37 @@ ssl_ctx_fake_private_key(SSL_CTX *ctx, void *data, char *buf, off_t len,
return ret;
}
+
+int
+ssl_ctx_fake_private_key(SSL_CTX *ctx, void *data, char *buf, off_t len,
+ X509 **x509ptr, EVP_PKEY **pkeyptr)
+{
+ int ret;
+
+ if (!(ret = ssl_ctx_load_pkey(ctx, data, buf, len,
+ x509ptr, pkeyptr)))
+ goto fail;
+
+ /*
+ * 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.
+ */
+ if (!SSL_CTX_use_PrivateKey(ctx, *pkeyptr)) {
+ SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_SSL_LIB);
+ goto fail;
+ }
+
+ return (1);
+
+ fail:
+ if (*pkeyptr != NULL)
+ EVP_PKEY_free(*pkeyptr);
+ if (*x509ptr != NULL)
+ X509_free(*x509ptr);
+ *x509ptr = NULL;
+ *pkeyptr = NULL;
+
+ return (0);
+}