Skip to content

Commit f18e749

Browse files
bneradtzwoop
authored andcommitted
Adding TLS session key logging capability (#8337)
Adding the ability to log TLS session keys to a log file for packet capture decryption purposes. This adds the following reloadable configuration: proxy.config.ssl.keylog_file Since this can work for QUIC as well, this also deprecates: proxy.config.quic.client.keylog_file (cherry picked from commit b26795d)
1 parent 476d50a commit f18e749

23 files changed

Lines changed: 399 additions & 61 deletions

build/crypto.m4

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,21 @@ AC_DEFUN([TS_CHECK_CRYPTO_OCSP], [
271271
AC_SUBST(use_tls_ocsp)
272272
])
273273

274+
dnl
275+
dnl Since OpenSSL 1.1.1
276+
dnl
277+
AC_DEFUN([TS_CHECK_CRYPTO_KEYLOGGING], [
278+
_keylogging_saved_LIBS=$LIBS
279+
TS_ADDTO(LIBS, [$OPENSSL_LIBS])
280+
AC_CHECK_FUNCS(SSL_CTX_set_keylog_callback, [enable_tls_keylogging=yes], [enable_tls_keylogging=no])
281+
LIBS=$_keylogging_saved_LIBS
282+
283+
AC_MSG_CHECKING(whether to enable TLS keylogging support)
284+
AC_MSG_RESULT([$enable_tls_keylogging])
285+
TS_ARG_ENABLE_VAR([has], [tls-keylogging])
286+
AC_SUBST(has_tls_keylogging)
287+
])
288+
274289
dnl
275290
dnl Since OpenSSL 1.1.1
276291
dnl

configure.ac

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,9 @@ TS_CHECK_CRYPTO_OCSP
12861286
# Check for SSL_CTX_set_ciphersuites call
12871287
TS_CHECK_CRYPTO_SET_CIPHERSUITES
12881288

1289+
# Check for TOLS keylogging support.
1290+
TS_CHECK_CRYPTO_KEYLOGGING
1291+
12891292
# Check for openssl early data support
12901293
TS_CHECK_EARLY_DATA
12911294

doc/admin-guide/files/records.config.en.rst

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3775,6 +3775,18 @@ SSL Termination
37753775

37763776
See :ref:`admin-performance-timeouts` for more discussion on |TS| timeouts.
37773777

3778+
.. ts:cv:: CONFIG proxy.config.ssl.keylog_file STRING NULL
3779+
:reloadable:
3780+
3781+
If configured, TLS session keys for TLS connections will be logged to the
3782+
specified file. This file is formatted in such a way that it can be
3783+
conveniently imported into tools such as Wireshark to decrypt packet
3784+
captures. This should only be used for debugging purposes since the data in
3785+
the keylog file can be used to decrypt the otherwise encrypted traffic. A
3786+
NULL value for this disables the feature.
3787+
3788+
This feature is disabled by default.
3789+
37783790
Client-Related Configuration
37793791
----------------------------
37803792

@@ -4234,12 +4246,6 @@ removed in the future without prior notice.
42344246
If specified, TLS session data will be stored to the file, and will be used
42354247
for resuming a session.
42364248

4237-
.. ts:cv:: CONFIG proxy.config.quic.client.keylog_file STRING ""
4238-
:reloadable:
4239-
4240-
Only available for :program:`traffic_quic`.
4241-
If specified, key information will be stored to the file.
4242-
42434249
.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_in INT 30000
42444250
:reloadable:
42454251

include/tscore/ink_config.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
#define TS_USE_TLS13 @use_tls13@
7676
#define TS_USE_QUIC @use_quic@
7777
#define TS_USE_TLS_SET_CIPHERSUITES @use_tls_set_ciphersuites@
78+
#define TS_HAS_TLS_KEYLOGGING @has_tls_keylogging@
7879
#define TS_USE_LINUX_NATIVE_AIO @use_linux_native_aio@
7980
#define TS_USE_REMOTE_UNWINDING @use_remote_unwinding@
8081
#define TS_USE_TLS_OCSP @use_tls_ocsp@

iocore/net/P_SSLConfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ struct SSLConfigParams : public ConfigInfo {
106106
char *server_groups_list;
107107
char *client_groups_list;
108108

109+
char *keylog_file;
110+
109111
static uint32_t server_max_early_data;
110112
static uint32_t server_recv_max_early_data;
111113
static bool server_allow_early_data_params;

iocore/net/P_SSLUtils.h

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
#include "records/I_RecCore.h"
3535
#include "P_SSLCertLookup.h"
3636

37-
#include <set>
3837
#include <map>
38+
#include <mutex>
39+
#include <set>
40+
#include <shared_mutex>
3941

4042
struct SSLConfigParams;
4143
class SSLNetVConnection;
@@ -60,6 +62,105 @@ struct SSLLoadingContext {
6062
explicit SSLLoadingContext(SSL_CTX *c, SSLCertContextType ctx_type) : ctx(c), ctx_type(ctx_type) {}
6163
};
6264

65+
/** A class for handling TLS secrets logging. */
66+
class TLSKeyLogger
67+
{
68+
public:
69+
TLSKeyLogger(const TLSKeyLogger &) = delete;
70+
TLSKeyLogger &operator=(const TLSKeyLogger &) = delete;
71+
72+
~TLSKeyLogger()
73+
{
74+
std::unique_lock lock{_mutex};
75+
close_keylog_file();
76+
}
77+
78+
/** A callback for TLS secret key logging.
79+
*
80+
* This is the callback registered with OpenSSL's SSL_CTX_set_keylog_callback
81+
* to log TLS secrets if the user enabled that feature. For more information
82+
* about this callback, see OpenSSL's documentation of
83+
* SSL_CTX_set_keylog_callback.
84+
*
85+
* @param[in] ssl The SSL object associated with the connection.
86+
* @param[in] line The line to place in the keylog file.
87+
*/
88+
static void
89+
ssl_keylog_cb(const SSL *ssl, const char *line)
90+
{
91+
instance().log(line);
92+
}
93+
94+
/** Return whether TLS key logging is enabled.
95+
*
96+
* @return True if TLS session key logging is enabled, false otherwise.
97+
*/
98+
static bool
99+
is_enabled()
100+
{
101+
return instance()._fd >= 0;
102+
}
103+
104+
/** Enable keylogging.
105+
*
106+
* @param[in] keylog_file The path to the file to log TLS secrets to.
107+
*/
108+
static void
109+
enable_keylogging(const char *keylog_file)
110+
{
111+
instance().enable_keylogging_internal(keylog_file);
112+
}
113+
114+
/** Disable TLS secrets logging. */
115+
static void
116+
disable_keylogging()
117+
{
118+
instance().disable_keylogging_internal();
119+
}
120+
121+
private:
122+
TLSKeyLogger() = default;
123+
124+
/** Return the TLSKeyLogger singleton.
125+
*
126+
* We use a getter rather than a class static singleton member so that the
127+
* construction of the singleton delayed until after TLS configuration is
128+
* processed.
129+
*/
130+
static TLSKeyLogger &
131+
instance()
132+
{
133+
static TLSKeyLogger instance;
134+
return instance;
135+
}
136+
137+
/** Close the file descriptor for the key log file.
138+
*
139+
* @note This assumes that a unique lock has been acquired for _mutex.
140+
*/
141+
void close_keylog_file();
142+
143+
/** A TLS secret line to log to the keylog file.
144+
*
145+
* @param[in] line A line to log to the keylog file.
146+
*/
147+
void log(const char *line);
148+
149+
/** Enable TLS keylogging in the instance singleton. */
150+
void enable_keylogging_internal(const char *keylog_file);
151+
152+
/** Disable TLS keylogging in the instance singleton. */
153+
void disable_keylogging_internal();
154+
155+
private:
156+
/** A file descriptor for the log file receiving the TLS secrets. */
157+
int _fd = -1;
158+
159+
/** A mutex to coordinate dynamically changing TLS logging config changes and
160+
* logging to the TLS log file. */
161+
std::shared_mutex _mutex;
162+
};
163+
63164
/**
64165
@brief Load SSL certificates from ssl_multicert.config and setup SSLCertLookup for SSLCertificateConfig
65166
*/
@@ -122,6 +223,7 @@ class SSLMultiCertConfigLoader
122223
virtual bool _set_info_callback(SSL_CTX *ctx);
123224
virtual bool _set_npn_callback(SSL_CTX *ctx);
124225
virtual bool _set_alpn_callback(SSL_CTX *ctx);
226+
virtual bool _set_keylog_callback(SSL_CTX *ctx);
125227
};
126228

127229
// Create a new SSL server context fully configured (cert and keys are optional).

iocore/net/QUICNetVConnection.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2323,8 +2323,8 @@ QUICNetVConnection::_setup_handshake_protocol(const shared_SSL_CTX &ctx)
23232323
{
23242324
// Initialize handshake protocol specific stuff
23252325
// For QUICv1 TLS is the only option
2326-
QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx.get(), this->direction(), this->options,
2327-
this->_quic_config->client_session_file(), this->_quic_config->client_keylog_file());
2326+
QUICTLS *tls =
2327+
new QUICTLS(this->_pp_key_info, ctx.get(), this->direction(), this->options, this->_quic_config->client_session_file());
23282328
SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast<QUICConnection *>(this));
23292329
TLSBasicSupport::bind(tls->ssl_handle(), this);
23302330
TLSSessionResumptionSupport::bind(tls->ssl_handle(), this);

