Support the CA key for SSL inspection in the ca process. Instead of
authorreyk <reyk@openbsd.org>
Tue, 22 Apr 2014 08:04:23 +0000 (08:04 +0000)
committerreyk <reyk@openbsd.org>
Tue, 22 Apr 2014 08:04:23 +0000 (08:04 +0000)
looking up the keys by relay id, add all keys to a list and look them
up by key id.

ok benno@

usr.sbin/relayd/ca.c
usr.sbin/relayd/config.c
usr.sbin/relayd/parse.y
usr.sbin/relayd/relay.c
usr.sbin/relayd/relayd.c
usr.sbin/relayd/relayd.h
usr.sbin/relayd/ssl.c

index 48a7c4d..b478d84 100644 (file)
@@ -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;
index c9e45ec..609317a 100644 (file)
@@ -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 */
index 5853d7e..f085bdd 100644 (file)
@@ -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;
        }
index ad7b7f8..d6d4cf6 100644 (file)
@@ -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)
index afabd00..2e8cc86 100644 (file)
@@ -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 *),
index 559b167..23ddafd 100644 (file)
@@ -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);
index 35c78b0..ffe43d3 100644 (file)
@@ -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);
+}