incoming TLS connections get routed to GetEchClientHelloInner

This commit is contained in:
Yves Rutschle committed 2026-08-20 07:56:34 +00:00
1 parent 34645a62b2
commit 17a0425f4f
10 files changed
+304 -48

No files matched your search

+37
View File
@@ -1,3 +1,40 @@
ech branch:
This is an experimental version and does not work.
Do not use it unless you are experimenting with ECH
and an experimental wolfSSL.
A lot of context is discussed here:
https://github.com/wolfSSL/wolfssl/issues/10485
What it does:
- It creates a public ECH configuration for the
first public name (configure in the `listen`
section of the configuration file). This gets
printed in a file configured in `ech_conf_sink`
(see ech_test.cfg example).
- Upon incoming connections, it will call an
imaginary wolfSSL_GetEchClientHelloInner().
The resulting packet is hexdumped.
- It will also use wolfSSL to decode the SNI and
print it (but does not yet use it to forward).
Most things happen in tls_ech.c, in particular there
is a stub of GetEchClientHelloInner() that needs to
be removed when the function becomes available in
wolfSSL.
TODO:
Change configure script to check for appropriate
wolfSSL version.
Create ECH configurations for each public name
Link decoded InnerHello to SNI extraction code
....
Error cases still to be worked out (see
conversations on github)
Profit!
v2.3.0:
Added `max_connections` setting to `listen` and
`protocol` configuration; see the
+3
View File
@@ -11,6 +11,9 @@ AC_CHECK_LIB([wrap], [hosts_ctl], [AC_DEFINE(HAVE_LIBWRAP) LIBS="$LIBS -lwrap" ]
AC_CHECK_LIB([cap], [cap_get_proc], [AC_DEFINE(HAVE_LIBCAP) LIBS="$LIBS -lcap" ], [])
AC_CHECK_LIB([bsd], [setproctitle], [AC_DEFINE(HAVE_LIBBSD) LIBS="$LIBS -lbsd" ], [])
dnl TODO: check that wolfssl contains wolfSSL_GetEchClientHelloInner instead of just existing
AC_CHECK_LIB([wolfssl], [wolfSSL_Init], [AC_DEFINE(HAVE_WOLFSSL) LIBS="$LIBS -lwolfssl" ], [])
AC_CHECK_HEADERS(linux/landlock.h, AC_DEFINE(HAVE_LANDLOCK), [])
AC_CHECK_HEADERS(proxy_protocol.h, [AC_DEFINE(HAVE_PROXYPROTOCOL) LIBS="$LIBS -lproxyprotocol" ], [])
+45
View File
@@ -0,0 +1,45 @@
# sslh configuration for saaz:
# ssh to localhost
# https to nextcloud
foreground: true;
inetd: false;
numeric: false;
transparent: false;
user: "yves";
pidfile: "/tmp/sslh.pid";
syslog_facility: "auth";
# Where to write the ECH configurations
ech_conf_sink: "/tmp/ech";
# Logging configuration
# Value: 1: stdout; 2: syslog; 3: stdout+syslog; 4: logfile; ...; 7: all
verbose: 1;
# Change hostname with your external address name.
listen:
(
{ host: "inet"; port: "4443"; },
{ host: "chaton"; port: "4445"; }
);
protocols:
(
{ name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; fork: true; },
{ name: "tls"; sni_hostnames: [
"inet.rutschle.net", "lists.rutschle.net"
];
host: "localhost"; port: "4453"; },
{ name: "tls"; sni_hostnames: [
"chaton.rutschle.net"
];
host: "localhost"; port: "4455"; }
);
on-timeout: "ssh";
+61 -15
View File
@@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Wed Sep 10 15:49:49 2025.
* on Sat Jul 18 17:34:37 2026.
# conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2024 Yves Rutschle
@@ -482,6 +482,8 @@ struct arg_file* sslhcfg_conffile;
struct arg_str* sslhcfg_chroot;
struct arg_str* sslhcfg_syslog_facility;
struct arg_str* sslhcfg_logfile;
struct arg_str* sslhcfg_ech_conf_sink;
struct arg_str* sslhcfg_ech_public_name;
struct arg_str* sslhcfg_on_timeout;
struct arg_str* sslhcfg_prefix;
struct arg_str* sslhcfg_listen;
@@ -1314,6 +1316,38 @@ static struct config_desc table_sslhcfg[] = {
/* default_val*/ .default_val.def_string = NULL
},
{
/* name */ "ech_conf_sink",
/* type */ CFG_STRING,
/* sub_group*/ NULL,
/* arg_cl */ & sslhcfg_ech_conf_sink,
/* base_addr */ NULL,
/* offset */ offsetof(struct sslhcfg_item, ech_conf_sink),
/* offset_len */ 0,
/* offset_present */ offsetof(struct sslhcfg_item, ech_conf_sink_is_present),
/* size */ sizeof(char*),
/* array_type */ -1,
/* mandatory */ 0,
/* optional */ 1,
/* default_val*/ .default_val.def_string = NULL
},
{
/* name */ "ech_public_name",
/* type */ CFG_STRING,
/* sub_group*/ NULL,
/* arg_cl */ & sslhcfg_ech_public_name,
/* base_addr */ NULL,
/* offset */ offsetof(struct sslhcfg_item, ech_public_name),
/* offset_len */ 0,
/* offset_present */ offsetof(struct sslhcfg_item, ech_public_name_is_present),
/* size */ sizeof(char*),
/* array_type */ -1,
/* mandatory */ 0,
/* optional */ 1,
/* default_val*/ .default_val.def_string = NULL
},
{
/* name */ "on_timeout",
/* type */ CFG_STRING,
@@ -1500,7 +1534,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: listen */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_listen,
.base_entry = & table_sslhcfg [26],
.base_entry = & table_sslhcfg [28],
.targets = sslhcfg_listen_targets,
@@ -1512,7 +1546,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: ssh */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_ssh,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_ssh_targets,
@@ -1524,7 +1558,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: tls */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_tls,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_tls_targets,
@@ -1536,7 +1570,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: ssl */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_ssl,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_ssl_targets,
@@ -1548,7 +1582,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: openvpn */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_openvpn,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_openvpn_targets,
@@ -1560,7 +1594,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: tinc */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_tinc,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_tinc_targets,
@@ -1572,7 +1606,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: wireguard */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_wireguard,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_wireguard_targets,
@@ -1584,7 +1618,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: xmpp */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_xmpp,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_xmpp_targets,
@@ -1596,7 +1630,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: http */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_http,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_http_targets,
@@ -1608,7 +1642,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: adb */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_adb,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_adb_targets,
@@ -1620,7 +1654,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: socks5 */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_socks5,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_socks5_targets,
@@ -1632,7 +1666,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: syslog */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_syslog,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_syslog_targets,
@@ -1644,7 +1678,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: msrdp */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_msrdp,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_msrdp_targets,
@@ -1656,7 +1690,7 @@ static struct compound_cl_arg compound_cl_args[] = {
{ /* arg: anyprot */
.regex = "(.+):(\\w+)",
.arg_cl = & sslhcfg_anyprot,
.base_entry = & table_sslhcfg [27],
.base_entry = & table_sslhcfg [29],
.targets = sslhcfg_anyprot_targets,
@@ -2345,6 +2379,8 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg)
sslhcfg_chroot = arg_strn("C", "chroot", "<path>", 0, 1, "Root to change to after set-up"),
sslhcfg_syslog_facility = arg_strn(NULL, "syslog-facility", "<str>", 0, 1, "Facility to syslog to"),
sslhcfg_logfile = arg_strn(NULL, "logfile", "<str>", 0, 1, "Log messages to a file"),
sslhcfg_ech_conf_sink = arg_strn(NULL, "ech-conf-sink", "<str>", 0, 1, "File where to write ECH configurations"),
sslhcfg_ech_public_name = arg_strn(NULL, "ech-public-name", "<str>", 0, 1, "Public name for ECH client-facing proxy (usually, sslh's address)"),
sslhcfg_on_timeout = arg_strn(NULL, "on-timeout", "<str>", 0, 1, "Target to connect to when timing out"),
sslhcfg_prefix = arg_strn(NULL, "prefix", "<str>", 0, 1, "Reserved for testing"),
sslhcfg_listen = arg_strn("p", "listen", "<host:port>", 0, 10, "Listen on host:port"),
@@ -2621,6 +2657,16 @@ void sslhcfg_fprint(
fprintf(out, " <unset>");
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "ech_conf_sink: %s", sslhcfg->ech_conf_sink);
if (! sslhcfg->ech_conf_sink_is_present)
fprintf(out, " <unset>");
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "ech_public_name: %s", sslhcfg->ech_public_name);
if (! sslhcfg->ech_public_name_is_present)
fprintf(out, " <unset>");
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "on_timeout: %s", sslhcfg->on_timeout);
fprintf(out, "\n");
indent(out, depth);
+6 -1
View File
@@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Wed Sep 10 15:49:49 2025.
* on Sat Jul 18 17:34:37 2026.
# conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2024 Yves Rutschle
@@ -38,6 +38,7 @@
#include "probe.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <wolfssl/ssl.h>
#include <netdb.h>
struct sslhcfg_listen_item {
@@ -114,6 +115,10 @@ struct sslhcfg_item {
char* syslog_facility;
int logfile_is_present;
char* logfile;
int ech_conf_sink_is_present;
char* ech_conf_sink;
int ech_public_name_is_present;
char* ech_public_name;
char* on_timeout;
char* prefix;
size_t listen_len;
+1 -1
View File
@@ -347,7 +347,7 @@ int main(int argc, char *argv[], char* envp[])
/* Open log file for writing */
setup_logfile();
ech_init();
ech_init(listen_sockets, num_addr_listen);
if (cfg.user || cfg.chroot)
drop_privileges(cfg.user, cfg.chroot);
+2 -4
View File
@@ -86,6 +86,8 @@ config: {
description: "Facility to syslog to"; },
{ name: "logfile"; type: "string"; optional: true;
description: "Log messages to a file" },
{ name: "ech_conf_sink"; type: "string"; optional: true;
description: "File where to write ECH configurations" },
{ name: "on-timeout"; type: "string"; default: "ssh";
description: "Target to connect to when timing out"; },
@@ -131,10 +133,6 @@ 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"
+6
View File
@@ -61,6 +61,7 @@ static int parse_server_name_extension(const struct TLSProtocol *, const char *,
static int parse_alpn_extension(const struct TLSProtocol *, const char *, size_t);
static int has_match(const char**, size_t, const char*, size_t);
/* Parse a TLS packet for the Server Name Indication and ALPN extension in the client
* hello handshake, returning a status code
*
@@ -81,6 +82,11 @@ parse_tls_header(const struct TLSProtocol *tls_data, const char *data, size_t da
if (data_len < TLS_HEADER_LEN)
return TLS_ELENGTH;
/* If if it is an ECH, decrypt and match */
ech_match_sni(data, data_len);
tls_content_type = data[0];
if (tls_content_type != TLS_HANDSHAKE_CONTENT_TYPE) {
print_message(msg_probe_info, "Request did not begin with TLS handshake.\n");
+1
View File
@@ -44,5 +44,6 @@ struct TLSProtocol *tls_data_set_list(struct TLSProtocol *, int, const char**, s
#define TLS_ENOEXT -4 /* No ALPN or SNI extension found */
#define TLS_EPROTOCOL -5 /* Protocol error */
void ech_match_sni(const char* buffer_in, size_t buffer_len);
#endif
+142 -27
View File
@@ -33,34 +33,134 @@
#include <arpa/inet.h>
#include "config.h"
#include "log.h"
#include "sslh-conf.h"
#include "tls.h"
WOLFSSL_CTX* wolfssl_ctx;
void ech_get_client_hello_inner(const char* data, size_t datalen)
// Hard-coded server certificate (PEM format)
// from snakeoil -- these serves no purpose beyond initialising the context
static const char* SERVER_CERT_PEM =
"-----BEGIN CERTIFICATE-----\n"
"MIICyjCCAbKgAwIBAgIUZrCzD4tEIu1r9EhkOn96raiupe4wDQYJKoZIhvcNAQEL\n"
"BQAwDzENMAsGA1UEAwwEc2FhejAeFw0yMTA1MjgyMDM0MjRaFw0zMTA1MjYyMDM0\n"
"MjRaMA8xDTALBgNVBAMMBHNhYXowggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n"
"AoIBAQC5s1UhjcmsrRnSdJMH82NxRQ3hlwMxGZz5NnI0MukXN5kptAYSge4BQc6J\n"
"MAL1MbPtX0pfR+yBILWUdn6JCnDqhv9ipO8OpeVeh+RKa2kGiEdeoQhBbKNZdsoe\n"
"gD9FE3lE895GIhEv7Jd9bt/r8CcCpmOLuhJF6md0cLWGPrAp4l+iCV/ixyE0z0bK\n"
"fJzuOxi7oIeINLEiR0Z4hJsM2XAEXlBEsI4oh2KdDJiU6ow3w25IY7+/nYVDDLD2\n"
"QFMByfkEmAGp9Br+2tquRUmR8qmSvZPMtWpOzMv8+iKTrxUcAUCtCpDMjHqNR8fd\n"
"6G6TLenPbQPEaac5UgGZ7rJvL9idAgMBAAGjHjAcMAkGA1UdEwQCMAAwDwYDVR0R\n"
"BAgwBoIEc2FhejANBgkqhkiG9w0BAQsFAAOCAQEAZPasi1Hu7q4S9wJsbIzcGj7m\n"
"ZCAxNdm3AINeV3mxfhToeqtXSoa2sujCEgwCuiYi0OE8wmseLO8e1xIsRc/NEpOl\n"
"h9u5OupV2Xbf7nuKzPl31YQ7kv+90mnixizf6CFpHXAdU3WEZ33+fMtS+lV/ZBYo\n"
"Nh9GGNJ7Grv5KIKu/b2cR403pRF1hGrjWABrIDZO3ZCtNgRp/My1Qr+/04rTs8VF\n"
"WyDshOe0u6Xo//M3sCMbx5+62BopCMmAu2TxiPew0OTM8eDa3IBbc2kLGxp8c4J+\n"
"EYpAKTZbkhs/6SleNMC4BOEmZQ1tk6D0N0u4Y0b1IKEjgx7HqwZ6mIdmbU1lZQ==\n"
"-----END CERTIFICATE-----\n";
static const char* SERVER_KEY_PEM =
"-----BEGIN PRIVATE KEY-----\n"
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5s1UhjcmsrRnS\n"
"dJMH82NxRQ3hlwMxGZz5NnI0MukXN5kptAYSge4BQc6JMAL1MbPtX0pfR+yBILWU\n"
"dn6JCnDqhv9ipO8OpeVeh+RKa2kGiEdeoQhBbKNZdsoegD9FE3lE895GIhEv7Jd9\n"
"bt/r8CcCpmOLuhJF6md0cLWGPrAp4l+iCV/ixyE0z0bKfJzuOxi7oIeINLEiR0Z4\n"
"hJsM2XAEXlBEsI4oh2KdDJiU6ow3w25IY7+/nYVDDLD2QFMByfkEmAGp9Br+2tqu\n"
"RUmR8qmSvZPMtWpOzMv8+iKTrxUcAUCtCpDMjHqNR8fd6G6TLenPbQPEaac5UgGZ\n"
"7rJvL9idAgMBAAECggEAbXNQctViD596/7rryhze+KztsI/UNsVU6uH3T+LN1XxU\n"
"jurnRVNFV4JU3DDrHV9tIDQw3pXCxJzlyRpKHDWGNgTZU2fI6sZGuX+4w1Apd8ss\n"
"3Y5mEkGYyaslF/MY13rR2B0wXf/IR4nYA/ssiaBjLcGqHHnQOVseHNgtdXFPXW9n\n"
"5IXJ2PSeaFW0Z13vbTQm9Cx2kCBKL4J3TymhkuSW3DUHxmlDfWUK14lkyXCZIZ3i\n"
"TbXQAXhwTrz3wqbG++iEP4MZM0Ka7/+WXqrsxA/yCirb+HnMewxwBKzGvkym2I2H\n"
"3BkjDn9exDgTePD7i0w22UYCF5uezDB9YOiPVZ634QKBgQDyKIgxD7XMMJezeg0Y\n"
"PaG+Eig/hE27mm2pyTQSd6MMZ1HpbDUpLQ/GO3Npy+bKS0/5eefNT4PWVcmpRL4W\n"
"blNIfixkcZq1a6wax9Nhk89jXZdhBinO8gfXFOiANFDS7B4fEXeTrfhmuryqUw9m\n"
"L6GJ0jk/H6fs6ads15y+O7A6tQKBgQDEUKlZg4qXxNMNKq7l+v7R6IH8VrNLt0I/\n"
"f4fhpW3IhmPJCRuOFOS0UpDPYjTeu14i3EFcpe0D+DVoQiggBTAh3I/qMHvRko5g\n"
"DT83YHp2/ec0AY0ocwnLwye224t6GF7S8R8vhG1FkIBk6DTJgWFZLDtY+dekZugz\n"
"IHvgtxSPSQKBgHWD7fPBJ/xbaIMUq94jqqZOsXGBhyePncBTgA2mOV3/leStOm8t\n"
"CwasOyoQZYOuYLU0z6T2/Ye6Qg7+6TCBgbEgafKknuuDwRWN+6rSzEXwWVIgZ5Gi\n"
"KuPZparxuHdjVorFMz5borxXys7tV//DBaWYe2eCuT9jdHiBefNni/IxAoGAWHTn\n"
"+deVqVEcsAAdkq8IBtk3SNZgL6vBhA8Y0QnTb9luOPWLnve3HbFeYrOjkwDmJ9sK\n"
"8I4rP/ClT/cPUW5FA9z4U9PI1uOsl4cghvlH9Tnu5bYVPranIVMsH+7I6Bj3ESFo\n"
"peaLvh6gW9dtgaZ0kNOnYi4hhoh/9Bmc9+JGt1ECgYAbGSQLa21L4Hx3NvMparVQ\n"
"bGjN26igvqKmhBaKrH8YolOlhEw/mCwTlg9zI7jrhdO0VClPrB8IVBoL+6HvrT21\n"
"LJM31J3ddqME9/5fQgKMQsD60kRDD6iV/iK2S6TOUjxJn1f6MuLmGSOHZYcbdBPZ\n"
"DyBKgbz/xGV6katjXvg74A==\n"
"-----END PRIVATE KEY-----\n";
#if 1
/* Will be provided by wolfSSL */
int wolfSSL_GetEchClientHelloInner(
WOLFSSL* ssl, /* Connected to an existing context with the ECH configs. Stores hpke state */
const byte* buffer_in, /* The full ClientHelloOuter */
word32 buffer_len, /* How many bytes in the buffer */
byte* buffer_out,
word32* buffer_out_len
)
{
char* inner = "some clienthelloinner";
*buffer_out_len = strlen(inner);
memcpy(buffer_out, inner, *buffer_out_len);
print_message(msg_fd, "GetEchClientHelloInner set\n");
return 0;
}
#endif
void ech_get_client_hello_inner(WOLFSSL_CTX* ctx, const byte* data, size_t datalen)
{
#if 0
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
printf("wolfSSL_new(%p)\n", ctx);
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);
byte client_hello_inner[1024];
word32 ch_len = sizeof(client_hello_inner);;
char* sni_data = NULL;
word16 sni_len = wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, (void**)&sni_data);
#endif
int res = wolfSSL_GetEchClientHelloInner(
ssl,
data, /* The full ClientHelloOuter */
datalen, /* How many bytes in the buffer */
(byte*)&client_hello_inner,
&ch_len
);
client_hello_inner[ch_len] = 0;
if (!res) {
print_message(msg_fd, "GetEchClientHelloInner: Innerlen: %d\n", ch_len);
hexdump(msg_fd, (char*)client_hello_inner, ch_len);
print_message(msg_fd, "/GetEchClientHelloInner\n");
}
byte sni_data[1024];
unsigned int sni_len = sizeof(sni_data);
memset(sni_data, 'A', sni_len);
printf("SNI_GetFromBuffer\n");
wolfSSL_SNI_GetFromBuffer(data, datalen, 0, (byte*)&sni_data, &sni_len);
sni_data[sni_len] = 0;
printf("sni_len = %d\n", sni_len);
printf("sni: %s\n", sni_data);
}
void ech_match_sni(void)
/* See if the context matches */
void ech_match_sni(const char* buffer_in, size_t buffer_len)
{
ech_get_client_hello_inner(wolfssl_ctx, (byte*)buffer_in, buffer_len);
}
@@ -90,8 +190,6 @@ static void reset_conf(void)
print_message(msg_config_error, "Unable to open %s:%d:%s\n", cfg.ech_conf_sink, errno, strerror(errno));
return;
}
printf("erased and opend %s\n", cfg.ech_conf_sink);
}
@@ -103,6 +201,8 @@ static void ech_genkey(WOLFSSL_CTX* ctx, const char* sni)
{
int ret;
printf("ech_genkey for ctx %p\n", ctx);
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) {
@@ -119,7 +219,7 @@ static void ech_genkey(WOLFSSL_CTX* ctx, const char* sni)
}
char out[512];
int outLen = sizeof(out);
word32 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);
@@ -132,38 +232,53 @@ static void ech_genkey(WOLFSSL_CTX* ctx, const char* sni)
* (Later, this will load the configurations from some place else */
static void ech_create_configs(WOLFSSL_CTX** ctx)
{
int i, j;
int ret;
reset_conf();
for (i = 0; i < cfg.listen_len; i++) {
struct sslhcfg_protocols_item* listen = &cfg.listen[i];
printf("1\n");
*ctx = malloc(cfg.listen_len * sizeof(*ctx));
/* TODO deal with malloc failure */
printf("2\n");
ctx[i] = wolfSSL_CTX_new(wolfTLSv1_3_server_method());
if (!ctx[i]) {
*ctx = wolfSSL_CTX_new(wolfTLSv1_3_server_method());
if (!*ctx) {
print_message(msg_system_error, "Failed to create WOLFSSL_CTX\n");
exit(1);
}
printf("3\n");
ech_genkey(ctx[i], cfg.listen[i].host);
printf("4\n");
// Load certificate from memory
ret = wolfSSL_CTX_use_certificate_buffer(*ctx,
(const unsigned char*)SERVER_CERT_PEM,
strlen(SERVER_CERT_PEM),
WOLFSSL_FILETYPE_PEM);
if (ret != WOLFSSL_SUCCESS) {
fprintf(stderr, "Failed to load certificate: %d\n", ret);
fprintf(stderr, "Please replace SERVER_CERT_PEM with a valid certificate\n");
wolfSSL_CTX_free(*ctx);
exit(1);
}
// Load private key from memory
ret = wolfSSL_CTX_use_PrivateKey_buffer(*ctx,
(const unsigned char*)SERVER_KEY_PEM,
strlen(SERVER_KEY_PEM),
WOLFSSL_FILETYPE_PEM);
if (ret != WOLFSSL_SUCCESS) {
fprintf(stderr, "Failed to load private key: %d\n", ret);
fprintf(stderr, "Please replace SERVER_KEY_PEM with a valid private key\n");
wolfSSL_CTX_free(*ctx);
exit(1);
}
printf("Certificate and key loaded successfully\n");
ech_genkey(*ctx, cfg.listen[0].host); /* For now this only works on the first host */
}
/* Initialises the ECH subsystem: create wolfSSL context, create ECH configs,
* etc */
void ech_init()
{
WOLFSSL_CTX* ctx = NULL;
wolfSSL_Init();
ech_create_configs(&ctx);
ech_create_configs(&wolfssl_ctx);
}