mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-08 08:07:10 +02:00
WIP/MINOR: ssl: add sample fetches for keylog in frontend
OpenSSL 1.1.1 provides a callback registering function SSL_CTX_set_keylog_callback, which allows one to receive a string containing the keys to deciphers TLSv1.3. Unfortunately it is not possible to store this data in binary form and we can only get this information using the callback. Which means that we need to store it until the connection is closed. This patches add 2 pools, the first one, pool_head_ssl_keylog is used to store a struct ssl_keylog which will be inserted as a ex_data in a SSL *. The second one is pool_head_ssl_keylog_str which will be used to store the hexadecimal strings. To enable the capture of the keys, you need to set "tune.ssl.keylog on" in your configuration. The following fetches were implemented: ssl_fc_client_early_traffic_secret, ssl_fc_client_handshake_traffic_secret, ssl_fc_server_handshake_traffic_secret, ssl_fc_client_traffic_secret_0, ssl_fc_server_traffic_secret_0, ssl_fc_exporter_secret, ssl_fc_early_exporter_secret
This commit is contained in:
parent
46a030cdda
commit
7d42ef5b22
@ -704,6 +704,7 @@ The following keywords are supported in the "global" section :
|
|||||||
- tune.sndbuf.client
|
- tune.sndbuf.client
|
||||||
- tune.sndbuf.server
|
- tune.sndbuf.server
|
||||||
- tune.ssl.cachesize
|
- tune.ssl.cachesize
|
||||||
|
- tune.ssl.keylog
|
||||||
- tune.ssl.lifetime
|
- tune.ssl.lifetime
|
||||||
- tune.ssl.force-private-cache
|
- tune.ssl.force-private-cache
|
||||||
- tune.ssl.maxrecord
|
- tune.ssl.maxrecord
|
||||||
@ -2157,6 +2158,44 @@ tune.ssl.force-private-cache
|
|||||||
this case, adding a first layer of hash-based load balancing before the SSL
|
this case, adding a first layer of hash-based load balancing before the SSL
|
||||||
layer might limit the impact of the lack of session sharing.
|
layer might limit the impact of the lack of session sharing.
|
||||||
|
|
||||||
|
tune.ssl.keylog { on | off }
|
||||||
|
This option activates the logging of the TLS keys. It should be used with
|
||||||
|
care as it will consume more memory per SSL session and could decrease
|
||||||
|
performances. This is disabled by default.
|
||||||
|
|
||||||
|
These sample fetches should be used to generate the SSLKEYLOGFILE that is
|
||||||
|
required to decipher traffic with wireshark.
|
||||||
|
|
||||||
|
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
|
||||||
|
|
||||||
|
The SSLKEYLOG is a series of lines which are formatted this way:
|
||||||
|
|
||||||
|
<Label> <space> <ClientRandom> <space> <Secret>
|
||||||
|
|
||||||
|
The ClientRandom is provided by the %[ssl_fc_client_random,hex] sample
|
||||||
|
fetch, the secret and the Label could be find in the array below. You need
|
||||||
|
to generate a SSLKEYLOGFILE with all the labels in this array.
|
||||||
|
|
||||||
|
The following sample fetches are hexadecimal strings and does not need to be
|
||||||
|
converted.
|
||||||
|
|
||||||
|
SSLKEYLOGFILE Label | Sample fetches for the Secrets
|
||||||
|
--------------------------------|-----------------------------------------
|
||||||
|
CLIENT_EARLY_TRAFFIC_SECRET | %[ssl_fc_client_early_traffic_secret]
|
||||||
|
CLIENT_HANDSHAKE_TRAFFIC_SECRET | %[ssl_fc_client_handshake_traffic_secret]
|
||||||
|
SERVER_HANDSHAKE_TRAFFIC_SECRET | %[ssl_fc_server_handshake_traffic_secret]
|
||||||
|
CLIENT_TRAFFIC_SECRET_0 | %[ssl_fc_client_traffic_secret_0]
|
||||||
|
SERVER_TRAFFIC_SECRET_0 | %[ssl_fc_server_traffic_secret_0]
|
||||||
|
EARLY_EXPORTER_SECRET | %[ssl_fc_exporter_secret]
|
||||||
|
EXPORTER_SECRET | %[ssl_fc_early_exporter_secret]
|
||||||
|
|
||||||
|
This is only available with OpenSSL 1.1.1, and useful with TLS1.3 session.
|
||||||
|
|
||||||
|
If you want to generate the content of a SSLKEYLOGFILE with TLS < 1.3, you
|
||||||
|
only need this line:
|
||||||
|
|
||||||
|
"CLIENT_RANDOM %[ssl_fc_client_random,hex] %[ssl_fc_session_key,hex]"
|
||||||
|
|
||||||
tune.ssl.lifetime <timeout>
|
tune.ssl.lifetime <timeout>
|
||||||
Sets how long a cached SSL session may remain valid. This time is expressed
|
Sets how long a cached SSL session may remain valid. This time is expressed
|
||||||
in seconds and defaults to 300 (5 min). It is important to understand that it
|
in seconds and defaults to 300 (5 min). It is important to understand that it
|
||||||
@ -17020,6 +17059,51 @@ ssl_fc_client_random : binary
|
|||||||
was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
|
was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
|
||||||
sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
|
sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
|
||||||
|
|
||||||
|
ssl_fc_client_early_traffic_secret : string
|
||||||
|
Return the CLIENT_EARLY_TRAFFIC_SECRET as an hexadecimal string for the
|
||||||
|
front connection when the incoming connection was made over a TLS 1.3
|
||||||
|
transport layer.
|
||||||
|
Require OpenSSL >= 1.1.1. This is one of the keys dumped by the OpenSSL
|
||||||
|
keylog callback to generate the SSLKEYLOGFILE. The SSL Key logging must be
|
||||||
|
activated with "tune.ssl.keylog on" in the global section. See also
|
||||||
|
"tune.ssl.keylog"
|
||||||
|
|
||||||
|
ssl_fc_client_handshake_traffic_secret : string
|
||||||
|
Return the CLIENT_HANDSHAKE_TRAFFIC_SECRET as an hexadecimal string for the
|
||||||
|
front connection when the incoming connection was made over a TLS 1.3
|
||||||
|
transport layer.
|
||||||
|
Require OpenSSL >= 1.1.1. This is one of the keys dumped by the OpenSSL
|
||||||
|
keylog callback to generate the SSLKEYLOGFILE. The SSL Key logging must be
|
||||||
|
activated with "tune.ssl.keylog on" in the global section. See also
|
||||||
|
"tune.ssl.keylog"
|
||||||
|
|
||||||
|
ssl_fc_client_traffic_secret_0 : string
|
||||||
|
Return the CLIENT_TRAFFIC_SECRET_0 as an hexadecimal string for the
|
||||||
|
front connection when the incoming connection was made over a TLS 1.3
|
||||||
|
transport layer.
|
||||||
|
Require OpenSSL >= 1.1.1. This is one of the keys dumped by the OpenSSL
|
||||||
|
keylog callback to generate the SSLKEYLOGFILE. The SSL Key logging must be
|
||||||
|
activated with "tune.ssl.keylog on" in the global section. See also
|
||||||
|
"tune.ssl.keylog"
|
||||||
|
|
||||||
|
ssl_fc_exporter_secret : string
|
||||||
|
Return the EXPORTER_SECRET as an hexadecimal string for the
|
||||||
|
front connection when the incoming connection was made over a TLS 1.3
|
||||||
|
transport layer.
|
||||||
|
Require OpenSSL >= 1.1.1. This is one of the keys dumped by the OpenSSL
|
||||||
|
keylog callback to generate the SSLKEYLOGFILE. The SSL Key logging must be
|
||||||
|
activated with "tune.ssl.keylog on" in the global section. See also
|
||||||
|
"tune.ssl.keylog"
|
||||||
|
|
||||||
|
ssl_fc_early_exporter_secret : string
|
||||||
|
Return the EARLY_EXPORTER_SECRET as an hexadecimal string for the
|
||||||
|
front connection when the incoming connection was made over an TLS 1.3
|
||||||
|
transport layer.
|
||||||
|
Require OpenSSL >= 1.1.1. This is one of the keys dumped by the OpenSSL
|
||||||
|
keylog callback to generate the SSLKEYLOGFILE. The SSL Key logging must be
|
||||||
|
activated with "tune.ssl.keylog on" in the global section. See also
|
||||||
|
"tune.ssl.keylog"
|
||||||
|
|
||||||
ssl_fc_has_crt : boolean
|
ssl_fc_has_crt : boolean
|
||||||
Returns true if a client certificate is present in an incoming connection over
|
Returns true if a client certificate is present in an incoming connection over
|
||||||
SSL/TLS transport layer. Useful if 'verify' statement is set to 'optional'.
|
SSL/TLS transport layer. Useful if 'verify' statement is set to 'optional'.
|
||||||
@ -17064,6 +17148,24 @@ ssl_fc_unique_id : binary
|
|||||||
returns the TLS unique ID as defined in RFC5929 section 3. The unique id
|
returns the TLS unique ID as defined in RFC5929 section 3. The unique id
|
||||||
can be encoded to base64 using the converter: "ssl_bc_unique_id,base64".
|
can be encoded to base64 using the converter: "ssl_bc_unique_id,base64".
|
||||||
|
|
||||||
|
ssl_fc_server_handshake_traffic_secret : string
|
||||||
|
Return the SERVER_HANDSHAKE_TRAFFIC_SECRET as an hexadecimal string for the
|
||||||
|
front connection when the incoming connection was made over a TLS 1.3
|
||||||
|
transport layer.
|
||||||
|
Require OpenSSL >= 1.1.1. This is one of the keys dumped by the OpenSSL
|
||||||
|
keylog callback to generate the SSLKEYLOGFILE. The SSL Key logging must be
|
||||||
|
activated with "tune.ssl.keylog on" in the global section. See also
|
||||||
|
"tune.ssl.keylog"
|
||||||
|
|
||||||
|
ssl_fc_server_traffic_secret_0 : string
|
||||||
|
Return the SERVER_TRAFFIC_SECRET_0 as an hexadecimal string for the
|
||||||
|
front connection when the incoming connection was made over an TLS 1.3
|
||||||
|
transport layer.
|
||||||
|
Require OpenSSL >= 1.1.1. This is one of the keys dumped by the OpenSSL
|
||||||
|
keylog callback to generate the SSLKEYLOGFILE. The SSL Key logging must be
|
||||||
|
activated with "tune.ssl.keylog on" in the global section. See also
|
||||||
|
"tune.ssl.keylog"
|
||||||
|
|
||||||
ssl_fc_server_random : binary
|
ssl_fc_server_random : binary
|
||||||
Returns the server random of the front connection when the incoming connection
|
Returns the server random of the front connection when the incoming connection
|
||||||
was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
|
was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
|
||||||
|
@ -226,6 +226,26 @@ struct ssl_capture {
|
|||||||
char ciphersuite[0];
|
char ciphersuite[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
#define SSL_KEYLOG_MAX_SECRET_SIZE 129
|
||||||
|
|
||||||
|
struct ssl_keylog {
|
||||||
|
/*
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
|
||||||
|
*/
|
||||||
|
char *client_random;
|
||||||
|
|
||||||
|
/* TLS 1.3 */
|
||||||
|
char *client_early_traffic_secret;
|
||||||
|
char *client_handshake_traffic_secret;
|
||||||
|
char *server_handshake_traffic_secret;
|
||||||
|
char *client_traffic_secret_0;
|
||||||
|
char *server_traffic_secret_0;
|
||||||
|
char *exporter_secret;
|
||||||
|
char *early_exporter_secret;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ssl_sock_ctx {
|
struct ssl_sock_ctx {
|
||||||
struct connection *conn;
|
struct connection *conn;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
@ -268,6 +288,7 @@ struct global_ssl {
|
|||||||
unsigned int default_dh_param; /* SSL maximum DH parameter size */
|
unsigned int default_dh_param; /* SSL maximum DH parameter size */
|
||||||
int ctx_cache; /* max number of entries in the ssl_ctx cache. */
|
int ctx_cache; /* max number of entries in the ssl_ctx cache. */
|
||||||
int capture_cipherlist; /* Size of the cipherlist buffer. */
|
int capture_cipherlist; /* Size of the cipherlist buffer. */
|
||||||
|
int keylog; /* activate keylog */
|
||||||
int extra_files; /* which files not defined in the configuration file are we looking for */
|
int extra_files; /* which files not defined in the configuration file are we looking for */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,6 +46,9 @@ extern unsigned int openssl_engines_initialized;
|
|||||||
extern int nb_engines;
|
extern int nb_engines;
|
||||||
extern struct xprt_ops ssl_sock;
|
extern struct xprt_ops ssl_sock;
|
||||||
extern int ssl_capture_ptr_index;
|
extern int ssl_capture_ptr_index;
|
||||||
|
extern int ssl_keylog_index;
|
||||||
|
extern struct pool_head *pool_head_ssl_keylog;
|
||||||
|
extern struct pool_head *pool_head_ssl_keylog_str;
|
||||||
|
|
||||||
int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *, SSL_CTX *ctx, char **err);
|
int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *, SSL_CTX *ctx, char **err);
|
||||||
int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf);
|
int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf);
|
||||||
|
@ -317,6 +317,44 @@ static int ssl_parse_global_capture_cipherlist(char **args, int section_type, st
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* init the SSLKEYLOGFILE pool */
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
static int ssl_parse_global_keylog(char **args, int section_type, struct proxy *curpx,
|
||||||
|
struct proxy *defpx, const char *file, int line,
|
||||||
|
char **err)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (too_many_args(1, args, err, NULL))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (strcmp(args[1], "on") == 0)
|
||||||
|
global_ssl.keylog = 1;
|
||||||
|
else if (strcmp(args[1], "off") == 0)
|
||||||
|
global_ssl.keylog = 0;
|
||||||
|
else {
|
||||||
|
memprintf(err, "'%s' expects either 'on' or 'off' but got '%s'.", args[0], args[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pool_head_ssl_keylog) /* already configured */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pool_head_ssl_keylog = create_pool("ssl-keylogfile", sizeof(struct ssl_keylog), MEM_F_SHARED);
|
||||||
|
if (!pool_head_ssl_keylog) {
|
||||||
|
memprintf(err, "Out of memory error.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_head_ssl_keylog_str = create_pool("ssl-keylogfile-str", sizeof(char) * SSL_KEYLOG_MAX_SECRET_SIZE, MEM_F_SHARED);
|
||||||
|
if (!pool_head_ssl_keylog_str) {
|
||||||
|
memprintf(err, "Out of memory error.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* parse "ssl.force-private-cache".
|
/* parse "ssl.force-private-cache".
|
||||||
* Returns <0 on alert, >0 on warning, 0 on success.
|
* Returns <0 on alert, >0 on warning, 0 on success.
|
||||||
*/
|
*/
|
||||||
@ -1820,6 +1858,9 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
|||||||
{ CFG_GLOBAL, "tune.ssl.maxrecord", ssl_parse_global_int },
|
{ CFG_GLOBAL, "tune.ssl.maxrecord", ssl_parse_global_int },
|
||||||
{ CFG_GLOBAL, "tune.ssl.ssl-ctx-cache-size", ssl_parse_global_int },
|
{ CFG_GLOBAL, "tune.ssl.ssl-ctx-cache-size", ssl_parse_global_int },
|
||||||
{ CFG_GLOBAL, "tune.ssl.capture-cipherlist-size", ssl_parse_global_capture_cipherlist },
|
{ CFG_GLOBAL, "tune.ssl.capture-cipherlist-size", ssl_parse_global_capture_cipherlist },
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
{ CFG_GLOBAL, "tune.ssl.keylog", ssl_parse_global_keylog },
|
||||||
|
#endif
|
||||||
{ CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
|
{ CFG_GLOBAL, "ssl-default-bind-ciphers", ssl_parse_global_ciphers },
|
||||||
{ CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
|
{ CFG_GLOBAL, "ssl-default-server-ciphers", ssl_parse_global_ciphers },
|
||||||
#if ((HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL) || defined(LIBRESSL_VERSION_NUMBER))
|
#if ((HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL) || defined(LIBRESSL_VERSION_NUMBER))
|
||||||
|
@ -1108,6 +1108,63 @@ smp_fetch_ssl_fc_cl_xxh64(const struct arg *args, struct sample *smp, const char
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dump the SSL keylog, it only works with "tune.ssl.keylog 1" */
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
static int smp_fetch_ssl_x_keylog(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||||
|
{
|
||||||
|
struct connection *conn;
|
||||||
|
struct ssl_keylog *keylog;
|
||||||
|
SSL *ssl;
|
||||||
|
char *src = NULL;
|
||||||
|
const char *sfx;
|
||||||
|
|
||||||
|
conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) :
|
||||||
|
smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
|
||||||
|
|
||||||
|
if (conn->flags & CO_FL_WAIT_XPRT) {
|
||||||
|
smp->flags |= SMP_F_MAY_CHANGE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl = ssl_sock_get_ssl_object(conn);
|
||||||
|
if (!ssl)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
|
||||||
|
if (!keylog)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sfx = kw + strlen("ssl_xx_");
|
||||||
|
|
||||||
|
if (strcmp(sfx, "client_early_traffic_secret") == 0) {
|
||||||
|
src = keylog->client_early_traffic_secret;
|
||||||
|
} else if (strcmp(sfx, "client_handshake_traffic_secret") == 0) {
|
||||||
|
src = keylog->client_handshake_traffic_secret;
|
||||||
|
} else if (strcmp(sfx, "server_handshake_traffic_secret") == 0) {
|
||||||
|
src = keylog->server_handshake_traffic_secret;
|
||||||
|
} else if (strcmp(sfx, "client_traffic_secret_0") == 0) {
|
||||||
|
src = keylog->client_traffic_secret_0;
|
||||||
|
} else if (strcmp(sfx, "server_traffic_secret_0") == 0) {
|
||||||
|
src = keylog->server_traffic_secret_0;
|
||||||
|
} else if (strcmp(sfx, "exporter_secret") == 0) {
|
||||||
|
src = keylog->exporter_secret;
|
||||||
|
} else if (strcmp(sfx, "early_exporter_secret") == 0) {
|
||||||
|
src = keylog->early_exporter_secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src || !*src)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
smp->data.u.str.area = src;
|
||||||
|
smp->data.type = SMP_T_STR;
|
||||||
|
smp->flags |= SMP_F_CONST;
|
||||||
|
smp->data.u.str.data = strlen(smp->data.u.str.area);
|
||||||
|
return 1;
|
||||||
|
/* log-format "CLIENT_RANDOM %[ssl_fc_client_random,hex] %[ssl_fc_session_key,hex]" */
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
smp_fetch_ssl_fc_cl_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
|
||||||
{
|
{
|
||||||
@ -1379,6 +1436,17 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
|
|||||||
{ "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
{ "ssl_fc_server_random", smp_fetch_ssl_fc_random, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
||||||
{ "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
{ "ssl_fc_session_key", smp_fetch_ssl_fc_session_key, 0, NULL, SMP_T_BIN, SMP_USE_L5CLI },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
{ "ssl_fc_client_early_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
|
{ "ssl_fc_client_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
|
{ "ssl_fc_server_handshake_traffic_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
|
{ "ssl_fc_client_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
|
{ "ssl_fc_server_traffic_secret_0", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
|
{ "ssl_fc_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
|
{ "ssl_fc_early_exporter_secret", smp_fetch_ssl_x_keylog, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||||
{ "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
{ "ssl_fc_sni", smp_fetch_ssl_fc_sni, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
|
||||||
#endif
|
#endif
|
||||||
|
157
src/ssl_sock.c
157
src/ssl_sock.c
@ -129,6 +129,9 @@ struct global_ssl global_ssl = {
|
|||||||
.ctx_cache = DEFAULT_SSL_CTX_CACHE,
|
.ctx_cache = DEFAULT_SSL_CTX_CACHE,
|
||||||
.capture_cipherlist = 0,
|
.capture_cipherlist = 0,
|
||||||
.extra_files = SSL_GF_ALL,
|
.extra_files = SSL_GF_ALL,
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
.keylog = 0
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static BIO_METHOD *ha_meth;
|
static BIO_METHOD *ha_meth;
|
||||||
@ -433,6 +436,12 @@ struct pool_head *pool_head_ssl_capture = NULL;
|
|||||||
int ssl_capture_ptr_index = -1;
|
int ssl_capture_ptr_index = -1;
|
||||||
static int ssl_app_data_index = -1;
|
static int ssl_app_data_index = -1;
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
int ssl_keylog_index = -1;
|
||||||
|
struct pool_head *pool_head_ssl_keylog = NULL;
|
||||||
|
struct pool_head *pool_head_ssl_keylog_str = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
|
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
|
||||||
struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference);
|
struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference);
|
||||||
#endif
|
#endif
|
||||||
@ -505,6 +514,12 @@ static void ssl_sock_parse_clienthello(struct connection *conn, int write_p, int
|
|||||||
int content_type, const void *buf, size_t len,
|
int content_type, const void *buf, size_t len,
|
||||||
SSL *ssl);
|
SSL *ssl);
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
static void ssl_init_keylog(struct connection *conn, int write_p, int version,
|
||||||
|
int content_type, const void *buf, size_t len,
|
||||||
|
SSL *ssl);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* List head of all registered SSL/TLS protocol message callbacks. */
|
/* List head of all registered SSL/TLS protocol message callbacks. */
|
||||||
struct list ssl_sock_msg_callbacks = LIST_HEAD_INIT(ssl_sock_msg_callbacks);
|
struct list ssl_sock_msg_callbacks = LIST_HEAD_INIT(ssl_sock_msg_callbacks);
|
||||||
|
|
||||||
@ -544,6 +559,13 @@ static int ssl_sock_register_msg_callbacks(void)
|
|||||||
if (!ssl_sock_register_msg_callback(ssl_sock_parse_clienthello))
|
if (!ssl_sock_register_msg_callback(ssl_sock_parse_clienthello))
|
||||||
return ERR_ABORT;
|
return ERR_ABORT;
|
||||||
}
|
}
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
if (global_ssl.keylog > 0) {
|
||||||
|
if (!ssl_sock_register_msg_callback(ssl_init_keylog))
|
||||||
|
return ERR_ABORT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1680,6 +1702,30 @@ static void ssl_sock_parse_clienthello(struct connection *conn, int write_p, int
|
|||||||
SSL_set_ex_data(ssl, ssl_capture_ptr_index, capture);
|
SSL_set_ex_data(ssl, ssl_capture_ptr_index, capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
static void ssl_init_keylog(struct connection *conn, int write_p, int version,
|
||||||
|
int content_type, const void *buf, size_t len,
|
||||||
|
SSL *ssl)
|
||||||
|
{
|
||||||
|
struct ssl_keylog *keylog;
|
||||||
|
|
||||||
|
if (SSL_get_ex_data(ssl, ssl_keylog_index))
|
||||||
|
return;
|
||||||
|
|
||||||
|
keylog = pool_alloc(pool_head_ssl_keylog);
|
||||||
|
if (!keylog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(keylog, 0, sizeof(*keylog));
|
||||||
|
|
||||||
|
if (!SSL_set_ex_data(ssl, ssl_keylog_index, keylog)) {
|
||||||
|
pool_free(pool_head_ssl_keylog, keylog);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Callback is called for ssl protocol analyse */
|
/* Callback is called for ssl protocol analyse */
|
||||||
void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
|
void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
|
||||||
{
|
{
|
||||||
@ -4020,6 +4066,88 @@ void ssl_set_shctx(SSL_CTX *ctx)
|
|||||||
SSL_CTX_sess_set_remove_cb(ctx, sh_ssl_sess_remove_cb);
|
SSL_CTX_sess_set_remove_cb(ctx, sh_ssl_sess_remove_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
|
||||||
|
*
|
||||||
|
* The format is:
|
||||||
|
* * <Label> <space> <ClientRandom> <space> <Secret>
|
||||||
|
* We only need to copy the secret as there is a sample fetch for the ClientRandom
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
void SSL_CTX_keylog(const SSL *ssl, const char *line)
|
||||||
|
{
|
||||||
|
struct ssl_keylog *keylog;
|
||||||
|
char *lastarg = NULL;
|
||||||
|
char *dst = NULL;
|
||||||
|
|
||||||
|
keylog = SSL_get_ex_data(ssl, ssl_keylog_index);
|
||||||
|
if (!keylog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lastarg = strrchr(line, ' ');
|
||||||
|
if (lastarg == NULL || ++lastarg == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dst = pool_alloc(pool_head_ssl_keylog_str);
|
||||||
|
if (!dst)
|
||||||
|
return;
|
||||||
|
|
||||||
|
strncpy(dst, lastarg, SSL_KEYLOG_MAX_SECRET_SIZE-1);
|
||||||
|
dst[SSL_KEYLOG_MAX_SECRET_SIZE-1] = '\0';
|
||||||
|
|
||||||
|
if (strncmp(line, "CLIENT_RANDOM ", strlen("CLIENT RANDOM ")) == 0) {
|
||||||
|
if (keylog->client_random)
|
||||||
|
goto error;
|
||||||
|
keylog->client_random = dst;
|
||||||
|
|
||||||
|
} else if (strncmp(line, "CLIENT_EARLY_TRAFFIC_SECRET ", strlen("CLIENT_EARLY_TRAFFIC_SECRET ")) == 0) {
|
||||||
|
if (keylog->client_early_traffic_secret)
|
||||||
|
goto error;
|
||||||
|
keylog->client_early_traffic_secret = dst;
|
||||||
|
|
||||||
|
} else if (strncmp(line, "CLIENT_HANDSHAKE_TRAFFIC_SECRET ", strlen("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")) == 0) {
|
||||||
|
if(keylog->client_handshake_traffic_secret)
|
||||||
|
goto error;
|
||||||
|
keylog->client_handshake_traffic_secret = dst;
|
||||||
|
|
||||||
|
} else if (strncmp(line, "SERVER_HANDSHAKE_TRAFFIC_SECRET ", strlen("SERVER_HANDSHAKE_TRAFFIC_SECRET ")) == 0) {
|
||||||
|
if (keylog->server_handshake_traffic_secret)
|
||||||
|
goto error;
|
||||||
|
keylog->server_handshake_traffic_secret = dst;
|
||||||
|
|
||||||
|
} else if (strncmp(line, "CLIENT_TRAFFIC_SECRET_0 ", strlen("CLIENT_TRAFFIC_SECRET_0 ")) == 0) {
|
||||||
|
if (keylog->client_traffic_secret_0)
|
||||||
|
goto error;
|
||||||
|
keylog->client_traffic_secret_0 = dst;
|
||||||
|
|
||||||
|
} else if (strncmp(line, "SERVER_TRAFFIC_SECRET_0 ", strlen("SERVER_TRAFFIC_SECRET_0 ")) == 0) {
|
||||||
|
if (keylog->server_traffic_secret_0)
|
||||||
|
goto error;
|
||||||
|
keylog->server_traffic_secret_0 = dst;
|
||||||
|
|
||||||
|
} else if (strncmp(line, "EARLY_EXPORTER_SECRET ", strlen("EARLY_EXPORTER_SECRET ")) == 0) {
|
||||||
|
if (keylog->early_exporter_secret)
|
||||||
|
goto error;
|
||||||
|
keylog->early_exporter_secret = dst;
|
||||||
|
|
||||||
|
} else if (strncmp(line, "EXPORTER_SECRET ", strlen("EXPORTER_SECRET ")) == 0) {
|
||||||
|
if (keylog->exporter_secret)
|
||||||
|
goto error;
|
||||||
|
keylog->exporter_secret = dst;
|
||||||
|
} else {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
pool_free(pool_head_ssl_keylog_str, dst);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function applies the SSL configuration on a SSL_CTX
|
* This function applies the SSL configuration on a SSL_CTX
|
||||||
* It returns an error code and fills the <err> buffer
|
* It returns an error code and fills the <err> buffer
|
||||||
@ -4182,6 +4310,9 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_
|
|||||||
#if HA_OPENSSL_VERSION_NUMBER >= 0x00907000L
|
#if HA_OPENSSL_VERSION_NUMBER >= 0x00907000L
|
||||||
SSL_CTX_set_msg_callback(ctx, ssl_sock_msgcbk);
|
SSL_CTX_set_msg_callback(ctx, ssl_sock_msgcbk);
|
||||||
#endif
|
#endif
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
SSL_CTX_set_keylog_callback(ctx, SSL_CTX_keylog);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
|
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
|
||||||
ssl_conf_cur = NULL;
|
ssl_conf_cur = NULL;
|
||||||
@ -6591,6 +6722,29 @@ static void ssl_sock_capture_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *
|
|||||||
pool_free(pool_head_ssl_capture, ptr);
|
pool_free(pool_head_ssl_capture, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
static void ssl_sock_keylog_free_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl, void *argp)
|
||||||
|
{
|
||||||
|
struct ssl_keylog *keylog;
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
keylog = ptr;
|
||||||
|
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->client_random);
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->client_early_traffic_secret);
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->client_handshake_traffic_secret);
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->server_handshake_traffic_secret);
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->client_traffic_secret_0);
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->server_traffic_secret_0);
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->exporter_secret);
|
||||||
|
pool_free(pool_head_ssl_keylog_str, keylog->early_exporter_secret);
|
||||||
|
|
||||||
|
pool_free(pool_head_ssl_keylog, ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
__attribute__((constructor))
|
__attribute__((constructor))
|
||||||
static void __ssl_sock_init(void)
|
static void __ssl_sock_init(void)
|
||||||
{
|
{
|
||||||
@ -6630,6 +6784,9 @@ static void __ssl_sock_init(void)
|
|||||||
#endif
|
#endif
|
||||||
ssl_app_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
|
ssl_app_data_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
|
||||||
ssl_capture_ptr_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_capture_free_func);
|
ssl_capture_ptr_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_capture_free_func);
|
||||||
|
#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L)
|
||||||
|
ssl_keylog_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, ssl_sock_keylog_free_func);
|
||||||
|
#endif
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
ENGINE_load_builtin_engines();
|
ENGINE_load_builtin_engines();
|
||||||
hap_register_post_check(ssl_check_async_engine_count);
|
hap_register_post_check(ssl_check_async_engine_count);
|
||||||
|
Loading…
Reference in New Issue
Block a user