mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-04 18:41:40 +01:00
MEDIUM: ssl/ech: config and load keys
This patch introduces the USE_ECH option in the Makefile to enable support for Encrypted Client Hello (ECH) with OpenSSL. A new function, load_echkeys, is added to load ECH keys from a specified directory. The SSL context initialization process in ssl_sock.c is updated to load these keys if configured. A new configuration directive, `ech`, is introduced to allow users to specify the ECH key directory in the listener configuration.
This commit is contained in:
parent
83e3cbc262
commit
dba4fd248a
4
Makefile
4
Makefile
@ -35,6 +35,7 @@
|
||||
# USE_OPENSSL : enable use of OpenSSL. Recommended, but see below.
|
||||
# USE_OPENSSL_AWSLC : enable use of AWS-LC
|
||||
# USE_OPENSSL_WOLFSSL : enable use of wolfSSL with the OpenSSL API
|
||||
# USE_ECH : enable use of ECH with the OpenSSL API
|
||||
# USE_QUIC : enable use of QUIC with the quictls API (quictls, libressl, boringssl)
|
||||
# USE_QUIC_OPENSSL_COMPAT : enable use of QUIC with the standard openssl API (limited features)
|
||||
# USE_ENGINE : enable use of OpenSSL Engine.
|
||||
@ -341,6 +342,7 @@ use_opts = USE_EPOLL USE_KQUEUE USE_NETFILTER USE_POLL \
|
||||
USE_TPROXY USE_LINUX_TPROXY USE_LINUX_CAP \
|
||||
USE_LINUX_SPLICE USE_LIBCRYPT USE_CRYPT_H USE_ENGINE \
|
||||
USE_GETADDRINFO USE_OPENSSL USE_OPENSSL_WOLFSSL USE_OPENSSL_AWSLC \
|
||||
USE_ECH \
|
||||
USE_SSL USE_LUA USE_ACCEPT4 USE_CLOSEFROM USE_ZLIB USE_SLZ \
|
||||
USE_CPU_AFFINITY USE_TFO USE_NS USE_DL USE_RT USE_LIBATOMIC \
|
||||
USE_MATH USE_DEVICEATLAS USE_51DEGREES \
|
||||
@ -1000,7 +1002,7 @@ OBJS += src/mux_h2.o src/mux_h1.o src/mux_fcgi.o src/log.o \
|
||||
src/ebsttree.o src/freq_ctr.o src/systemd.o src/init.o \
|
||||
src/http_acl.o src/dict.o src/dgram.o src/pipe.o \
|
||||
src/hpack-huff.o src/hpack-enc.o src/ebtree.o src/hash.o \
|
||||
src/httpclient_cli.o src/version.o src/ncbmbuf.o
|
||||
src/httpclient_cli.o src/version.o src/ncbmbuf.o src/ech.o
|
||||
|
||||
ifneq ($(TRACE),)
|
||||
OBJS += src/calltrace.o
|
||||
|
||||
11
include/haproxy/ech.h
Normal file
11
include/haproxy/ech.h
Normal file
@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef _HAPROXY_ECH_H
|
||||
# define _HAPROXY_ECH_H
|
||||
#ifdef USE_ECH
|
||||
|
||||
#include <openssl/ech.h>
|
||||
|
||||
int load_echkeys(SSL_CTX *ctx, char *dirname, int *loaded);
|
||||
|
||||
# endif /* USE_ECH */
|
||||
#endif /* _HAPROXY_ECH_H */
|
||||
@ -152,6 +152,9 @@ struct ssl_bind_conf {
|
||||
char *client_sigalgs; /* Client Signature algorithms */
|
||||
struct tls_version_filter ssl_methods_cfg; /* original ssl methods found in configuration */
|
||||
struct tls_version_filter ssl_methods; /* actual ssl methods used at runtime */
|
||||
#ifdef USE_ECH
|
||||
char *ech_filedir; /* ECH config, file/directory name */
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
100
src/ech.c
Normal file
100
src/ech.c
Normal file
@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#ifdef USE_ECH
|
||||
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <haproxy/applet.h>
|
||||
#include <haproxy/cli.h>
|
||||
#include <haproxy/ech.h>
|
||||
#include <haproxy/fd.h>
|
||||
#include <haproxy/global.h>
|
||||
#include <haproxy/listener.h>
|
||||
#include <haproxy/log.h>
|
||||
#include <haproxy/obj_type.h>
|
||||
#include <haproxy/openssl-compat.h>
|
||||
#include <haproxy/proxy.h>
|
||||
#include <haproxy/ssl_sock-t.h>
|
||||
|
||||
|
||||
/*
|
||||
* load any key files called <name>.ech we find in the named
|
||||
* directory
|
||||
*/
|
||||
int load_echkeys(SSL_CTX *ctx, char *dirname, int *loaded)
|
||||
{
|
||||
struct dirent **de_list = NULL;
|
||||
struct stat thestat;
|
||||
int rv = 0, i, nrv, somekeyworked = 0;
|
||||
char *den = NULL, *last4 = NULL, privname[PATH_MAX];
|
||||
size_t elen = 0, nlen = 0;
|
||||
OSSL_ECHSTORE * const es = OSSL_ECHSTORE_new(NULL, NULL);
|
||||
|
||||
if (es == NULL)
|
||||
goto end;
|
||||
nrv = scandir(dirname, &de_list, 0, alphasort);
|
||||
if (nrv < 0)
|
||||
goto end;
|
||||
for (i = 0; i != nrv; i++) {
|
||||
struct dirent *de = de_list[i];
|
||||
|
||||
den = de->d_name;
|
||||
nlen = strlen(den);
|
||||
if (nlen > 4) {
|
||||
last4 = den + nlen - 4;
|
||||
if (strncmp(last4, ".ech", 4))
|
||||
goto ignore_entry;
|
||||
if ((elen + 1 + nlen + 1) >= PATH_MAX)
|
||||
goto ignore_entry;
|
||||
snprintf(privname, PATH_MAX,"%s/%s", dirname, den);
|
||||
if (stat(privname, &thestat) == 0) {
|
||||
BIO *in = BIO_new_file(privname, "r");
|
||||
const int is_retry_config = OSSL_ECH_FOR_RETRY;
|
||||
|
||||
if (in != NULL && 1 == OSSL_ECHSTORE_read_pem(es, in, is_retry_config))
|
||||
somekeyworked = 1;
|
||||
BIO_free_all(in);
|
||||
}
|
||||
}
|
||||
ignore_entry:
|
||||
free(de);
|
||||
}
|
||||
|
||||
if (somekeyworked == 0)
|
||||
goto end;
|
||||
if (OSSL_ECHSTORE_num_keys(es, loaded) != 1)
|
||||
goto end;
|
||||
if (1 != SSL_CTX_set1_echstore(ctx, es))
|
||||
goto end;
|
||||
rv = 1;
|
||||
end:
|
||||
free(de_list);
|
||||
OSSL_ECHSTORE_free(es);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static int bind_parse_ech(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||
{
|
||||
if (!experimental_directives_allowed) {
|
||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'",
|
||||
args[0]);
|
||||
return -1;
|
||||
}
|
||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
||||
|
||||
free(conf->ssl_conf.ech_filedir);
|
||||
conf->ssl_conf.ech_filedir = strdup(args[cur_arg+1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct bind_kw_list bind_kws = { "SSL", { }, {
|
||||
{ "ech", bind_parse_ech, 1 }, /* set ECH PEM file */
|
||||
{ 0, NULL, 0 },
|
||||
}};
|
||||
|
||||
|
||||
INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
|
||||
#endif
|
||||
@ -90,7 +90,9 @@
|
||||
#include <haproxy/ssl_ocsp.h>
|
||||
#include <haproxy/trace.h>
|
||||
#include <haproxy/ssl_trace.h>
|
||||
|
||||
#ifdef USE_ECH
|
||||
#include <haproxy/ech.h>
|
||||
#endif
|
||||
|
||||
/* ***** READ THIS before adding code here! *****
|
||||
*
|
||||
@ -3954,6 +3956,19 @@ ssl_sock_initial_ctx(struct bind_conf *bind_conf)
|
||||
if (global_ssl.security_level > -1)
|
||||
SSL_CTX_set_security_level(ctx, global_ssl.security_level);
|
||||
|
||||
#ifdef USE_ECH
|
||||
if (bind_conf->ssl_conf.ech_filedir) {
|
||||
int loaded = 0;
|
||||
|
||||
if (load_echkeys(ctx, bind_conf->ssl_conf.ech_filedir, &loaded) != 1) {
|
||||
cfgerr += 1;
|
||||
ha_alert("Proxy '%s': failed to load ECH key s from %s for '%s' at [%s:%d].\n",
|
||||
bind_conf->frontend->id, bind_conf->ssl_conf.ech_filedir,
|
||||
bind_conf->arg, bind_conf->file, bind_conf->line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (conf_ssl_methods->flags && (conf_ssl_methods->min || conf_ssl_methods->max))
|
||||
ha_warning("Proxy '%s': no-sslv3/no-tlsv1x are ignored for bind '%s' at [%s:%d]. "
|
||||
"Use only 'ssl-min-ver' and 'ssl-max-ver' to fix.\n",
|
||||
@ -5320,9 +5335,15 @@ int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf)
|
||||
px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
|
||||
}
|
||||
else {
|
||||
#ifdef USE_ECH
|
||||
if (!bind_conf->ssl_conf.ech_filedir) {
|
||||
#endif
|
||||
ha_alert("Proxy '%s': no SSL certificate specified for bind '%s' at [%s:%d] (use 'crt').\n",
|
||||
px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
|
||||
return -1;
|
||||
#ifdef USE_ECH
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user