diff options
author | jsing <jsing@openbsd.org> | 2017-07-19 17:36:25 +0000 |
---|---|---|
committer | jsing <jsing@openbsd.org> | 2017-07-19 17:36:25 +0000 |
commit | 88ad1069f3e0e7b8bbe53365c34b80501665797f (patch) | |
tree | c72b63269e54ae3337aae05417edecf475c52e34 /usr.sbin/httpd | |
parent | Avoid the historical term "loader", consistently talk about the "linker". (diff) | |
download | wireguard-openbsd-88ad1069f3e0e7b8bbe53365c34b80501665797f.tar.xz wireguard-openbsd-88ad1069f3e0e7b8bbe53365c34b80501665797f.zip |
Rework the way that TLS configuration is sent/received via imsgs, so that
are no longer limited by the 16KB maximum size of a single imsg.
Configuration data that is larger than a single message is now chunked and
sent via multiple imsgs.
Prompted by a diff from Jack Burton <jack at saosce dot com dot au>.
ok reyk@
Diffstat (limited to 'usr.sbin/httpd')
-rw-r--r-- | usr.sbin/httpd/config.c | 194 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.h | 20 | ||||
-rw-r--r-- | usr.sbin/httpd/server.c | 4 |
3 files changed, 130 insertions, 88 deletions
diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c index 4dcf433f676..3c31c3d4cd3 100644 --- a/usr.sbin/httpd/config.c +++ b/usr.sbin/httpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.52 2017/05/28 10:37:26 benno Exp $ */ +/* $OpenBSD: config.c,v 1.53 2017/07/19 17:36:25 jsing Exp $ */ /* * Copyright (c) 2011 - 2015 Reyk Floeter <reyk@openbsd.org> @@ -222,7 +222,7 @@ config_setserver(struct httpd *env, struct server *srv) } /* Configure TLS if necessary. */ - config_settls(env, srv); + config_setserver_tls(env, srv); } else { if (proc_composev(ps, id, IMSG_CFG_SERVER, iov, c) != 0) { @@ -246,8 +246,9 @@ config_setserver(struct httpd *env, struct server *srv) return (0); } -int -config_settls(struct httpd *env, struct server *srv) +static int +config_settls(struct httpd *env, struct server *srv, enum tls_config_type type, + const char *label, uint8_t *data, size_t len) { struct privsep *ps = env->sc_ps; struct server_config *srv_conf = &srv->srv_conf; @@ -255,76 +256,65 @@ config_settls(struct httpd *env, struct server *srv) struct iovec iov[2]; size_t c; - if ((srv_conf->flags & SRVFLAG_TLS) == 0) + if (data == NULL || len == 0) return (0); - log_debug("%s: configuring tls for %s", __func__, srv_conf->name); + DPRINTF("%s: sending tls %s for \"%s[%u]\" to %s fd %d", __func__, + label, srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], + srv->srv_s); - if (srv_conf->tls_cert_len != 0) { - DPRINTF("%s: sending tls cert \"%s[%u]\" to %s fd %d", __func__, - srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], - srv->srv_s); + memset(&tls, 0, sizeof(tls)); + tls.id = srv_conf->id; + tls.tls_type = type; + tls.tls_len = len; + tls.tls_chunk_offset = 0; - memset(&tls, 0, sizeof(tls)); - tls.id = srv_conf->id; - tls.tls_cert_len = srv_conf->tls_cert_len; + while (len > 0) { + tls.tls_chunk_len = len; + if (tls.tls_chunk_len > (MAX_IMSG_DATA_SIZE - sizeof(tls))) + tls.tls_chunk_len = MAX_IMSG_DATA_SIZE - sizeof(tls); c = 0; iov[c].iov_base = &tls; iov[c++].iov_len = sizeof(tls); - iov[c].iov_base = srv_conf->tls_cert; - iov[c++].iov_len = srv_conf->tls_cert_len; + iov[c].iov_base = data; + iov[c++].iov_len = tls.tls_chunk_len; if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " "`%s'", __func__, srv_conf->name); return (-1); } - } - if (srv_conf->tls_key_len != 0) { - DPRINTF("%s: sending tls key \"%s[%u]\" to %s fd %d", __func__, - srv_conf->name, srv_conf->id, ps->ps_title[PROC_SERVER], - srv->srv_s); + tls.tls_chunk_offset += tls.tls_chunk_len; + data += tls.tls_chunk_len; + len -= tls.tls_chunk_len; + } - memset(&tls, 0, sizeof(tls)); - tls.id = srv_conf->id; - tls.tls_key_len = srv_conf->tls_key_len; + return (0); +} - c = 0; - iov[c].iov_base = &tls; - iov[c++].iov_len = sizeof(tls); - iov[c].iov_base = srv_conf->tls_key; - iov[c++].iov_len = srv_conf->tls_key_len; +int +config_setserver_tls(struct httpd *env, struct server *srv) +{ + struct server_config *srv_conf = &srv->srv_conf; - if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { - log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " - "`%s'", __func__, srv_conf->name); - return (-1); - } - } + if ((srv_conf->flags & SRVFLAG_TLS) == 0) + return (0); - if (srv_conf->tls_ocsp_staple_len != 0) { - DPRINTF("%s: sending ocsp staple \"%s[%u]\" to %s fd %d", - __func__, srv_conf->name, srv_conf->id, - ps->ps_title[PROC_SERVER], srv->srv_s); + log_debug("%s: configuring tls for %s", __func__, srv_conf->name); - memset(&tls, 0, sizeof(tls)); - tls.id = srv_conf->id; - tls.tls_ocsp_staple_len = srv_conf->tls_ocsp_staple_len; + if (config_settls(env, srv, TLS_CFG_CERT, "cert", srv_conf->tls_cert, + srv_conf->tls_cert_len) != 0) + return (-1); - c = 0; - iov[c].iov_base = &tls; - iov[c++].iov_len = sizeof(tls); - iov[c].iov_base = srv_conf->tls_ocsp_staple; - iov[c++].iov_len = srv_conf->tls_ocsp_staple_len; + if (config_settls(env, srv, TLS_CFG_KEY, "key", srv_conf->tls_key, + srv_conf->tls_key_len) != 0) + return (-1); - if (proc_composev(ps, PROC_SERVER, IMSG_CFG_TLS, iov, c) != 0) { - log_warn("%s: failed to compose IMSG_CFG_TLS imsg for " - "`%s'", __func__, srv_conf->name); - return (-1); - } - } + if (config_settls(env, srv, TLS_CFG_OCSP_STAPLE, "ocsp staple", + srv_conf->tls_ocsp_staple, srv_conf->tls_ocsp_staple_len) != 0) + return (-1); return (0); } @@ -593,57 +583,101 @@ config_getserver(struct httpd *env, struct imsg *imsg) return (-1); } -int -config_gettls(struct httpd *env, struct imsg *imsg) +static int +config_gettls(struct httpd *env, struct server_config *srv_conf, + struct tls_config *tls_conf, const char *label, uint8_t *data, size_t len, + uint8_t **outdata, size_t *outlen) { #ifdef DEBUG struct privsep *ps = env->sc_ps; #endif + + DPRINTF("%s: %s %d getting tls %s (%zu:%zu@%zu) for \"%s[%u]\"", + __func__, ps->ps_title[privsep_process], ps->ps_instance, label, + tls_conf->tls_len, len, tls_conf->tls_chunk_offset, srv_conf->name, + srv_conf->id); + + if (tls_conf->tls_chunk_offset == 0) { + free(*outdata); + *outlen = 0; + if ((*outdata = calloc(1, tls_conf->tls_len)) == NULL) + goto fail; + *outlen = tls_conf->tls_len; + } + + if (*outdata == NULL) { + log_debug("%s: tls config invalid chunk sequence", __func__); + goto fail; + } + + if (*outlen != tls_conf->tls_len) { + log_debug("%s: tls config length mismatch (%zu != %zu)", + __func__, *outlen, tls_conf->tls_len); + goto fail; + } + + if (len > (tls_conf->tls_len - tls_conf->tls_chunk_offset)) { + log_debug("%s: tls config invalid chunk length", __func__); + goto fail; + } + + memcpy(*outdata + tls_conf->tls_chunk_offset, data, len); + + return (0); + + fail: + return (-1); +} + +int +config_getserver_tls(struct httpd *env, struct imsg *imsg) +{ struct server_config *srv_conf = NULL; struct tls_config tls_conf; uint8_t *p = imsg->data; - size_t s; + size_t len; IMSG_SIZE_CHECK(imsg, &tls_conf); memcpy(&tls_conf, p, sizeof(tls_conf)); - s = sizeof(tls_conf); - if ((IMSG_DATA_SIZE(imsg) - s) < - (tls_conf.tls_cert_len + tls_conf.tls_key_len + - tls_conf.tls_ocsp_staple_len)) { + len = tls_conf.tls_chunk_len; + + if ((IMSG_DATA_SIZE(imsg) - sizeof(tls_conf)) < len) { log_debug("%s: invalid message length", __func__); goto fail; } + p += sizeof(tls_conf); + if ((srv_conf = serverconfig_byid(tls_conf.id)) == NULL) { log_debug("%s: server not found", __func__); goto fail; } - DPRINTF("%s: %s %d tls configuration \"%s[%u]\"", __func__, - ps->ps_title[privsep_process], ps->ps_instance, - srv_conf->name, srv_conf->id); - - if (tls_conf.tls_cert_len != 0) { - srv_conf->tls_cert_len = tls_conf.tls_cert_len; - if ((srv_conf->tls_cert = get_data(p + s, - tls_conf.tls_cert_len)) == NULL) + switch (tls_conf.tls_type) { + case TLS_CFG_CERT: + if (config_gettls(env, srv_conf, &tls_conf, "cert", p, len, + &srv_conf->tls_cert, &srv_conf->tls_cert_len) != 0) goto fail; - s += tls_conf.tls_cert_len; - } - if (tls_conf.tls_key_len != 0) { - srv_conf->tls_key_len = tls_conf.tls_key_len; - if ((srv_conf->tls_key = get_data(p + s, - tls_conf.tls_key_len)) == NULL) + break; + + case TLS_CFG_KEY: + if (config_gettls(env, srv_conf, &tls_conf, "key", p, len, + &srv_conf->tls_key, &srv_conf->tls_key_len) != 0) goto fail; - s += tls_conf.tls_key_len; - } - if (tls_conf.tls_ocsp_staple_len != 0) { - srv_conf->tls_ocsp_staple_len = tls_conf.tls_ocsp_staple_len; - if ((srv_conf->tls_ocsp_staple = get_data(p + s, - tls_conf.tls_ocsp_staple_len)) == NULL) + break; + + case TLS_CFG_OCSP_STAPLE: + if (config_gettls(env, srv_conf, &tls_conf, "ocsp staple", + p, len, &srv_conf->tls_ocsp_staple, + &srv_conf->tls_ocsp_staple_len) != 0) goto fail; - s += tls_conf.tls_ocsp_staple_len; + break; + + default: + log_debug("%s: unknown tls config type %i\n", + __func__, tls_conf.tls_type); + goto fail; } return (0); diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index 94e13c6c13e..94891f5dae3 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.132 2017/05/28 10:37:26 benno Exp $ */ +/* $OpenBSD: httpd.h,v 1.133 2017/07/19 17:36:25 jsing Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org> @@ -192,6 +192,7 @@ struct imsgev { fatalx("bad length imsg received"); \ } while (0) #define IMSG_DATA_SIZE(imsg) ((imsg)->hdr.len - IMSG_HEADER_SIZE) +#define MAX_IMSG_DATA_SIZE (MAX_IMSGSIZE - IMSG_HEADER_SIZE) struct ctl_conn { TAILQ_ENTRY(ctl_conn) entry; @@ -518,12 +519,19 @@ struct server_config { }; TAILQ_HEAD(serverhosts, server_config); +enum tls_config_type { + TLS_CFG_CERT, + TLS_CFG_KEY, + TLS_CFG_OCSP_STAPLE, +}; + struct tls_config { uint32_t id; - size_t tls_cert_len; - size_t tls_key_len; - size_t tls_ocsp_staple_len; + enum tls_config_type tls_type; + size_t tls_len; + size_t tls_chunk_len; + size_t tls_chunk_offset; }; struct server { @@ -786,9 +794,9 @@ int config_setreset(struct httpd *, unsigned int); int config_getreset(struct httpd *, struct imsg *); int config_getcfg(struct httpd *, struct imsg *); int config_setserver(struct httpd *, struct server *); -int config_settls(struct httpd *, struct server *); +int config_setserver_tls(struct httpd *, struct server *); int config_getserver(struct httpd *, struct imsg *); -int config_gettls(struct httpd *, struct imsg *); +int config_getserver_tls(struct httpd *, struct imsg *); int config_setmedia(struct httpd *, struct media_type *); int config_getmedia(struct httpd *, struct imsg *); int config_setauth(struct httpd *, struct auth *); diff --git a/usr.sbin/httpd/server.c b/usr.sbin/httpd/server.c index 45be38f1389..8270a85d973 100644 --- a/usr.sbin/httpd/server.c +++ b/usr.sbin/httpd/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.109 2017/04/17 21:58:27 deraadt Exp $ */ +/* $OpenBSD: server.c,v 1.110 2017/07/19 17:36:25 jsing Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org> @@ -1280,7 +1280,7 @@ server_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg) config_getserver(httpd_env, imsg); break; case IMSG_CFG_TLS: - config_gettls(httpd_env, imsg); + config_getserver_tls(httpd_env, imsg); break; case IMSG_CFG_DONE: config_getcfg(httpd_env, imsg); |