Skip to content

Commit

Permalink
openssl: support SSLKEYLOGFILE client secret logging
Browse files Browse the repository at this point in the history
This patch checks for the env var SSLKEYLOGFILE=path, if present, then
client connection tls secrets are appended into path.vhostname.

This allows decryption of captured encrypted data for debugging purposes.

SSKEYLOGFILE=path env var method is the same as provided by Firefox and
Chrome for this purpose.
  • Loading branch information
lws-team committed Dec 13, 2021
1 parent e88a1b1 commit b8c4820
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmake/lws_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
#cmakedefine LWS_HAVE_SSL_CTX_load_verify_dir
#cmakedefine LWS_HAVE_SSL_CTX_set1_param
#cmakedefine LWS_HAVE_SSL_CTX_set_ciphersuites
#cmakedefine LWS_HAVE_SSL_CTX_set_keylog_callback
#cmakedefine LWS_HAVE_SSL_EXTRA_CHAIN_CERTS
#cmakedefine LWS_HAVE_SSL_get0_alpn_selected
#cmakedefine LWS_HAVE_SSL_CTX_EVP_PKEY_new_raw_private_key
Expand Down
4 changes: 4 additions & 0 deletions lib/core/private-lib-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,10 @@ struct lws_context {
#if defined(LWS_WITH_SERVER)
char canonical_hostname[96];
#endif
#if defined(LWS_HAVE_SSL_CTX_set_keylog_callback) && \
defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
char keylog_file[96];
#endif

#if defined(LWS_WITH_FILE_OPS)
struct lws_plat_file_ops fops_platform;
Expand Down
11 changes: 11 additions & 0 deletions lib/plat/unix/unix-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ lws_plat_init(struct lws_context *context,
return 1;
}

#if defined(LWS_HAVE_SSL_CTX_set_keylog_callback) && \
defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
{
char *klf_env = getenv("SSLKEYLOGFILE");

if (klf_env)
lws_strncpy(context->keylog_file, klf_env,
sizeof(context->keylog_file));
}
#endif

#if defined(LWS_WITH_PLUGINS) && !defined(LWS_WITH_PLUGINS_BUILTIN)
{
char *ld_env = getenv("LD_LIBRARY_PATH");
Expand Down
11 changes: 11 additions & 0 deletions lib/plat/windows/windows-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ lws_plat_init(struct lws_context *context,
}
#endif

#if defined(LWS_HAVE_SSL_CTX_set_keylog_callback) && \
defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
{
char *klf_env = getenv("SSLKEYLOGFILE");

if (klf_env)
lws_strncpy(context->keylog_file, klf_env,
sizeof(context->keylog_file));
}
#endif

for (i = 0; i < FD_HASHTABLE_MODULUS; i++) {
context->fd_hashtable[i].wsi =
lws_zalloc(sizeof(struct lws*) * context->max_fds,
Expand Down
1 change: 1 addition & 0 deletions lib/tls/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ CHECK_SYMBOL_EXISTS(${VARIA}SSL_CTX_set_ciphersuites LWS_HAVE_SSL_CTX_set_cipher
CHECK_FUNCTION_EXISTS(${VARIA}EVP_PKEY_new_raw_private_key LWS_HAVE_EVP_PKEY_new_raw_private_key PARENT_SCOPE)
CHECK_FUNCTION_EXISTS(${VARIA}SSL_SESSION_set_time LWS_HAVE_SSL_SESSION_set_time PARENT_SCOPE)
CHECK_SYMBOL_EXISTS(${VARIA}SSL_SESSION_up_ref LWS_HAVE_SSL_SESSION_up_ref PARENT_SCOPE)
CHECK_FUNCTION_EXISTS(${VARIA}SSL_CTX_set_keylog_callback LWS_HAVE_SSL_CTX_set_keylog_callback PARENT_SCOPE)


# deprecated in openssl v3
Expand Down
60 changes: 60 additions & 0 deletions lib/tls/openssl/openssl-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,60 @@ lws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
return n != 1;
}

#if defined(LWS_HAVE_SSL_CTX_set_keylog_callback) && \
defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
static void
lws_klog_dump(const SSL *ssl, const char *line)
{
struct lws *wsi = SSL_get_ex_data(ssl,
openssl_websocket_private_data_index);
char path[128], hdr[128], ts[64];
size_t w = 0, wx = 0;
int fd, t;

if (!wsi || !wsi->a.context->keylog_file[0] || !wsi->a.vhost)
return;

lws_snprintf(path, sizeof(path), "%s.%s", wsi->a.context->keylog_file,
wsi->a.vhost->name);

fd = open(path, O_CREAT | O_RDWR | O_APPEND, 0600);
if (fd == -1) {
lwsl_vhost_warn(wsi->a.vhost, "Failed to append %s", path);
return;
}

/* the first item in the chunk */
if (!strncmp(line, "SERVER_HANDSHAKE_TRAFFIC_SECRET", 31)) {
w += (size_t)write(fd, "\n# ", 3);
wx += 3;
t = lwsl_timestamp(LLL_WARN, ts, sizeof(ts));
wx += (size_t)t;
w += (size_t)write(fd, ts, (size_t)t);

t = lws_snprintf(hdr, sizeof(hdr), "%s\n", wsi->lc.gutag);
w += (size_t)write(fd, hdr, (size_t)t);
wx += (size_t)t;

lwsl_vhost_warn(wsi->a.vhost, "appended ssl keylog: %s", path);
}

wx += strlen(line) + 1;
w += (size_t)write(fd, line,
#if defined(WIN32)
(unsigned int)
#endif
strlen(line));
w += (size_t)write(fd, "\n", 1);
close(fd);

if (w != wx) {
lwsl_vhost_warn(wsi->a.vhost, "Failed to write %s", path);
return;
}
}
#endif

int
lws_tls_client_create_vhost_context(struct lws_vhost *vh,
const struct lws_context_creation_info *info,
Expand Down Expand Up @@ -887,6 +941,12 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,

vh->tls.tcr = tcr;

#if defined(LWS_HAVE_SSL_CTX_set_keylog_callback) && \
defined(LWS_WITH_TLS) && defined(LWS_WITH_CLIENT)
if (vh->context->keylog_file[0])
SSL_CTX_set_keylog_callback(vh->tls.ssl_client_ctx, lws_klog_dump);
#endif

#if defined(LWS_WITH_TLS_SESSIONS)
vh->tls_session_cache_max = info->tls_session_cache_max ?
info->tls_session_cache_max : 10;
Expand Down

0 comments on commit b8c4820

Please sign in to comment.