|
commit 6338b7d4a884639f98823e885325a50750f72e04
|
|
Author: William Lallemand <wlallemand@haproxy.org>
|
|
Date: Tue Dec 28 18:47:17 2021 +0100
|
|
|
|
BUG/MEDIUM: ssl: initialize correctly ssl w/ default-server
|
|
|
|
This bug was introduced by d817dc73 ("MEDIUM: ssl: Load client
|
|
certificates in a ckch for backend servers") in which the creation of
|
|
the SSL_CTX for a server was moved to the configuration parser when
|
|
using a "crt" keyword instead of being done in ssl_sock_prepare_srv_ctx().
|
|
|
|
The patch 0498fa40 ("BUG/MINOR: ssl: Default-server configuration ignored by
|
|
server") made it worse by setting the same SSL_CTX for every servers
|
|
using a default-server. Resulting in any SSL option on a server applied
|
|
to every server in its backend.
|
|
|
|
This patch fixes the issue by reintroducing a string which store the
|
|
path of certificate inside the server structure, and loading the
|
|
certificate in ssl_sock_prepare_srv_ctx() again.
|
|
|
|
This is a quick fix to backport, a cleaner way can be achieve by always
|
|
creating the SSL_CTX in ssl_sock_prepare_srv_ctx() and splitting
|
|
properly the ssl_sock_load_srv_cert() function.
|
|
|
|
This patch fixes issue #1488.
|
|
|
|
Must be backported as far as 2.4.
|
|
|
|
(cherry picked from commit 2c776f1c30c85be11c9ba8ca8d9a7d62690d1a32)
|
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
(cherry picked from commit 2f3c354b6cdc21ee185e263b5c7422c86ae58c98)
|
|
[wt: ssl_sock_load_srv_cert() doesn't take the create_if_none arg in 2.4,
|
|
thus adjust context and make sure ssl_sock_prepare_srv_ctx() matches
|
|
what srv_parse_crt() used to do]
|
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
|
|
--- a/include/haproxy/server-t.h
|
|
+++ b/include/haproxy/server-t.h
|
|
@@ -364,6 +364,7 @@ struct server {
|
|
char *verify_host; /* hostname of certificate must match this host */
|
|
char *ca_file; /* CAfile to use on verify */
|
|
char *crl_file; /* CRLfile to use on verify */
|
|
+ char *client_crt; /* client certificate to send */
|
|
struct sample_expr *sni; /* sample expression for SNI */
|
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
|
char *npn_str; /* NPN protocol string */
|
|
--- a/reg-tests/ssl/ssl_default_server.vtc
|
|
+++ b/reg-tests/ssl/ssl_default_server.vtc
|
|
@@ -15,7 +15,7 @@ feature cmd "$HAPROXY_PROGRAM -cc 'versi
|
|
feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
|
|
feature ignore_unknown_macro
|
|
|
|
-server s1 -repeat 7 {
|
|
+server s1 -repeat 10 {
|
|
rxreq
|
|
txresp
|
|
} -start
|
|
@@ -56,7 +56,10 @@ haproxy h1 -conf {
|
|
|
|
backend third_be
|
|
default-server ssl crt client1.pem ca-file ca-auth.crt verify none
|
|
- server s1 "${tmpdir}/ssl.sock" crt client2_expired.pem
|
|
+ server s1 "${tmpdir}/ssl.sock"
|
|
+ server s2 "${tmpdir}/ssl.sock" crt client2_expired.pem
|
|
+ server s3 "${tmpdir}/ssl.sock"
|
|
+ server s4 "${tmpdir}/ssl.sock"
|
|
|
|
backend fourth_be
|
|
default-server ssl crt client1.pem verify none
|
|
@@ -106,9 +109,25 @@ client c1 -connect ${h1_clearlst_sock} {
|
|
txreq
|
|
rxresp
|
|
expect resp.status == 200
|
|
+ expect resp.http.x-ssl == "Ok"
|
|
+} -run
|
|
+
|
|
+client c1 -connect ${h1_clearlst_sock} {
|
|
+ txreq -url "/third"
|
|
+ txreq
|
|
+ rxresp
|
|
+ expect resp.status == 200
|
|
expect resp.http.x-ssl == "Expired"
|
|
} -run
|
|
|
|
+client c1 -connect ${h1_clearlst_sock} -repeat 2 {
|
|
+ txreq -url "/third"
|
|
+ txreq
|
|
+ rxresp
|
|
+ expect resp.status == 200
|
|
+ expect resp.http.x-ssl == "Ok"
|
|
+} -run
|
|
+
|
|
client c1 -connect ${h1_clearlst_sock} {
|
|
txreq -url "/fourth"
|
|
txreq
|
|
--- a/src/cfgparse-ssl.c
|
|
+++ b/src/cfgparse-ssl.c
|
|
@@ -1450,25 +1450,17 @@ static int srv_parse_crl_file(char **arg
|
|
/* parse the "crt" server keyword */
|
|
static int srv_parse_crt(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
|
{
|
|
- int retval = -1;
|
|
- char *path = NULL;
|
|
-
|
|
if (!*args[*cur_arg + 1]) {
|
|
memprintf(err, "'%s' : missing certificate file path", args[*cur_arg]);
|
|
return ERR_ALERT | ERR_FATAL;
|
|
}
|
|
|
|
if ((*args[*cur_arg + 1] != '/') && global_ssl.crt_base)
|
|
- memprintf(&path, "%s/%s", global_ssl.crt_base, args[*cur_arg + 1]);
|
|
+ memprintf(&newsrv->ssl_ctx.client_crt, "%s/%s", global_ssl.crt_base, args[*cur_arg + 1]);
|
|
else
|
|
- memprintf(&path, "%s", args[*cur_arg + 1]);
|
|
-
|
|
- if (path) {
|
|
- retval = ssl_sock_load_srv_cert(path, newsrv, err);
|
|
- free(path);
|
|
- }
|
|
+ memprintf(&newsrv->ssl_ctx.client_crt, "%s", args[*cur_arg + 1]);
|
|
|
|
- return retval;
|
|
+ return 0;
|
|
}
|
|
|
|
/* parse the "no-check-ssl" server keyword */
|
|
--- a/src/server.c
|
|
+++ b/src/server.c
|
|
@@ -2063,6 +2063,8 @@ static void srv_conn_src_cpy(struct serv
|
|
static void srv_ssl_settings_cpy(struct server *srv, struct server *src)
|
|
{
|
|
/* <src> is the current proxy's default server and SSL is enabled */
|
|
+ BUG_ON(src->ssl_ctx.ctx != NULL); /* the SSL_CTX must never be initialized in a default-server */
|
|
+
|
|
if (src == &srv->proxy->defsrv && src->use_ssl == 1)
|
|
srv->flags |= SRV_F_DEFSRV_USE_SSL;
|
|
|
|
@@ -2070,10 +2072,11 @@ static void srv_ssl_settings_cpy(struct
|
|
srv->ssl_ctx.ca_file = strdup(src->ssl_ctx.ca_file);
|
|
if (src->ssl_ctx.crl_file != NULL)
|
|
srv->ssl_ctx.crl_file = strdup(src->ssl_ctx.crl_file);
|
|
+ if (src->ssl_ctx.client_crt != NULL)
|
|
+ srv->ssl_ctx.client_crt = strdup(src->ssl_ctx.client_crt);
|
|
|
|
srv->ssl_ctx.verify = src->ssl_ctx.verify;
|
|
|
|
- srv->ssl_ctx.ctx = src->ssl_ctx.ctx;
|
|
|
|
if (src->ssl_ctx.verify_host != NULL)
|
|
srv->ssl_ctx.verify_host = strdup(src->ssl_ctx.verify_host);
|
|
--- a/src/ssl_sock.c
|
|
+++ b/src/ssl_sock.c
|
|
@@ -4669,7 +4669,7 @@ int ssl_sock_prepare_srv_ctx(struct serv
|
|
{
|
|
struct proxy *curproxy = srv->proxy;
|
|
int cfgerr = 0;
|
|
- SSL_CTX *ctx = srv->ssl_ctx.ctx;
|
|
+ SSL_CTX *ctx;
|
|
|
|
/* Make sure openssl opens /dev/urandom before the chroot */
|
|
if (!ssl_initialize_random()) {
|
|
@@ -4693,6 +4693,26 @@ int ssl_sock_prepare_srv_ctx(struct serv
|
|
if (srv->use_ssl == 1)
|
|
srv->xprt = &ssl_sock;
|
|
|
|
+ if (srv->ssl_ctx.client_crt) {
|
|
+ char *err = NULL;
|
|
+ int err_code = 0;
|
|
+
|
|
+ /* If there is a crt keyword there, the SSL_CTX will be created here. */
|
|
+ err_code = ssl_sock_load_srv_cert(srv->ssl_ctx.client_crt, srv, &err);
|
|
+ if (err_code != ERR_NONE) {
|
|
+ if ((err_code & ERR_WARN) && !(err_code & ERR_ALERT))
|
|
+ ha_warning("%s", err);
|
|
+ else
|
|
+ ha_alert("%s", err);
|
|
+
|
|
+ if (err_code & (ERR_FATAL|ERR_ABORT))
|
|
+ cfgerr++;
|
|
+ }
|
|
+ ha_free(&err);
|
|
+ }
|
|
+
|
|
+ ctx = srv->ssl_ctx.ctx;
|
|
+
|
|
/* The context will be uninitialized if there wasn't any "cert" option
|
|
* in the server line. */
|
|
if (!ctx) {
|