mirror of
https://github.com/yrutschle/sslh.git
synced 2026-10-22 18:12:10 +03:00
ECH configuration generation for each SNI, with DNS configuration printed in logs
This commit is contained in:
1 parent
6219527ce4
commit
6d50082993
6 files changed
+184
-1
No files matched your search
+1
-1
@@ -35,7 +35,7 @@ CFLAGS +=-Wall -O2 -DLIBPCRE -g $(CFLAGS_COV) $(CFLAGS_SAN)
|
||||
|
||||
|
||||
LIBS=-lm -lpcre2-8 @LIBS@
|
||||
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o collection.o gap.o tcp-probe.o landlock.o proxyprotocol.o
|
||||
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o tls_ech.o argtable3.o collection.o gap.o tcp-probe.o landlock.o proxyprotocol.o
|
||||
OBJS_A=libsslh.a
|
||||
FORK_OBJS=sslh-fork.o $(OBJS_A)
|
||||
SELECT_OBJS=processes.o udp-listener.o sslh-select.o hash.o tcp-listener.o $(OBJS_A)
|
||||
|
||||
@@ -18,4 +18,7 @@
|
||||
/* libbsd, to change process name */
|
||||
#undef HAVE_LIBBSD
|
||||
|
||||
/* wolfssl, to support Encrypted Client Hello (ECH) */
|
||||
#undef HAVE_WOLFSSL
|
||||
|
||||
#endif
|
||||
@@ -3329,6 +3329,47 @@ then :
|
||||
LIBS="$LIBS -lbsd"
|
||||
fi
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wolfSSL_Init in -lwolfssl" >&5
|
||||
printf %s "checking for wolfSSL_Init in -lwolfssl... " >&6; }
|
||||
if test ${ac_cv_lib_wolfssl_wolfSSL_Init+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else $as_nop
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lwolfssl $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char wolfSSL_Init ();
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return wolfSSL_Init ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"
|
||||
then :
|
||||
ac_cv_lib_wolfssl_wolfSSL_Init=yes
|
||||
else $as_nop
|
||||
ac_cv_lib_wolfssl_wolfSSL_Init=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wolfssl_wolfSSL_Init" >&5
|
||||
printf "%s\n" "$ac_cv_lib_wolfssl_wolfSSL_Init" >&6; }
|
||||
if test "x$ac_cv_lib_wolfssl_wolfSSL_Init" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_WOLFSSL 1" >>confdefs.h
|
||||
LIBS="$LIBS -lwolfssl"
|
||||
fi
|
||||
|
||||
|
||||
ac_header= ac_cache=
|
||||
for ac_item in $ac_header_c_list
|
||||
|
||||
@@ -347,6 +347,8 @@ int main(int argc, char *argv[], char* envp[])
|
||||
/* Open log file for writing */
|
||||
setup_logfile();
|
||||
|
||||
ech_init();
|
||||
|
||||
if (cfg.user || cfg.chroot)
|
||||
drop_privileges(cfg.user, cfg.chroot);
|
||||
setup_landlock();
|
||||
|
||||
@@ -18,6 +18,7 @@ includes: (
|
||||
"probe.h",
|
||||
" <sys/types.h>",
|
||||
" <sys/socket.h>",
|
||||
" <wolfssl/ssl.h>",
|
||||
" <netdb.h>"
|
||||
);
|
||||
|
||||
@@ -130,6 +131,10 @@ config: {
|
||||
type: "array",
|
||||
element_type: "string"
|
||||
},
|
||||
{ name: "wolfssl_ctx", # One context object per public hostname; they will have the same index as prot->sni_hostnames
|
||||
type: "runtime",
|
||||
c_type: "WOLFSSL_CTX**"
|
||||
},
|
||||
{ name: "alpn_protocols",
|
||||
type: "array",
|
||||
element_type: "string"
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
# tls_ech.c: support for RFC9849 TLS Encrypted Client Hello (ECH)
|
||||
#
|
||||
# Copyright (C) 2026 Yves Rutschle
|
||||
#
|
||||
# This program is free software; you can redistribute it
|
||||
# and/or modify it under the terms of the GNU General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be
|
||||
# useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
# PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# The full text for the General Public License is here:
|
||||
# http://www.gnu.org/licenses/gpl.html
|
||||
|
||||
*/
|
||||
|
||||
#define WOLFSSL_USE_OPTION_H
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/wolfcrypt/random.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
#include "log.h"
|
||||
#include "sslh-conf.h"
|
||||
|
||||
|
||||
void ech_get_client_hello_inner(const char* data, size_t datalen)
|
||||
{
|
||||
#if 0
|
||||
WOLFSSL_CTX* ctx = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
|
||||
ssl = wolfSSL_new(ctx);
|
||||
if (ssl == NULL) {
|
||||
fprintf(stderr, "Failed to create WOLFSSL object\n");
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable certificate verification on this connection
|
||||
wolfSSL_set_verify(ssl, WOLFSSL_VERIFY_NONE, NULL);
|
||||
|
||||
|
||||
char* sni_data = NULL;
|
||||
word16 sni_len = wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, (void**)&sni_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ech_match_sni(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Generate a keypair for a config; later this will be moved to a separate
|
||||
* process, and sslh will just read it */
|
||||
static void ech_genkey(WOLFSSL_CTX* ctx, const char* sni)
|
||||
{
|
||||
int ret;
|
||||
|
||||
print_message(msg_config, "Generating ECH config for outer SNI: %s\n", sni);
|
||||
ret = wolfSSL_CTX_GenerateEchConfig(ctx, sni, 0, 0, 0);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
print_message(msg_system_error, "Failed to generate ECH config: %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
byte echConfig[512];
|
||||
word32 echConfigLen = sizeof(echConfig);
|
||||
ret = wolfSSL_CTX_GetEchConfigs(ctx, echConfig, &echConfigLen);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
print_message(msg_system_error, "Failed to get ECH config: %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char out[512];
|
||||
int outLen = sizeof(out);
|
||||
if (Base64_Encode_NoNl(echConfig, echConfigLen, (byte*)out, &outLen) != 0) {
|
||||
print_message(msg_system_error, "Failed to encode to base64: %d\n", ret);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print_message(msg_config, "%s. IN HTTPS 1 . alpn=\"h2\" ech=\"%s\"\n", sni, out);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* For all server names, create a keypair and configuration.
|
||||
* (Later, this will load the configurations from some place else */
|
||||
static void ech_load_configs(WOLFSSL_CTX* ctx)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < cfg.protocols_len; i++) {
|
||||
struct sslhcfg_protocols_item* prot = &cfg.protocols[i];
|
||||
prot->wolfssl_ctx = malloc(prot->sni_hostnames_len * sizeof(prot->wolfssl_ctx[0]));
|
||||
/* TODO deal with malloc failure */
|
||||
|
||||
for (j = 0; j < prot->sni_hostnames_len; j++) {
|
||||
prot->wolfssl_ctx[j] = wolfSSL_CTX_new(wolfTLSv1_3_server_method());
|
||||
if (prot->wolfssl_ctx[j] == NULL) {
|
||||
print_message(msg_system_error, "Failed to create WOLFSSL_CTX\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ech_genkey(prot->wolfssl_ctx[j], prot->sni_hostnames[j]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Initialises the ECH subsystem: create wolfSSL context, create ECH configs,
|
||||
* etc */
|
||||
void ech_init()
|
||||
{
|
||||
|
||||
wolfSSL_Init();
|
||||
|
||||
ech_load_configs(NULL);
|
||||
}
|
||||
Reference in new issue
Block a user