iocore/net/QUICPacketHandler.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ QUICPacketHandlerIn::_send_invalid_token_error(const uint8_t *initial_packet, ui
497497
QUICPacketFactory pf(ppki);
498498
QUICPacketHeaderProtector php(ppki);
499499
QUICCertConfig::scoped_config server_cert;
500-
QUICTLS tls(ppki, server_cert->ssl_default.get(), NET_VCONNECTION_IN, {}, "", "");
500+
QUICTLS tls(ppki, server_cert->ssl_default.get(), NET_VCONNECTION_IN, {}, "");
501501
tls.initialize_key_materials(dcid_in_initial, version_in_initial);
502502

503503
// Create INITIAL packet

iocore/net/SSLClientCoordinator.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ SSLClientCoordinator::startup()
4949
sslClientUpdate->attach("proxy.config.ssl.client.cert.filename");
5050
sslClientUpdate->attach("proxy.config.ssl.client.private_key.path");
5151
sslClientUpdate->attach("proxy.config.ssl.client.private_key.filename");
52+
sslClientUpdate->attach("proxy.config.ssl.keylog_file");
5253
SSLConfig::startup();
5354
sslClientUpdate->attach("proxy.config.ssl.servername.filename");
5455
SNIConfig::startup();

iocore/net/SSLClientUtils.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "P_Net.h"
2929
#include "P_SSLClientUtils.h"
30+
#include "P_SSLConfig.h"
3031
#include "P_SSLNetVConnection.h"
3132
#include "YamlSNIConfig.h"
3233
#include "SSLDiags.h"
@@ -234,6 +235,12 @@ SSLInitClientContext(const SSLConfigParams *params)
234235
SSL_CTX_sess_set_new_cb(client_ctx, ssl_new_session_callback);
235236
}
236237

238+
#if TS_HAS_TLS_KEYLOGGING
239+
if (unlikely(TLSKeyLogger::is_enabled())) {
240+
SSL_CTX_set_keylog_callback(client_ctx, TLSKeyLogger::ssl_keylog_cb);
241+
}
242+
#endif
243+
237244
return client_ctx;
238245

239246
fail:

0 commit comments

Comments
 (0)