On Thursday 14 May 2015, Michal Lesniewski wrote:
On 14.05.2015 15:02, Joel Sing wrote:
On Thursday 14 May 2015, Michal Lesniewski wrote:
Hello,
I'm trying to configure OpenBSD 5.7 httpd with tls with
intermediate/chain certificate without no success.
my httpd.conf:
server "default" {
listen on 10.11.0.200 tls port 443
tls {
certificate "/etc/ssl/server-unified.pem"
key "/etc/ssl/private/server.key"
}
root "/htdocs/default"
}
types {
include "/usr/share/misc/mime.types"
}
My certificate is intermediate/chain certificate. That mean I need to
supply "next level" certificate that is between my certificate and CA.
I made that chain certificate concatenating PEM format files with
corresponding certs (all certs Signature Algorithm:
sha256WithRSAEncryption)
cat server.pem sub.class2.server.ca.pem ca-sha2.pem >
/etc/ssl/server-unified.pem
server-unified.pem looks like:
-----BEGIN CERTIFICATE-----
(Primary SSL certificate: server.pem)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate: sub.class2.server.ca.pem)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Root certificate: ca-sha2.pem)
-----END CERTIFICATE-----
Certificate and key installed in default locations:
# ls -alh /etc/ssl/private/server.key
-r-------- 1 root wheel 6.2K May 13 19:40
/etc/ssl/private/server.key # ls -alh /etc/ssl/server.pem
-rw-r--r-- 1 root wheel 3.3K May 13 19:41 /etc/ssl/server.pem
# ls -alh /etc/ssl/server-unified.pem
-rw-r--r-- 1 root wheel 8.0K May 14 13:53
/etc/ssl/server-unified.pem
I try to test using openssl s_client:
michal@michal-MSQ87TN:~$ openssl s_client -connect 10.11.0.200:443
CONNECTED(00000003)
GET / HTTP/1.0
httpd log:
# httpd -dvvvvvvvvvv
startup
server_tls_load_keypair: using certificate /etc/ssl/server-unified.pem
server_tls_load_keypair: using private key /etc/ssl/private/server.key
socket_rlimit: max open files 1024
socket_rlimit: max open files 1024
server_privinit: adding server default
server_privinit: adding server default
socket_rlimit: max open files 1024
server_launch: running server default
server_launch: running server default
server_launch: running server default
there is no "server_tls_init"
nothing apears when started openssl s_client command
This smells very much like the same problem that has been mentioned on
the list earlier - with a 6KB private key and a 8KB bundle, you're almost
certainly hitting the 16K limit for a single imsg. Unfortunately there
were missing return value checks which means that this fails silently. If
you can try httpd from -current you will likely see an error instead of a
silent failure. Otherwise you can try removing one of the certificates
from the bundle in order to reduce the size and see if it then
reports "server_tls_init" and starts working.
tested on -current:
# httpd -dvvvvvvvvvvvvv
startup
server_tls_load_keypair: using certificate /etc/ssl/server-unified.pem
server_tls_load_keypair: using private key /etc/ssl/private/server.key
socket_rlimit: max open files 1024
server_privinit: adding server default
server_privinit: adding server default
config_setserver: failed to compose IMSG_CFG_SERVER imsg for `default':
Result too large
fatal: send server: Result too large
socket_rlimit: max open files 1024
logger exiting, pid 4965
socket_rlimit: max open files 1024
server exiting, pid 10727
server exiting, pid 32594
server exiting, pid 5337
Above situation occurs when I have server cert + intermediate + ca and
only server cert + intermediate in server-chain.pem.
httpd starts only when I supply only my server cert to it.
Is there any solution to run httpd with such big private key?
Try this (albeit only tested a little beyond compilation...)
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/config.c,v
retrieving revision 1.37
diff -u -p -r1.37 config.c
--- config.c 11 Apr 2015 14:52:49 -0000 1.37
+++ config.c 14 May 2015 13:58:57 -0000
@@ -193,14 +193,6 @@ config_setserver(struct httpd *env, stru
iov[c].iov_base = srv->srv_conf.return_uri;
iov[c++].iov_len = srv->srv_conf.return_uri_len;
}
- if (srv->srv_conf.tls_cert_len != 0) {
- iov[c].iov_base = srv->srv_conf.tls_cert;
- iov[c++].iov_len = srv->srv_conf.tls_cert_len;
- }
- if (srv->srv_conf.tls_key_len != 0) {
- iov[c].iov_base = srv->srv_conf.tls_key;
- iov[c++].iov_len = srv->srv_conf.tls_key_len;
- }
if (id == PROC_SERVER &&
(srv->srv_conf.flags & SRVFLAG_LOCATION) == 0) {
@@ -220,6 +212,9 @@ config_setserver(struct httpd *env, stru
return (-1);
}
}
+
+ /* Configure TLS if necessary. */
+ config_settls(env, srv);
} else {
if (proc_composev_imsg(ps, id, -1, IMSG_CFG_SERVER, -1,
iov, c) != 0) {
@@ -235,6 +230,72 @@ config_setserver(struct httpd *env, stru
}
int
+config_settls(struct httpd *env, struct server *srv)
+{
+ struct privsep *ps = env->sc_ps;
+ struct tls_config tls;
+ struct iovec iov[2];
+ size_t c;
+
+ if ((srv->srv_conf.flags & SRVFLAG_TLS) == 0)
+ return (0);
+
+ log_debug("%s: configuring TLS for %s", __func__, srv->srv_conf.name);
+
+ if (srv->srv_conf.tls_cert_len != 0) {
+ DPRINTF("%s: sending TLS cert \"%s[%u]\" to %s fd %d", __func__,
+ srv->srv_conf.name, srv->srv_conf.id,
+ ps->ps_title[PROC_SERVER], srv->srv_s);
+
+ memset(&tls, 0, sizeof(tls));
+ tls.id = srv->srv_conf.id;
+ tls.port = srv->srv_conf.port;
+ memcpy(&tls.ss, &srv->srv_conf.ss, sizeof(tls.ss));
+ tls.tls_cert_len = srv->srv_conf.tls_cert_len;
+
+ c = 0;
+ iov[c].iov_base = &tls;
+ iov[c++].iov_len = sizeof(tls);
+ iov[c].iov_base = srv->srv_conf.tls_cert;
+ iov[c++].iov_len = srv->srv_conf.tls_cert_len;
+
+ if (proc_composev_imsg(ps, PROC_SERVER, -1, IMSG_CFG_TLS, -1,
+ iov, c) != 0) {
+ log_warn("%s: failed to compose IMSG_CFG_TLS imsg for "
+ "`%s'", __func__, srv->srv_conf.name);
+ return (-1);
+ }
+ }
+
+ if (srv->srv_conf.tls_key_len != 0) {
+ DPRINTF("%s: sending TLS key \"%s[%u]\" to %s fd %d", __func__,
+ srv->srv_conf.name, srv->srv_conf.id,
+ ps->ps_title[PROC_SERVER], srv->srv_s);
+
+ memset(&tls, 0, sizeof(tls));
+ tls.id = srv->srv_conf.id;
+ tls.port = srv->srv_conf.port;
+ memcpy(&tls.ss, &srv->srv_conf.ss, sizeof(tls.ss));
+ tls.tls_key_len = srv->srv_conf.tls_key_len;
+
+ c = 0;
+ iov[c].iov_base = &tls;
+ iov[c++].iov_len = sizeof(tls);
+ iov[c].iov_base = srv->srv_conf.tls_key;
+ iov[c++].iov_len = srv->srv_conf.tls_key_len;
+
+ if (proc_composev_imsg(ps, PROC_SERVER, -1, IMSG_CFG_TLS, -1,
+ iov, c) != 0) {
+ log_warn("%s: failed to compose IMSG_CFG_TLS imsg for "
+ "`%s'", __func__, srv->srv_conf.name);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int
config_getserver_auth(struct httpd *env, struct server_config *srv_conf)
{
struct privsep *ps = env->sc_ps;
@@ -422,9 +483,7 @@ config_getserver(struct httpd *env, stru
/* Reset these variables to avoid free'ing invalid pointers */
serverconfig_reset(&srv_conf);
- if ((IMSG_DATA_SIZE(imsg) - s) <
- (srv_conf.tls_cert_len + srv_conf.tls_key_len +
- srv_conf.return_uri_len)) {
+ if ((IMSG_DATA_SIZE(imsg) - s) < (size_t)srv_conf.return_uri_len) {
log_debug("%s: invalid message length", __func__);
goto fail;
}
@@ -475,17 +534,64 @@ config_getserver(struct httpd *env, stru
goto fail;
s += srv->srv_conf.return_uri_len;
}
- if (srv->srv_conf.tls_cert_len != 0) {
+
+ return (0);
+
+ fail:
+ if (imsg->fd != -1)
+ close(imsg->fd);
+ if (srv != NULL)
+ free(srv->srv_conf.return_uri);
+ free(srv);
+
+ return (-1);
+}
+
+int
+config_gettls(struct httpd *env, struct imsg *imsg)
+{
+#ifdef DEBUG
+ struct privsep *ps = env->sc_ps;
+#endif
+ struct server *srv = NULL;
+ struct tls_config tls_conf;
+ u_int8_t *p = imsg->data;
+ size_t s;
+
+ 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)) {
+ log_debug("%s: invalid message length", __func__);
+ goto fail;
+ }
+
+ /* Find server with matching listening socket. */
+ if ((srv = server_byaddr((struct sockaddr *)
+ &tls_conf.ss, tls_conf.port)) == 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->srv_conf.name, srv->srv_conf.id);
+
+ if (tls_conf.tls_cert_len != 0) {
+ srv->srv_conf.tls_cert_len = tls_conf.tls_cert_len;
if ((srv->srv_conf.tls_cert = get_data(p + s,
- srv->srv_conf.tls_cert_len)) == NULL)
+ tls_conf.tls_cert_len)) == NULL)
goto fail;
- s += srv->srv_conf.tls_cert_len;
+ s += tls_conf.tls_cert_len;
}
- if (srv->srv_conf.tls_key_len != 0) {
+ if (tls_conf.tls_key_len != 0) {
+ srv->srv_conf.tls_key_len = tls_conf.tls_key_len;
if ((srv->srv_conf.tls_key = get_data(p + s,
- srv->srv_conf.tls_key_len)) == NULL)
+ tls_conf.tls_key_len)) == NULL)
goto fail;
- s += srv->srv_conf.tls_key_len;
+ s += tls_conf.tls_key_len;
}
return (0);
@@ -493,11 +599,6 @@ config_getserver(struct httpd *env, stru
fail:
if (imsg->fd != -1)
close(imsg->fd);
- if (srv != NULL) {
- free(srv->srv_conf.tls_cert);
- free(srv->srv_conf.tls_key);
- }
- free(srv);
return (-1);
}
Index: httpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
retrieving revision 1.82
diff -u -p -r1.82 httpd.h
--- httpd.h 15 Mar 2015 22:08:45 -0000 1.82
+++ httpd.h 14 May 2015 13:58:57 -0000
@@ -199,6 +199,7 @@ enum imsg_type {
IMSG_CTL_START,
IMSG_CTL_REOPEN,
IMSG_CFG_SERVER,
+ IMSG_CFG_TLS,
IMSG_CFG_MEDIA,
IMSG_CFG_AUTH,
IMSG_CFG_DONE,
@@ -436,6 +437,18 @@ struct server_config {
};
TAILQ_HEAD(serverhosts, server_config);
+struct tls_config {
+ u_int32_t id;
+
+ in_port_t port;
+ struct sockaddr_storage ss;
+
+ u_int8_t *tls_cert;
+ size_t tls_cert_len;
+ u_int8_t *tls_key;
+ size_t tls_key_len;
+};
+
struct server {
TAILQ_ENTRY(server) srv_entry;
struct server_config srv_conf;
@@ -674,7 +687,9 @@ int config_setreset(struct httpd *, u_i
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_getserver(struct httpd *, struct imsg *);
+int config_gettls(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 *);
Index: server.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server.c,v
retrieving revision 1.63
diff -u -p -r1.63 server.c
--- server.c 23 Apr 2015 16:59:28 -0000 1.63
+++ server.c 14 May 2015 13:58:57 -0000
@@ -1118,6 +1118,9 @@ server_dispatch_parent(int fd, struct pr
case IMSG_CFG_SERVER:
config_getserver(env, imsg);
break;
+ case IMSG_CFG_TLS:
+ config_gettls(env, imsg);
+ break;
case IMSG_CFG_DONE:
config_getcfg(env, imsg);
break;