From: Remi Gacogne Date: Tue, 15 Oct 2019 15:30:12 +0000 (+0200) Subject: dnsdist: Add support dumping TLS keys via keyLogFile X-Git-Tag: dnsdist-1.4.0-rc4~3^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F8442%2Fhead;p=thirdparty%2Fpdns.git dnsdist: Add support dumping TLS keys via keyLogFile This is similar to what various programs do when the SSLKEYLOGFILE environment variable is set, and uses the format described in: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format --- diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 6fcdfa5b65..39ef2da24d 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -198,6 +198,10 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost: config.d_ocspFiles.push_back(file.second); } } + + if (vars->count("keyLogFile")) { + config.d_keyLogFile = boost::get((*vars)["keyLogFile"]); + } } #endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS) diff --git a/pdns/dnsdistdist/docs/reference/config.rst b/pdns/dnsdistdist/docs/reference/config.rst index 813aa08096..8dcb9a70c6 100644 --- a/pdns/dnsdistdist/docs/reference/config.rst +++ b/pdns/dnsdistdist/docs/reference/config.rst @@ -136,6 +136,7 @@ Listen Sockets * ``sessionTickets``: bool - Whether session resumption via session tickets is enabled. Default is true, meaning tickets are enabled. * ``numberOfStoredSessions``: int - The maximum number of sessions kept in memory at the same time. Default is 20480. Setting this value to 0 disables stored session entirely. * ``preferServerCiphers``: bool - Whether to prefer the order of ciphers set by the server instead of the one set by the client. Default is false, meaning that the order of the client is used. + * ``keyLogFile``: str - Write the TLS keys in the specified file so that an external program can decrypt TLS exchanges, in the format described in https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. .. function:: addTLSLocal(address, certFile(s), keyFile(s) [, options]) @@ -146,7 +147,7 @@ Listen Sockets .. versionchanged:: 1.3.3 ``numberOfStoredSessions`` option added. .. versionchanged:: 1.4.0 - ``ciphersTLS13``, ``minTLSVersion``, ``ocspResponses`` and ``preferServerCiphers`` options added. + ``ciphersTLS13``, ``minTLSVersion``, ``ocspResponses``, ``preferServerCiphers``, ``keyLogFile`` options added. Listen on the specified address and TCP port for incoming DNS over TLS connections, presenting the specified X.509 certificate. @@ -173,6 +174,7 @@ Listen Sockets * ``ocspResponses``: list - List of files containing OCSP responses, in the same order than the certificates and keys, that will be used to provide OCSP stapling responses. * ``minTLSVersion``: str - Minimum version of the TLS protocol to support. Possible values are 'tls1.0', 'tls1.1', 'tls1.2' and 'tls1.3'. Default is to require at least TLS 1.0. Note that this value is ignored when the GnuTLS provider is in use, and the ``ciphers`` option should be set accordingly instead. For example, 'NORMAL:!VERS-TLS1.0:!VERS-TLS1.1' will disable TLS 1.0 and 1.1. * ``preferServerCiphers``: bool - Whether to prefer the order of ciphers set by the server instead of the one set by the client. Default is false, meaning that the order of the client is used. + * ``keyLogFile``: str - Write the TLS keys in the specified file so that an external program can decrypt TLS exchanges, in the format described in https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. .. function:: setLocal(address[, options]) diff --git a/pdns/dnsdistdist/doh.cc b/pdns/dnsdistdist/doh.cc index 09edacbcbf..ae86cb60cf 100644 --- a/pdns/dnsdistdist/doh.cc +++ b/pdns/dnsdistdist/doh.cc @@ -159,6 +159,7 @@ public: std::map d_ocspResponses; std::unique_ptr d_ticketKeys{nullptr}; + std::unique_ptr d_keyLogFile{nullptr, fclose}; ClientState* d_cs{nullptr}; time_t d_ticketsKeyRotationDelay{0}; @@ -1055,6 +1056,10 @@ static void setupTLSContext(DOHAcceptContext& acceptCtx, libssl_set_error_counters_callback(ctx, &counters); + if (!tlsConfig.d_keyLogFile.empty()) { + acceptCtx.d_keyLogFile = libssl_set_key_log_file(ctx, tlsConfig.d_keyLogFile); + } + h2o_ssl_register_alpn_protocols(ctx.get(), h2o_http2_alpn_protocols); if (tlsConfig.d_ticketKeyFile.empty()) { diff --git a/pdns/dnsdistdist/libssl.cc b/pdns/dnsdistdist/libssl.cc index 1cb9b3e2de..ee9b9ef0fc 100644 --- a/pdns/dnsdistdist/libssl.cc +++ b/pdns/dnsdistdist/libssl.cc @@ -67,10 +67,16 @@ static void openssl_thread_cleanup() static std::atomic s_users; static int s_ticketsKeyIndex{-1}; static int s_countersIndex{-1}; +static int s_keyLogIndex{-1}; void registerOpenSSLUser() { if (s_users.fetch_add(1) == 0) { +#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || defined LIBRESSL_VERSION_NUMBER) + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + openssl_thread_setup(); +#endif s_ticketsKeyIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); if (s_ticketsKeyIndex == -1) { @@ -82,11 +88,12 @@ void registerOpenSSLUser() if (s_countersIndex == -1) { throw std::runtime_error("Error getting an index for counters"); } -#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || defined LIBRESSL_VERSION_NUMBER) - SSL_load_error_strings(); - OpenSSL_add_ssl_algorithms(); - openssl_thread_setup(); -#endif + + s_keyLogIndex = SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); + + if (s_keyLogIndex == -1) { + throw std::runtime_error("Error getting an index for TLS key logging"); + } } } @@ -717,4 +724,38 @@ std::unique_ptr libssl_init_server_context(const TLS return ctx; } +#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK +static void libssl_key_log_file_callback(const SSL* ssl, const char* line) +{ + SSL_CTX* sslCtx = SSL_get_SSL_CTX(ssl); + if (sslCtx == nullptr) { + return; + } + + auto fp = reinterpret_cast(SSL_CTX_get_ex_data(sslCtx, s_keyLogIndex)); + if (fp == nullptr) { + return; + } + + fprintf(fp, "%s\n", line); +} +#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */ + +std::unique_ptr libssl_set_key_log_file(std::unique_ptr& ctx, const std::string& logFile) +{ +#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK + auto fp = std::unique_ptr(fopen(logFile.c_str(), "a"), fclose); + if (!fp) { + throw std::runtime_error("Error opening TLS log file '" + logFile + "'"); + } + + SSL_CTX_set_ex_data(ctx.get(), s_keyLogIndex, fp.get()); + SSL_CTX_set_keylog_callback(ctx.get(), &libssl_key_log_file_callback); + + return fp; +#else + return std::unique_ptr(nullptr, fclose); +#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */ +} + #endif /* HAVE_LIBSSL */ diff --git a/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 b/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 index ca8885ce8a..fb6eed63b4 100644 --- a/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 +++ b/pdns/dnsdistdist/m4/dnsdist_with_libssl.m4 @@ -17,7 +17,7 @@ AC_DEFUN([DNSDIST_WITH_LIBSSL], [ save_LIBS=$LIBS CFLAGS="$LIBSSL_CFLAGS $CFLAGS" LIBS="$LIBSSL_LIBS -lcrypto $LIBS" - AC_CHECK_FUNCS([SSL_CTX_set_ciphersuites OCSP_basic_sign SSL_CTX_set_num_tickets]) + AC_CHECK_FUNCS([SSL_CTX_set_ciphersuites OCSP_basic_sign SSL_CTX_set_num_tickets SSL_CTX_set_keylog_callback]) CFLAGS=$save_CFLAGS LIBS=$save_LIBS diff --git a/pdns/libssl.hh b/pdns/libssl.hh index 2a114b3f0b..634d390916 100644 --- a/pdns/libssl.hh +++ b/pdns/libssl.hh @@ -21,6 +21,7 @@ public: std::string d_ciphers; std::string d_ciphers13; std::string d_ticketKeyFile; + std::string d_keyLogFile; size_t d_maxStoredSessions{20480}; time_t d_ticketsKeyRotationDelay{43200}; @@ -117,4 +118,5 @@ bool libssl_set_min_tls_version(std::unique_ptr& ctx std::unique_ptr libssl_init_server_context(const TLSConfig& config, std::map& ocspResponses); +std::unique_ptr libssl_set_key_log_file(std::unique_ptr& ctx, const std::string& logFile); #endif /* HAVE_LIBSSL */