Load the SSL public/private keys in the parent process, then provide them
authorjsing <jsing@openbsd.org>
Wed, 6 Aug 2014 02:04:42 +0000 (02:04 +0000)
committerjsing <jsing@openbsd.org>
Wed, 6 Aug 2014 02:04:42 +0000 (02:04 +0000)
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@

usr.sbin/httpd/config.c
usr.sbin/httpd/httpd.8
usr.sbin/httpd/httpd.h
usr.sbin/httpd/parse.y
usr.sbin/httpd/server.c

index 9eb8dd8..95c80a8 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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
index 050bfcd..f7c9da8 100644 (file)
@@ -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 <reyk@openbsd.org>
 .\"
@@ -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
index 74fa3c5..0983ce2 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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);
index 91e18be..9daf57c 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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;
                }
index 7f675e1..8f4b7ce 100644 (file)
@@ -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 <reyk@openbsd.org>
@@ -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);