You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2021/10/07 15:05:41 UTC
[trafficserver] branch 9.2.x updated: Adding TLS session key
logging capability (#8337)
This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch 9.2.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/9.2.x by this push:
new f18e749 Adding TLS session key logging capability (#8337)
f18e749 is described below
commit f18e7497b5929a103ff21f2d87de06d55a2a8de6
Author: Brian Neradt <br...@gmail.com>
AuthorDate: Wed Oct 6 13:00:59 2021 -0500
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 b26795d307024570eda96c30aaf96a8af4e85bde)
---
build/crypto.m4 | 15 +++
configure.ac | 3 +
doc/admin-guide/files/records.config.en.rst | 18 ++--
include/tscore/ink_config.h.in | 1 +
iocore/net/P_SSLConfig.h | 2 +
iocore/net/P_SSLUtils.h | 104 ++++++++++++++++++++-
iocore/net/QUICNetVConnection.cc | 4 +-
iocore/net/QUICPacketHandler.cc | 2 +-
iocore/net/SSLClientCoordinator.cc | 1 +
iocore/net/SSLClientUtils.cc | 7 ++
iocore/net/SSLConfig.cc | 10 ++
iocore/net/SSLUtils.cc | 87 +++++++++++++++++
iocore/net/quic/QUICConfig.cc | 12 +--
iocore/net/quic/QUICConfig.h | 2 -
iocore/net/quic/QUICGlobals.cc | 17 ----
iocore/net/quic/QUICTLS.cc | 6 --
iocore/net/quic/QUICTLS.h | 4 +-
iocore/net/quic/QUICTLS_boringssl.cc | 8 +-
iocore/net/quic/QUICTLS_openssl.cc | 8 +-
lib/perl/lib/Apache/TS/AdminClient.pm | 1 +
mgmt/RecordsConfig.cc | 4 +-
.../tls/tls_session_key_logging.replay.yaml | 48 ++++++++++
.../gold_tests/tls/tls_session_key_logging.test.py | 96 +++++++++++++++++++
23 files changed, 399 insertions(+), 61 deletions(-)
diff --git a/build/crypto.m4 b/build/crypto.m4
index b7bb9c6..f804c94 100644
--- a/build/crypto.m4
+++ b/build/crypto.m4
@@ -274,6 +274,21 @@ AC_DEFUN([TS_CHECK_CRYPTO_OCSP], [
dnl
dnl Since OpenSSL 1.1.1
dnl
+AC_DEFUN([TS_CHECK_CRYPTO_KEYLOGGING], [
+ _keylogging_saved_LIBS=$LIBS
+ TS_ADDTO(LIBS, [$OPENSSL_LIBS])
+ AC_CHECK_FUNCS(SSL_CTX_set_keylog_callback, [enable_tls_keylogging=yes], [enable_tls_keylogging=no])
+ LIBS=$_keylogging_saved_LIBS
+
+ AC_MSG_CHECKING(whether to enable TLS keylogging support)
+ AC_MSG_RESULT([$enable_tls_keylogging])
+ TS_ARG_ENABLE_VAR([has], [tls-keylogging])
+ AC_SUBST(has_tls_keylogging)
+])
+
+dnl
+dnl Since OpenSSL 1.1.1
+dnl
AC_DEFUN([TS_CHECK_CRYPTO_SET_CIPHERSUITES], [
_set_ciphersuites_saved_LIBS=$LIBS
diff --git a/configure.ac b/configure.ac
index 8d0a340..1cf7d1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1286,6 +1286,9 @@ TS_CHECK_CRYPTO_OCSP
# Check for SSL_CTX_set_ciphersuites call
TS_CHECK_CRYPTO_SET_CIPHERSUITES
+# Check for TOLS keylogging support.
+TS_CHECK_CRYPTO_KEYLOGGING
+
# Check for openssl early data support
TS_CHECK_EARLY_DATA
diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst
index b73c834..26106a3 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -3775,6 +3775,18 @@ SSL Termination
See :ref:`admin-performance-timeouts` for more discussion on |TS| timeouts.
+.. ts:cv:: CONFIG proxy.config.ssl.keylog_file STRING NULL
+ :reloadable:
+
+ If configured, TLS session keys for TLS connections will be logged to the
+ specified file. This file is formatted in such a way that it can be
+ conveniently imported into tools such as Wireshark to decrypt packet
+ captures. This should only be used for debugging purposes since the data in
+ the keylog file can be used to decrypt the otherwise encrypted traffic. A
+ NULL value for this disables the feature.
+
+ This feature is disabled by default.
+
Client-Related Configuration
----------------------------
@@ -4234,12 +4246,6 @@ removed in the future without prior notice.
If specified, TLS session data will be stored to the file, and will be used
for resuming a session.
-.. ts:cv:: CONFIG proxy.config.quic.client.keylog_file STRING ""
- :reloadable:
-
- Only available for :program:`traffic_quic`.
- If specified, key information will be stored to the file.
-
.. ts:cv:: CONFIG proxy.config.quic.no_activity_timeout_in INT 30000
:reloadable:
diff --git a/include/tscore/ink_config.h.in b/include/tscore/ink_config.h.in
index 0c97a62..d66e509 100644
--- a/include/tscore/ink_config.h.in
+++ b/include/tscore/ink_config.h.in
@@ -75,6 +75,7 @@
#define TS_USE_TLS13 @use_tls13@
#define TS_USE_QUIC @use_quic@
#define TS_USE_TLS_SET_CIPHERSUITES @use_tls_set_ciphersuites@
+#define TS_HAS_TLS_KEYLOGGING @has_tls_keylogging@
#define TS_USE_LINUX_NATIVE_AIO @use_linux_native_aio@
#define TS_USE_REMOTE_UNWINDING @use_remote_unwinding@
#define TS_USE_TLS_OCSP @use_tls_ocsp@
diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h
index 262df7c..8e92525 100644
--- a/iocore/net/P_SSLConfig.h
+++ b/iocore/net/P_SSLConfig.h
@@ -106,6 +106,8 @@ struct SSLConfigParams : public ConfigInfo {
char *server_groups_list;
char *client_groups_list;
+ char *keylog_file;
+
static uint32_t server_max_early_data;
static uint32_t server_recv_max_early_data;
static bool server_allow_early_data_params;
diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h
index b01da6f..4215644 100644
--- a/iocore/net/P_SSLUtils.h
+++ b/iocore/net/P_SSLUtils.h
@@ -34,8 +34,10 @@
#include "records/I_RecCore.h"
#include "P_SSLCertLookup.h"
-#include <set>
#include <map>
+#include <mutex>
+#include <set>
+#include <shared_mutex>
struct SSLConfigParams;
class SSLNetVConnection;
@@ -60,6 +62,105 @@ struct SSLLoadingContext {
explicit SSLLoadingContext(SSL_CTX *c, SSLCertContextType ctx_type) : ctx(c), ctx_type(ctx_type) {}
};
+/** A class for handling TLS secrets logging. */
+class TLSKeyLogger
+{
+public:
+ TLSKeyLogger(const TLSKeyLogger &) = delete;
+ TLSKeyLogger &operator=(const TLSKeyLogger &) = delete;
+
+ ~TLSKeyLogger()
+ {
+ std::unique_lock lock{_mutex};
+ close_keylog_file();
+ }
+
+ /** A callback for TLS secret key logging.
+ *
+ * This is the callback registered with OpenSSL's SSL_CTX_set_keylog_callback
+ * to log TLS secrets if the user enabled that feature. For more information
+ * about this callback, see OpenSSL's documentation of
+ * SSL_CTX_set_keylog_callback.
+ *
+ * @param[in] ssl The SSL object associated with the connection.
+ * @param[in] line The line to place in the keylog file.
+ */
+ static void
+ ssl_keylog_cb(const SSL *ssl, const char *line)
+ {
+ instance().log(line);
+ }
+
+ /** Return whether TLS key logging is enabled.
+ *
+ * @return True if TLS session key logging is enabled, false otherwise.
+ */
+ static bool
+ is_enabled()
+ {
+ return instance()._fd >= 0;
+ }
+
+ /** Enable keylogging.
+ *
+ * @param[in] keylog_file The path to the file to log TLS secrets to.
+ */
+ static void
+ enable_keylogging(const char *keylog_file)
+ {
+ instance().enable_keylogging_internal(keylog_file);
+ }
+
+ /** Disable TLS secrets logging. */
+ static void
+ disable_keylogging()
+ {
+ instance().disable_keylogging_internal();
+ }
+
+private:
+ TLSKeyLogger() = default;
+
+ /** Return the TLSKeyLogger singleton.
+ *
+ * We use a getter rather than a class static singleton member so that the
+ * construction of the singleton delayed until after TLS configuration is
+ * processed.
+ */
+ static TLSKeyLogger &
+ instance()
+ {
+ static TLSKeyLogger instance;
+ return instance;
+ }
+
+ /** Close the file descriptor for the key log file.
+ *
+ * @note This assumes that a unique lock has been acquired for _mutex.
+ */
+ void close_keylog_file();
+
+ /** A TLS secret line to log to the keylog file.
+ *
+ * @param[in] line A line to log to the keylog file.
+ */
+ void log(const char *line);
+
+ /** Enable TLS keylogging in the instance singleton. */
+ void enable_keylogging_internal(const char *keylog_file);
+
+ /** Disable TLS keylogging in the instance singleton. */
+ void disable_keylogging_internal();
+
+private:
+ /** A file descriptor for the log file receiving the TLS secrets. */
+ int _fd = -1;
+
+ /** A mutex to coordinate dynamically changing TLS logging config changes and
+ * logging to the TLS log file. */
+ std::shared_mutex _mutex;
+};
+
/**
@brief Load SSL certificates from ssl_multicert.config and setup SSLCertLookup for SSLCertificateConfig
*/
@@ -122,6 +223,7 @@ private:
virtual bool _set_info_callback(SSL_CTX *ctx);
virtual bool _set_npn_callback(SSL_CTX *ctx);
virtual bool _set_alpn_callback(SSL_CTX *ctx);
+ virtual bool _set_keylog_callback(SSL_CTX *ctx);
};
// Create a new SSL server context fully configured (cert and keys are optional).
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index d2d07fd..979fc86 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -2323,8 +2323,8 @@ QUICNetVConnection::_setup_handshake_protocol(const shared_SSL_CTX &ctx)
{
// Initialize handshake protocol specific stuff
// For QUICv1 TLS is the only option
- QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx.get(), this->direction(), this->options,
- this->_quic_config->client_session_file(), this->_quic_config->client_keylog_file());
+ QUICTLS *tls =
+ new QUICTLS(this->_pp_key_info, ctx.get(), this->direction(), this->options, this->_quic_config->client_session_file());
SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, static_cast<QUICConnection *>(this));
TLSBasicSupport::bind(tls->ssl_handle(), this);
TLSSessionResumptionSupport::bind(tls->ssl_handle(), this);
diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc
index 4a69065..a30e9be 100644
--- a/iocore/net/QUICPacketHandler.cc
+++ b/iocore/net/QUICPacketHandler.cc
@@ -497,7 +497,7 @@ QUICPacketHandlerIn::_send_invalid_token_error(const uint8_t *initial_packet, ui
QUICPacketFactory pf(ppki);
QUICPacketHeaderProtector php(ppki);
QUICCertConfig::scoped_config server_cert;
- QUICTLS tls(ppki, server_cert->ssl_default.get(), NET_VCONNECTION_IN, {}, "", "");
+ QUICTLS tls(ppki, server_cert->ssl_default.get(), NET_VCONNECTION_IN, {}, "");
tls.initialize_key_materials(dcid_in_initial, version_in_initial);
// Create INITIAL packet
diff --git a/iocore/net/SSLClientCoordinator.cc b/iocore/net/SSLClientCoordinator.cc
index e27fd52..8c994b1 100644
--- a/iocore/net/SSLClientCoordinator.cc
+++ b/iocore/net/SSLClientCoordinator.cc
@@ -49,6 +49,7 @@ SSLClientCoordinator::startup()
sslClientUpdate->attach("proxy.config.ssl.client.cert.filename");
sslClientUpdate->attach("proxy.config.ssl.client.private_key.path");
sslClientUpdate->attach("proxy.config.ssl.client.private_key.filename");
+ sslClientUpdate->attach("proxy.config.ssl.keylog_file");
SSLConfig::startup();
sslClientUpdate->attach("proxy.config.ssl.servername.filename");
SNIConfig::startup();
diff --git a/iocore/net/SSLClientUtils.cc b/iocore/net/SSLClientUtils.cc
index 4d14569..36d057e 100644
--- a/iocore/net/SSLClientUtils.cc
+++ b/iocore/net/SSLClientUtils.cc
@@ -27,6 +27,7 @@
#include "P_Net.h"
#include "P_SSLClientUtils.h"
+#include "P_SSLConfig.h"
#include "P_SSLNetVConnection.h"
#include "YamlSNIConfig.h"
#include "SSLDiags.h"
@@ -234,6 +235,12 @@ SSLInitClientContext(const SSLConfigParams *params)
SSL_CTX_sess_set_new_cb(client_ctx, ssl_new_session_callback);
}
+#if TS_HAS_TLS_KEYLOGGING
+ if (unlikely(TLSKeyLogger::is_enabled())) {
+ SSL_CTX_set_keylog_callback(client_ctx, TLSKeyLogger::ssl_keylog_cb);
+ }
+#endif
+
return client_ctx;
fail:
diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc
index cecbb45..020c2bd 100644
--- a/iocore/net/SSLConfig.cc
+++ b/iocore/net/SSLConfig.cc
@@ -50,6 +50,7 @@
#include "P_SSLSNI.h"
#include "P_SSLCertLookup.h"
#include "P_SSLSNI.h"
+#include "P_SSLUtils.h"
#include "SSLDiags.h"
#include "SSLSessionCache.h"
#include "SSLSessionTicket.h"
@@ -114,6 +115,7 @@ SSLConfigParams::reset()
client_tls13_cipher_suites = nullptr;
server_groups_list = nullptr;
client_groups_list = nullptr;
+ keylog_file = nullptr;
client_ctx = nullptr;
clientCertLevel = client_verify_depth = verify_depth = 0;
verifyServerPolicy = YamlSNIConfig::Policy::DISABLED;
@@ -152,6 +154,7 @@ SSLConfigParams::cleanup()
client_tls13_cipher_suites = static_cast<char *>(ats_free_null(client_tls13_cipher_suites));
server_groups_list = static_cast<char *>(ats_free_null(server_groups_list));
client_groups_list = static_cast<char *>(ats_free_null(client_groups_list));
+ keylog_file = static_cast<char *>(ats_free_null(keylog_file));
cleanupCTXTable();
reset();
@@ -423,6 +426,13 @@ SSLConfigParams::initialize()
REC_ReadConfigStringAlloc(client_groups_list, "proxy.config.ssl.client.groups_list");
+ REC_ReadConfigStringAlloc(keylog_file, "proxy.config.ssl.keylog_file");
+ if (keylog_file == nullptr) {
+ TLSKeyLogger::disable_keylogging();
+ } else {
+ TLSKeyLogger::enable_keylogging(keylog_file);
+ }
+
REC_ReadConfigInt32(ssl_allow_client_renegotiation, "proxy.config.ssl.allow_client_renegotiation");
REC_ReadConfigInt32(ssl_misc_max_iobuffer_size_index, "proxy.config.ssl.misc.io.max_buffer_index");
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 43b4635..55d4628 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -46,7 +46,11 @@
#include "SSLDiags.h"
#include "SSLStats.h"
+#include <fcntl.h>
#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
#include <unistd.h>
#include <termios.h>
#include <vector>
@@ -100,6 +104,74 @@ static int ssl_vc_index = -1;
static ink_mutex *mutex_buf = nullptr;
static bool open_ssl_initialized = false;
+// The caller of this function is responsible to acquire a unique_lock for
+// _mutex.
+void
+TLSKeyLogger::close_keylog_file()
+{
+ if (_fd == -1) {
+ return;
+ }
+ if (close(_fd) == -1) {
+ Error("Could not close keylog file: %s", strerror(errno));
+ }
+ _fd = -1;
+}
+
+void
+TLSKeyLogger::enable_keylogging_internal(const char *keylog_file)
+{
+#if TS_HAS_TLS_KEYLOGGING
+ Debug("ssl_keylog", "Enabling TLS key logging to: %s.", keylog_file);
+ std::unique_lock lock{_mutex};
+ if (keylog_file == nullptr) {
+ close_keylog_file();
+ Debug("ssl_keylog", "Received a nullptr for keylog_file: disabling keylogging.");
+ return;
+ }
+
+ _fd = open(keylog_file, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
+ if (_fd == -1) {
+ Error("Could not open keylog file %s: %s", keylog_file, strerror(errno));
+ return;
+ }
+ Note("Opened %s for TLS key logging.", keylog_file);
+#else
+ Error("TLS keylogging is configured, but Traffic Server is not compiled with a version of OpenSSL that supports it.");
+ return;
+#endif /* TS_HAS_TLS_KEYLOGGING */
+}
+
+void
+TLSKeyLogger::disable_keylogging_internal()
+{
+ std::unique_lock lock{_mutex};
+ if (is_enabled()) {
+ Note("Disabling TLS key logging.");
+ }
+ close_keylog_file();
+ Debug("ssl_keylog", "TLS keylogging is disabled.");
+}
+
+void
+TLSKeyLogger::log(const char *line)
+{
+ std::shared_lock lock{_mutex};
+ if (!is_enabled()) {
+ return;
+ }
+
+ // writev() is guaranteed to be thread safe.
+ struct iovec vector[2];
+ vector[0].iov_base = const_cast<void *>(reinterpret_cast<const void *>(line));
+ vector[0].iov_len = strlen(line);
+ vector[1].iov_base = const_cast<void *>(reinterpret_cast<const void *>("\n"));
+ vector[1].iov_len = 1;
+ if (writev(_fd, vector, 2) <= 0) {
+ Error("Could not write TLS session key to key log file: %s", strerror(errno));
+ }
+}
+
/* Using pthread thread ID and mutex functions directly, instead of
* ATS this_ethread / ProxyMutex, so that other linked libraries
* may use pthreads and openssl without confusing us here. (TS-2271).
@@ -1365,6 +1437,12 @@ SSLMultiCertConfigLoader::init_server_ssl_ctx(CertLoadData const &data, const SS
goto fail;
}
+#if TS_HAS_TLS_KEYLOGGING
+ if (unlikely(TLSKeyLogger::is_enabled()) && !this->_set_keylog_callback(ctx)) {
+ goto fail;
+ }
+#endif
+
if (SSLConfigParams::init_ssl_ctx_cb) {
SSLConfigParams::init_ssl_ctx_cb(ctx, true);
}
@@ -1599,6 +1677,15 @@ SSLMultiCertConfigLoader::_set_alpn_callback(SSL_CTX *ctx)
return true;
}
+bool
+SSLMultiCertConfigLoader::_set_keylog_callback(SSL_CTX *ctx)
+{
+#if TS_HAS_TLS_KEYLOGGING
+ SSL_CTX_set_keylog_callback(ctx, TLSKeyLogger::ssl_keylog_cb);
+#endif
+ return true;
+}
+
SSL_CTX *
SSLCreateServerContext(const SSLConfigParams *params, const SSLMultiCertConfigParams *sslMultiCertSettings, const char *cert_path,
const char *key_path)
diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc
index 171725d..50e75d7 100644
--- a/iocore/net/quic/QUICConfig.cc
+++ b/iocore/net/quic/QUICConfig.cc
@@ -28,6 +28,7 @@
#include <records/I_RecHttp.h>
#include "P_SSLConfig.h"
+#include "P_SSLUtils.h"
#include "QUICGlobals.h"
#include "QUICTransportParameters.h"
@@ -82,8 +83,8 @@ quic_init_client_ssl_ctx(const QUICConfigParams *params)
SSL_CTX_sess_set_new_cb(ssl_ctx.get(), QUIC::ssl_client_new_session);
}
- if (params->client_keylog_file() != nullptr) {
- SSL_CTX_set_keylog_callback(ssl_ctx.get(), QUIC::ssl_client_keylog_cb);
+ if (unlikely(TLSKeyLogger::is_enabled())) {
+ SSL_CTX_set_keylog_callback(ssl_ctx.get(), TLSKeyLogger::ssl_keylog_cb);
}
return ssl_ctx;
@@ -116,7 +117,6 @@ QUICConfigParams::initialize()
REC_ReadConfigStringAlloc(this->_server_supported_groups, "proxy.config.quic.server.supported_groups");
REC_ReadConfigStringAlloc(this->_client_supported_groups, "proxy.config.quic.client.supported_groups");
REC_ReadConfigStringAlloc(this->_client_session_file, "proxy.config.quic.client.session_file");
- REC_ReadConfigStringAlloc(this->_client_keylog_file, "proxy.config.quic.client.keylog_file");
REC_ReadConfigStringAlloc(this->_qlog_dir, "proxy.config.quic.qlog_dir");
// Transport Parameters
@@ -442,12 +442,6 @@ QUICConfigParams::client_session_file() const
}
const char *
-QUICConfigParams::client_keylog_file() const
-{
- return this->_client_keylog_file;
-}
-
-const char *
QUICConfigParams::qlog_dir() const
{
return this->_qlog_dir;
diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h
index 0ce045a..08090e5 100644
--- a/iocore/net/quic/QUICConfig.h
+++ b/iocore/net/quic/QUICConfig.h
@@ -46,7 +46,6 @@ public:
const char *server_supported_groups() const;
const char *client_supported_groups() const;
const char *client_session_file() const;
- const char *client_keylog_file() const;
const char *qlog_dir() const;
shared_SSL_CTX client_ssl_ctx() const;
@@ -107,7 +106,6 @@ private:
char *_server_supported_groups = nullptr;
char *_client_supported_groups = nullptr;
char *_client_session_file = nullptr;
- char *_client_keylog_file = nullptr;
char *_qlog_dir = nullptr;
shared_SSL_CTX _client_ssl_ctx = nullptr;
diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc
index 9cef369..6dcd8f0 100644
--- a/iocore/net/quic/QUICGlobals.cc
+++ b/iocore/net/quic/QUICGlobals.cc
@@ -68,23 +68,6 @@ QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session)
}
void
-QUIC::ssl_client_keylog_cb(const SSL *ssl, const char *line)
-{
- QUICTLS *qtls = static_cast<QUICTLS *>(SSL_get_ex_data(ssl, QUIC::ssl_quic_tls_index));
- const char *keylog_file = qtls->keylog_file();
- std::ofstream file(keylog_file, std::ios_base::app);
-
- if (!file.is_open()) {
- QUICGlobalDebug("could not open keylog file: %s", keylog_file);
- return;
- }
-
- file.write(line, strlen(line));
- file.put('\n');
- file.flush();
-}
-
-void
QUIC::_register_stats()
{
quic_rsb = RecAllocateRawStatBlock(static_cast<int>(QUICStats::count));
diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc
index a618e3a..d12fe5b 100644
--- a/iocore/net/quic/QUICTLS.cc
+++ b/iocore/net/quic/QUICTLS.cc
@@ -111,12 +111,6 @@ QUICTLS::session_file() const
return this->_session_file;
}
-const char *
-QUICTLS::keylog_file() const
-{
- return this->_keylog_file;
-}
-
QUICTLS::~QUICTLS()
{
SSL_free(this->_ssl);
diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h
index 938e1e2..9a488c4 100644
--- a/iocore/net/quic/QUICTLS.h
+++ b/iocore/net/quic/QUICTLS.h
@@ -43,7 +43,7 @@ class QUICTLS : public QUICHandshakeProtocol
{
public:
QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx,
- const NetVCOptions &netvc_options, const char *session_file = nullptr, const char *keylog_file = nullptr);
+ const NetVCOptions &netvc_options, const char *session_file = nullptr);
~QUICTLS();
// TODO: integrate with _early_data_processed
@@ -61,7 +61,6 @@ public:
void set_remote_transport_parameters(std::shared_ptr<const QUICTransportParameters> tp) override;
const char *session_file() const;
- const char *keylog_file() const;
// FIXME Should not exist
SSL *ssl_handle();
@@ -110,7 +109,6 @@ private:
static void _msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
const char *_session_file = nullptr;
- const char *_keylog_file = nullptr;
SSL *_ssl = nullptr;
NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET;
bool _early_data_processed = false;
diff --git a/iocore/net/quic/QUICTLS_boringssl.cc b/iocore/net/quic/QUICTLS_boringssl.cc
index 01aabfa..091b186 100644
--- a/iocore/net/quic/QUICTLS_boringssl.cc
+++ b/iocore/net/quic/QUICTLS_boringssl.cc
@@ -173,12 +173,8 @@ QUICTLS::_msg_cb(int write_p, int version, int content_type, const void *buf, si
}
QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx,
- const NetVCOptions &netvc_options, const char *session_file, const char *keylog_file)
- : QUICHandshakeProtocol(pp_key_info),
- _session_file(session_file),
- _keylog_file(keylog_file),
- _ssl(SSL_new(ssl_ctx)),
- _netvc_context(nvc_ctx)
+ const NetVCOptions &netvc_options, const char *session_file)
+ : QUICHandshakeProtocol(pp_key_info), _session_file(session_file), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx)
{
ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET);
diff --git a/iocore/net/quic/QUICTLS_openssl.cc b/iocore/net/quic/QUICTLS_openssl.cc
index c34598d..5a5d3a9 100644
--- a/iocore/net/quic/QUICTLS_openssl.cc
+++ b/iocore/net/quic/QUICTLS_openssl.cc
@@ -125,12 +125,8 @@ QUICTLS::_msg_cb(int write_p, int version, int content_type, const void *buf, si
}
QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, NetVConnectionContext_t nvc_ctx,
- const NetVCOptions &netvc_options, const char *session_file, const char *keylog_file)
- : QUICHandshakeProtocol(pp_key_info),
- _session_file(session_file),
- _keylog_file(keylog_file),
- _ssl(SSL_new(ssl_ctx)),
- _netvc_context(nvc_ctx)
+ const NetVCOptions &netvc_options, const char *session_file)
+ : QUICHandshakeProtocol(pp_key_info), _session_file(session_file), _ssl(SSL_new(ssl_ctx)), _netvc_context(nvc_ctx)
{
ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET);
diff --git a/lib/perl/lib/Apache/TS/AdminClient.pm b/lib/perl/lib/Apache/TS/AdminClient.pm
index 258c592..b097c00 100644
--- a/lib/perl/lib/Apache/TS/AdminClient.pm
+++ b/lib/perl/lib/Apache/TS/AdminClient.pm
@@ -590,6 +590,7 @@ The Apache Traffic Server Administration Manual will explain what these strings
proxy.config.ssl.TLSv1_3
proxy.config.ssl.server.multicert.filename
proxy.config.ssl.server.private_key.path
+ proxy.config.ssl.keylog_file
proxy.config.stat_collector.interval
proxy.config.stat_collector.port
proxy.config.syslog_facility
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index fd00ca0..b7d6c59 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -1202,6 +1202,8 @@ static const RecordElement RecordsConfig[] =
,
{RECT_CONFIG, "proxy.config.ssl.server.allow_early_data_params", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,
+ {RECT_CONFIG, "proxy.config.ssl.keylog_file", RECD_STRING, nullptr, RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
+ ,
//##############################################################################
//#
//# OCSP (Online Certificate Status Protocol) Stapling Configuration
@@ -1421,8 +1423,6 @@ static const RecordElement RecordsConfig[] =
,
{RECT_CONFIG, "proxy.config.quic.client.session_file", RECD_STRING, nullptr , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,
- {RECT_CONFIG, "proxy.config.quic.client.keylog_file", RECD_STRING, nullptr , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
- ,
{RECT_CONFIG, "proxy.config.quic.qlog_dir", RECD_STRING, nullptr , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,
// Transport Parameters
diff --git a/tests/gold_tests/tls/tls_session_key_logging.replay.yaml b/tests/gold_tests/tls/tls_session_key_logging.replay.yaml
new file mode 100644
index 0000000..9d37fac
--- /dev/null
+++ b/tests/gold_tests/tls/tls_session_key_logging.replay.yaml
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+meta:
+ version: "1.0"
+
+sessions:
+- protocol:
+ - name: http
+ version: 1
+ - name: tls
+ - name: tcp
+ - name: ip
+
+ transactions:
+ - client-request:
+ method: "GET"
+ version: "1.1"
+ url: /for/tls
+ headers:
+ fields:
+ - [ Host, example.com ]
+ - [ Connection, keep-alive ]
+ - [ Content-Length, 16 ]
+ - [ uuid, 2 ]
+
+ server-response:
+ status: 200
+ reason: OK
+ headers:
+ fields:
+ - [ Content-Length, 32 ]
+
+ proxy-response:
+ status: 200
diff --git a/tests/gold_tests/tls/tls_session_key_logging.test.py b/tests/gold_tests/tls/tls_session_key_logging.test.py
new file mode 100644
index 0000000..1e40363
--- /dev/null
+++ b/tests/gold_tests/tls/tls_session_key_logging.test.py
@@ -0,0 +1,96 @@
+'''
+Test TLS secrets logging.
+'''
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+
+Test.Summary = '''
+Test TLS secrets logging.
+'''
+
+
+class TlsKeyloggingTest:
+
+ replay_file = "tls_session_key_logging.replay.yaml"
+ keylog_file = os.path.join(Test.RunDirectory, "tls_secrets.txt")
+
+ server_counter = 0
+ ts_counter = 0
+ client_counter = 0
+
+ def __init__(self, enable_secrets_logging):
+ self.setupOriginServer()
+ self.setupTS(enable_secrets_logging)
+
+ def setupOriginServer(self):
+ server_name = f"server_{TlsKeyloggingTest.server_counter}"
+ TlsKeyloggingTest.server_counter += 1
+ self.server = Test.MakeVerifierServerProcess(
+ server_name, TlsKeyloggingTest.replay_file)
+
+ def setupTS(self, enable_secrets_logging):
+ ts_name = f"ts_{TlsKeyloggingTest.ts_counter}"
+ TlsKeyloggingTest.ts_counter += 1
+ self.ts = Test.MakeATSProcess(ts_name, enable_tls=True, enable_cache=False)
+ self.ts.addDefaultSSLFiles()
+ self.ts.Disk.records_config.update({
+ "proxy.config.ssl.server.cert.path": f'{self.ts.Variables.SSLDir}',
+ "proxy.config.ssl.server.private_key.path": f'{self.ts.Variables.SSLDir}',
+ "proxy.config.ssl.client.verify.server.policy": 'PERMISSIVE',
+
+ 'proxy.config.diags.debug.enabled': 1,
+ 'proxy.config.diags.debug.tags': 'ssl_keylog'
+ })
+ self.ts.Disk.ssl_multicert_config.AddLine(
+ 'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+ )
+ self.ts.Disk.remap_config.AddLine(
+ f'map / https://127.0.0.1:{self.server.Variables.https_port}'
+ )
+ if enable_secrets_logging:
+ self.ts.Disk.records_config.update({
+ 'proxy.config.ssl.keylog_file': TlsKeyloggingTest.keylog_file,
+ })
+
+ self.ts.Disk.diags_log.Content += Testers.ContainsExpression(
+ f"Opened {TlsKeyloggingTest.keylog_file} for TLS key logging",
+ "Verify the user was notified of TLS secrets logging.")
+ self.ts.Disk.File(TlsKeyloggingTest.keylog_file, id="keylog", exists=True)
+ # It would be nice to verify the content of certain lines in the
+ # keylog file, but the content is dependent upon the particular TLS
+ # protocol version. Thus I'm hesitant to add ContainsExpression
+ # checks here which will be fragile and eventually become outdated.
+ else:
+ self.ts.Disk.File(TlsKeyloggingTest.keylog_file, exists=False)
+
+ def run(self):
+ tr = Test.AddTestRun()
+ tr.Processes.Default.StartBefore(self.server)
+ tr.Processes.Default.StartBefore(self.ts)
+
+ client_name = f"client_{TlsKeyloggingTest.client_counter}"
+ TlsKeyloggingTest.client_counter += 1
+ tr.AddVerifierClientProcess(
+ client_name,
+ TlsKeyloggingTest.replay_file,
+ https_ports=[self.ts.Variables.ssl_port])
+
+
+TlsKeyloggingTest(enable_secrets_logging=False).run()
+TlsKeyloggingTest(enable_secrets_logging=True).run()