]> granicus.if.org Git - pdns/commitdiff
dnsdist: Add support dumping TLS keys via keyLogFile
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 15 Oct 2019 15:30:12 +0000 (17:30 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 23 Oct 2019 10:34:17 +0000 (12:34 +0200)
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

pdns/dnsdist-lua.cc
pdns/dnsdistdist/docs/reference/config.rst
pdns/dnsdistdist/doh.cc
pdns/dnsdistdist/libssl.cc
pdns/dnsdistdist/m4/dnsdist_with_libssl.m4
pdns/libssl.hh

index 6fcdfa5b6522cd3fdf3463c8ea9eabbad4234b1c..39ef2da24d2fa76a17cb827abf458326042b4b68 100644 (file)
@@ -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<const string>((*vars)["keyLogFile"]);
+  }
 }
 
 #endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
index 813aa080962f116e7acccd423f947f09937267a4..8dcb9a70c64a710bdc95c6d153be0c9a5361cc2e 100644 (file)
@@ -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])
 
index 09edacbcbfa54d4c82cfa3b6df01c8c8e6dece7c..ae86cb60cf7348cfc4d619dc90cdfdd65d20f44d 100644 (file)
@@ -159,6 +159,7 @@ public:
 
   std::map<int, std::string> d_ocspResponses;
   std::unique_ptr<OpenSSLTLSTicketKeysRing> d_ticketKeys{nullptr};
+  std::unique_ptr<FILE, int(*)(FILE*)> 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()) {
index 1cb9b3e2de4212958aa28fd1a12c2f39d0305627..ee9b9ef0fc2a98fabc5de114559bc7366779dde1 100644 (file)
@@ -67,10 +67,16 @@ static void openssl_thread_cleanup()
 static std::atomic<uint64_t> 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<SSL_CTX, void(*)(SSL_CTX*)> 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<FILE*>(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<FILE, int(*)(FILE*)> libssl_set_key_log_file(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx, const std::string& logFile)
+{
+#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
+  auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(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<FILE, int(*)(FILE*)>(nullptr, fclose);
+#endif /* HAVE_SSL_CTX_SET_KEYLOG_CALLBACK */
+}
+
 #endif /* HAVE_LIBSSL */
index ca8885ce8a4638e2ecb3fcfbdf49956e7c8bdf1e..fb6eed63b4301320ae875d1c60049c5449a22274 100644 (file)
@@ -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
 
index 2a114b3f0b5810f8b720ccdac5beaf6cb5e54a09..634d390916e75388aa7685f878170517bd116ed0 100644 (file)
@@ -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<SSL_CTX, void(*)(SSL_CTX*)>& ctx
 std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> libssl_init_server_context(const TLSConfig& config,
                                                                        std::map<int, std::string>& ocspResponses);
 
+std::unique_ptr<FILE, int(*)(FILE*)> libssl_set_key_log_file(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx, const std::string& logFile);
 #endif /* HAVE_LIBSSL */