From: jsing Date: Wed, 6 Aug 2014 02:04:42 +0000 (+0000) Subject: Load the SSL public/private keys in the parent process, then provide them X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=45767b45828a293ea811455369f6b8d538f70f64;p=openbsd Load the SSL public/private keys in the parent process, then provide them to the privsep process via imsg. This allows the keys to be moved out of the chroot (now /etc/ssl/server.crt, /etc/ssl/private/server.key). ok reyk@ --- diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c index 9eb8dd801c1..95c80a8b635 100644 --- a/usr.sbin/httpd/config.c +++ b/usr.sbin/httpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.19 2014/08/05 18:01:10 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.20 2014/08/06 02:04:42 jsing Exp $ */ /* * Copyright (c) 2011 - 2014 Reyk Floeter @@ -184,6 +184,14 @@ config_setserver(struct httpd *env, struct server *srv) c = 0; iov[c].iov_base = &s; iov[c++].iov_len = sizeof(s); + if (srv->srv_conf.ssl_cert_len != 0) { + iov[c].iov_base = srv->srv_conf.ssl_cert; + iov[c++].iov_len = srv->srv_conf.ssl_cert_len; + } + if (srv->srv_conf.ssl_key_len != 0) { + iov[c].iov_base = srv->srv_conf.ssl_key; + iov[c++].iov_len = srv->srv_conf.ssl_key_len; + } if (id == PROC_SERVER && (srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) { @@ -313,7 +321,7 @@ config_getserver(struct httpd *env, struct imsg *imsg) #ifdef DEBUG struct privsep *ps = env->sc_ps; #endif - struct server *srv; + struct server *srv = NULL; struct server_config srv_conf; u_int8_t *p = imsg->data; size_t s; @@ -322,6 +330,12 @@ config_getserver(struct httpd *env, struct imsg *imsg) memcpy(&srv_conf, p, sizeof(srv_conf)); s = sizeof(srv_conf); + if ((u_int)(IMSG_DATA_SIZE(imsg) - s) < + (srv_conf.ssl_cert_len + srv_conf.ssl_key_len)) { + log_debug("%s: invalid message length", __func__); + goto fail; + } + /* Check if server with matching listening socket already exists */ if ((srv = server_byaddr((struct sockaddr *) &srv_conf.ss, srv_conf.port)) != NULL) { @@ -354,7 +368,27 @@ config_getserver(struct httpd *env, struct imsg *imsg) srv->srv_conf.name, printb_flags(srv->srv_conf.flags, SRVFLAG_BITS)); + if (srv->srv_conf.ssl_cert_len != 0) { + if ((srv->srv_conf.ssl_cert = get_data(p + s, + srv->srv_conf.ssl_cert_len)) == NULL) + goto fail; + s += srv->srv_conf.ssl_cert_len; + } + if (srv->srv_conf.ssl_key_len != 0) { + if ((srv->srv_conf.ssl_key = get_data(p + s, + srv->srv_conf.ssl_key_len)) == NULL) + goto fail; + s += srv->srv_conf.ssl_key_len; + } + return (0); + + fail: + free(srv->srv_conf.ssl_cert); + free(srv->srv_conf.ssl_key); + free(srv); + + return (-1); } int diff --git a/usr.sbin/httpd/httpd.8 b/usr.sbin/httpd/httpd.8 index 050bfcdeff2..f7c9da88b39 100644 --- a/usr.sbin/httpd/httpd.8 +++ b/usr.sbin/httpd/httpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: httpd.8,v 1.41 2014/08/04 18:12:15 reyk Exp $ +.\" $OpenBSD: httpd.8,v 1.42 2014/08/06 02:04:42 jsing Exp $ .\" .\" Copyright (c) 2014 Reyk Floeter .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 4 2014 $ +.Dd $Mdocdate: August 6 2014 $ .Dt HTTPD 8 .Os .Sh NAME @@ -36,10 +36,10 @@ Default configuration file. .Ux Ns -domain socket used for communication with .Nm . -.It /var/www/conf/server.key -Default SSL/TLS server key. -.It /var/www/conf/server.crt +.It /etc/ssl/server.crt Default SSL/TLS server certificate. +.It /etc/ssl/private/server.key +Default SSL/TLS server key. .It /var/www/logs/access.log Default access log file. .It /var/www/logs/error.log diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index 74fa3c5dbc5..0983ce22500 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.46 2014/08/05 18:01:10 reyk Exp $ */ +/* $OpenBSD: httpd.h,v 1.47 2014/08/06 02:04:42 jsing Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -38,8 +38,8 @@ #define HTTPD_LOGROOT "/logs" #define HTTPD_ACCESS_LOG "access.log" #define HTTPD_ERROR_LOG "error.log" -#define HTTPD_SSL_KEY "/conf/server.key" -#define HTTPD_SSL_CERT "/conf/server.crt" +#define HTTPD_SSL_KEY "/etc/ssl/private/server.key" +#define HTTPD_SSL_CERT "/etc/ssl/server.crt" #define FD_RESERVE 5 #define SERVER_MAX_CLIENTS 1024 @@ -367,6 +367,13 @@ struct server_config { struct timeval timeout; u_int32_t maxrequests; + char *ssl_cert; + off_t ssl_cert_len; + char *ssl_cert_file; + char *ssl_key; + off_t ssl_key_len; + char *ssl_key_file; + u_int16_t flags; u_int8_t tcpflags; int tcpbufsiz; @@ -446,6 +453,7 @@ int cmdline_symset(char *); /* server.c */ pid_t server(struct privsep *, struct privsep_proc *); +int server_ssl_load_keypair(struct server *); int server_privinit(struct server *); void server_purge(struct server *); int server_socket_af(struct sockaddr_storage *, in_port_t); diff --git a/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y index 91e18bed818..9daf57c7592 100644 --- a/usr.sbin/httpd/parse.y +++ b/usr.sbin/httpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.28 2014/08/05 18:01:10 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.29 2014/08/06 02:04:42 jsing Exp $ */ /* * Copyright (c) 2007 - 2014 Reyk Floeter @@ -233,6 +233,8 @@ server : SERVER STRING { s->srv_conf.maxrequests = SERVER_MAXREQUESTS; s->srv_conf.flags |= SRVFLAG_LOG; s->srv_conf.logformat = LOG_FORMAT_COMMON; + s->srv_conf.ssl_cert_file = HTTPD_SSL_CERT; + s->srv_conf.ssl_key_file = HTTPD_SSL_KEY; if (last_server_id == INT_MAX) { yyerror("too many servers defined"); @@ -250,6 +252,11 @@ server : SERVER STRING { free($2); YYERROR; } + if (server_ssl_load_keypair(srv) == -1) { + yyerror("failed to load public/private keys " + "for server %s", srv->srv_conf.name); + YYERROR; + } srv = NULL; srv_conf = NULL; } diff --git a/usr.sbin/httpd/server.c b/usr.sbin/httpd/server.c index 7f675e1249e..8f4b7ce61ae 100644 --- a/usr.sbin/httpd/server.c +++ b/usr.sbin/httpd/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.29 2014/08/05 15:36:59 reyk Exp $ */ +/* $OpenBSD: server.c,v 1.30 2014/08/06 02:04:42 jsing Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -116,6 +116,57 @@ server_privinit(struct server *srv) return (0); } +static char * +server_load_file(const char *filename, off_t *len) +{ + struct stat st; + off_t size; + char *buf = NULL; + int fd; + + if ((fd = open(filename, O_RDONLY)) == -1) + return (NULL); + if (fstat(fd, &st) != 0) + goto fail; + size = st.st_size; + if ((buf = calloc(1, size + 1)) == NULL) + goto fail; + if (read(fd, buf, size) != size) + goto fail; + + close(fd); + + *len = size; + return (buf); + + fail: + free(buf); + close(fd); + + return (NULL); +} + +int +server_ssl_load_keypair(struct server *srv) +{ + if ((srv->srv_conf.flags & SRVFLAG_SSL) == 0) + return (0); + + if ((srv->srv_conf.ssl_cert = server_load_file( + srv->srv_conf.ssl_cert_file, &srv->srv_conf.ssl_cert_len)) == NULL) + return (-1); + log_debug("%s: using certificate %s", __func__, + srv->srv_conf.ssl_cert_file); + + if ((srv->srv_conf.ssl_key = server_load_file( + srv->srv_conf.ssl_key_file, &srv->srv_conf.ssl_key_len)) == NULL) + return (-1); + log_debug("%s: using private key %s", __func__, + srv->srv_conf.ssl_key_file); + + return (0); +} + int server_ssl_init(struct server *srv) { @@ -137,12 +188,10 @@ server_ssl_init(struct server *srv) return (-1); } - /* - * XXX Make these configurable and move keys out of the chroot. - * XXX The RSA privsep code in relayd should be adopted to ressl. - */ - ressl_config_set_cert_file(srv->srv_ressl_config, HTTPD_SSL_CERT); - ressl_config_set_key_file(srv->srv_ressl_config, HTTPD_SSL_KEY); + ressl_config_set_cert_mem(srv->srv_ressl_config, + srv->srv_conf.ssl_cert, srv->srv_conf.ssl_cert_len); + ressl_config_set_key_mem(srv->srv_ressl_config, + srv->srv_conf.ssl_key, srv->srv_conf.ssl_key_len); if (ressl_configure(srv->srv_ressl_ctx, srv->srv_ressl_config) != 0) { log_warn("%s: failed to configure SSL - %s", __func__, @@ -150,6 +199,12 @@ server_ssl_init(struct server *srv) return (-1); } + /* We're now done with the key... */ + explicit_bzero(srv->srv_conf.ssl_key, srv->srv_conf.ssl_key_len); + free(srv->srv_conf.ssl_key); + srv->srv_conf.ssl_key = NULL; + srv->srv_conf.ssl_key_len = 0; + return (0); } @@ -223,8 +278,11 @@ server_purge(struct server *srv) TAILQ_REMOVE(&srv->srv_hosts, srv_conf, entry); /* It might point to our own "default" entry */ - if (srv_conf != &srv->srv_conf) + if (srv_conf != &srv->srv_conf) { + free(srv_conf->ssl_cert); + free(srv_conf->ssl_key); free(srv_conf); + } } ressl_config_free(srv->srv_ressl_config);