This is an automated email from the ASF dual-hosted git repository.

masaori pushed a commit to branch quic-latest
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/quic-latest by this push:
     new d57c17c  Add keylog support on QUIC client
d57c17c is described below

commit d57c17c83cb5e1de59d61d73221c6a223cae385b
Author: Masaori Koshiba <[email protected]>
AuthorDate: Thu Feb 14 16:18:09 2019 +0900

    Add keylog support on QUIC client
---
 iocore/net/QUICNetVConnection.cc   |  4 +-
 iocore/net/quic/QUICConfig.cc      | 21 +++++++--
 iocore/net/quic/QUICConfig.h       |  6 ++-
 iocore/net/quic/QUICGlobals.cc     | 18 ++++++++
 iocore/net/quic/QUICGlobals.h      |  1 +
 iocore/net/quic/QUICTLS.cc         |  6 +++
 iocore/net/quic/QUICTLS.h          |  7 +--
 iocore/net/quic/QUICTLS_openssl.cc | 90 +++++++++++++++++++++++++++++++++-----
 mgmt/RecordsConfig.cc              |  2 +
 9 files changed, 133 insertions(+), 22 deletions(-)

diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index 6a23128..799b994 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -2236,8 +2236,10 @@ QUICNetVConnection::_setup_handshake_protocol(SSL_CTX 
*ctx)
 {
   // Initialize handshake protocol specific stuff
   // For QUICv1 TLS is the only option
-  QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), 
this->options, this->_quic_config->session_file());
+  QUICTLS *tls = new QUICTLS(this->_pp_key_info, ctx, this->direction(), 
this->options, this->_quic_config->client_session_file(),
+                             this->_quic_config->client_keylog_file());
   SSL_set_ex_data(tls->ssl_handle(), QUIC::ssl_quic_qc_index, 
static_cast<QUICConnection *>(this));
+
   return tls;
 }
 
diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc
index 0213cee..86e9707 100644
--- a/iocore/net/quic/QUICConfig.cc
+++ b/iocore/net/quic/QUICConfig.cc
@@ -82,11 +82,17 @@ quic_init_client_ssl_ctx(const QUICConfigParams *params)
     }
   }
 
-  if (params->session_file() != nullptr) {
+  if (params->client_session_file() != nullptr) {
     SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT | 
SSL_SESS_CACHE_NO_INTERNAL_STORE);
     SSL_CTX_sess_set_new_cb(ssl_ctx, QUIC::ssl_client_new_session);
   }
 
+#ifdef SSL_MODE_QUIC_HACK
+  if (params->client_keylog_file() != nullptr) {
+    SSL_CTX_set_keylog_callback(ssl_ctx, QUIC::ssl_client_keylog_cb);
+  }
+#endif
+
   return ssl_ctx;
 }
 
@@ -113,7 +119,8 @@ 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->_session_file, 
"proxy.config.quic.client.session_file");
+  REC_ReadConfigStringAlloc(this->_client_session_file, 
"proxy.config.quic.client.session_file");
+  REC_ReadConfigStringAlloc(this->_client_keylog_file, 
"proxy.config.quic.client.keylog_file");
 
   // Transport Parameters
   REC_EstablishStaticConfigInt32U(this->_no_activity_timeout_in, 
"proxy.config.quic.no_activity_timeout_in");
@@ -417,9 +424,15 @@ QUICConfigParams::scid_len()
 }
 
 const char *
-QUICConfigParams::session_file() const
+QUICConfigParams::client_session_file() const
+{
+  return this->_client_session_file;
+}
+
+const char *
+QUICConfigParams::client_keylog_file() const
 {
-  return _session_file;
+  return this->_client_keylog_file;
 }
 
 //
diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h
index 4ab237a..c56d74f 100644
--- a/iocore/net/quic/QUICConfig.h
+++ b/iocore/net/quic/QUICConfig.h
@@ -45,7 +45,8 @@ public:
 
   const char *server_supported_groups() const;
   const char *client_supported_groups() const;
-  const char *session_file() const;
+  const char *client_session_file() const;
+  const char *client_keylog_file() const;
 
   SSL_CTX *client_ssl_ctx() const;
 
@@ -100,7 +101,8 @@ private:
 
   char *_server_supported_groups = nullptr;
   char *_client_supported_groups = nullptr;
-  char *_session_file            = nullptr;
+  char *_client_session_file     = nullptr;
+  char *_client_keylog_file      = nullptr;
 
   SSL_CTX *_client_ssl_ctx = nullptr;
 
diff --git a/iocore/net/quic/QUICGlobals.cc b/iocore/net/quic/QUICGlobals.cc
index 0798020..661f816 100644
--- a/iocore/net/quic/QUICGlobals.cc
+++ b/iocore/net/quic/QUICGlobals.cc
@@ -24,6 +24,7 @@
 #include "QUICGlobals.h"
 
 #include <cstring>
+#include <fstream>
 
 #include "P_SSLNextProtocolSet.h"
 
@@ -85,6 +86,23 @@ QUIC::ssl_client_new_session(SSL *ssl, SSL_SESSION *session)
   return 0;
 }
 
+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();
+}
+
 int
 QUIC::ssl_cert_cb(SSL *ssl, void * /*arg*/)
 {
diff --git a/iocore/net/quic/QUICGlobals.h b/iocore/net/quic/QUICGlobals.h
index cd4ac54..0bbde28 100644
--- a/iocore/net/quic/QUICGlobals.h
+++ b/iocore/net/quic/QUICGlobals.h
@@ -34,6 +34,7 @@ public:
   static int ssl_select_next_protocol(SSL *ssl, const unsigned char **out, 
unsigned char *outlen, const unsigned char *in,
                                       unsigned inlen, void *);
   static int ssl_client_new_session(SSL *ssl, SSL_SESSION *session);
+  static void ssl_client_keylog_cb(const SSL *ssl, const char *line);
   static int ssl_cert_cb(SSL *ssl, void *arg);
   static int ssl_sni_cb(SSL *ssl, int *ad, void *arg);
 
diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc
index de11e02..f03a5a7 100644
--- a/iocore/net/quic/QUICTLS.cc
+++ b/iocore/net/quic/QUICTLS.cc
@@ -68,6 +68,12 @@ 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 5a2ac56..7bba45a 100644
--- a/iocore/net/quic/QUICTLS.h
+++ b/iocore/net/quic/QUICTLS.h
@@ -40,7 +40,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 NetVCOptions &netvc_options, const char *session_file = 
nullptr, const char *keylog_file = nullptr);
   ~QUICTLS();
 
   // TODO: integrate with _early_data_processed
@@ -58,6 +58,7 @@ 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();
@@ -79,8 +80,6 @@ private:
   QUICKeyGenerator _keygen_for_server = 
QUICKeyGenerator(QUICKeyGenerator::Context::SERVER);
   const EVP_MD *_get_handshake_digest() const;
 
-  const char *_session_file;
-
   int _read_early_data();
   int _write_early_data();
   int _handshake(QUICHandshakeMsgs *out, const QUICHandshakeMsgs *in);
@@ -94,6 +93,8 @@ private:
   void _print_km(const char *header, const uint8_t *key_for_hp, size_t 
key_for_hp_len, const uint8_t *key, size_t key_len,
                  const uint8_t *iv, size_t iv_len, const uint8_t *secret = 
nullptr, size_t secret_len = 0);
 
+  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_openssl.cc 
b/iocore/net/quic/QUICTLS_openssl.cc
index 94e1867..7f7c961 100644
--- a/iocore/net/quic/QUICTLS_openssl.cc
+++ b/iocore/net/quic/QUICTLS_openssl.cc
@@ -20,8 +20,6 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-#include "QUICGlobals.h"
-#include "QUICPacketProtectionKeyInfo.h"
 #include "QUICTLS.h"
 
 #include <openssl/err.h>
@@ -31,11 +29,21 @@
 #include <openssl/evp.h>
 
 #include "QUICConfig.h"
-
+#include "QUICGlobals.h"
 #include "QUICDebugNames.h"
+#include "QUICPacketProtectionKeyInfo.h"
 
 static constexpr char tag[] = "quic_tls";
 
+using namespace std::literals;
+
+static constexpr std::string_view 
QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL("QUIC_CLIENT_EARLY_TRAFFIC_SECRET"sv);
+static constexpr std::string_view 
QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL("QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET"sv);
+static constexpr std::string_view 
QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL("QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET"sv);
+// TODO: support key update
+static constexpr std::string_view 
QUIC_CLIENT_TRAFFIC_SECRET_LABEL("QUIC_CLIENT_TRAFFIC_SECRET_0"sv);
+static constexpr std::string_view 
QUIC_SERVER_TRAFFIC_SECRET_LABEL("QUIC_SERVER_TRAFFIC_SECRET_0"sv);
+
 static const char *
 content_type_str(int type)
 {
@@ -139,6 +147,58 @@ msg_cb(int write_p, int version, int content_type, const 
void *buf, size_t len,
   return;
 }
 
+/**
+   This is very inspired from writting keylog format of ngtcp2's examples
+   
https://github.com/ngtcp2/ngtcp2/blob/894ed23c970d61eede74f69d9178090af63fdf70/examples/keylog.cc
+ */
+static void
+log_secret(SSL *ssl, int name, const unsigned char *secret, size_t secretlen)
+{
+  if (auto keylog_cb = SSL_CTX_get_keylog_callback(SSL_get_SSL_CTX(ssl))) {
+    unsigned char crandom[32];
+    if (SSL_get_client_random(ssl, crandom, sizeof(crandom)) != 
sizeof(crandom)) {
+      return;
+    }
+    uint8_t line[256] = {0};
+    size_t len        = 0;
+    switch (name) {
+    case SSL_KEY_CLIENT_EARLY_TRAFFIC:
+      memcpy(line, QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.data(), 
QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.size());
+      len += QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.size();
+      break;
+    case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC:
+      memcpy(line, QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.data(), 
QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.size());
+      len += QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.size();
+      break;
+    case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC:
+      memcpy(line, QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.data(), 
QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.size());
+      len += QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.size();
+      break;
+    case SSL_KEY_CLIENT_APPLICATION_TRAFFIC:
+      memcpy(line, QUIC_CLIENT_TRAFFIC_SECRET_LABEL.data(), 
QUIC_CLIENT_TRAFFIC_SECRET_LABEL.size());
+      len += QUIC_CLIENT_TRAFFIC_SECRET_LABEL.size();
+      break;
+    case SSL_KEY_SERVER_APPLICATION_TRAFFIC:
+      memcpy(line, QUIC_SERVER_TRAFFIC_SECRET_LABEL.data(), 
QUIC_SERVER_TRAFFIC_SECRET_LABEL.size());
+      len += QUIC_SERVER_TRAFFIC_SECRET_LABEL.size();
+      break;
+
+    default:
+      return;
+    }
+
+    line[len] = ' ';
+    ++len;
+    QUICDebug::to_hex(line + len, crandom, sizeof(crandom));
+    len += sizeof(crandom) * 2;
+    line[len] = ' ';
+    ++len;
+    QUICDebug::to_hex(line + len, secret, secretlen);
+
+    keylog_cb(ssl, reinterpret_cast<char *>(line));
+  }
+}
+
 static int
 key_cb(SSL *ssl, int name, const unsigned char *secret, size_t secret_len, 
void *arg)
 {
@@ -149,6 +209,8 @@ key_cb(SSL *ssl, int name, const unsigned char *secret, 
size_t secret_len, void
   QUICTLS *qtls = reinterpret_cast<QUICTLS *>(arg);
   qtls->update_key_materials_on_key_cb(name, secret, secret_len);
 
+  log_secret(ssl, name, secret, secret_len);
+
   return 1;
 }
 
@@ -158,19 +220,19 @@ QUICTLS::update_key_materials_on_key_cb(int name, const 
uint8_t *secret, size_t
   if (is_debug_tag_set("vv_quic_crypto")) {
     switch (name) {
     case SSL_KEY_CLIENT_EARLY_TRAFFIC:
-      Debug("vv_quic_crypto", "client_early_traffic");
+      Debug("vv_quic_crypto", "%s", 
QUIC_CLIENT_EARLY_TRAFFIC_SECRET_LABEL.data());
       break;
     case SSL_KEY_CLIENT_HANDSHAKE_TRAFFIC:
-      Debug("vv_quic_crypto", "client_handshake_traffic");
-      break;
-    case SSL_KEY_CLIENT_APPLICATION_TRAFFIC:
-      Debug("vv_quic_crypto", "client_application_traffic");
+      Debug("vv_quic_crypto", "%s", 
QUIC_CLIENT_HANDSHAKE_TRAFFIC_SECRET_LABEL.data());
       break;
     case SSL_KEY_SERVER_HANDSHAKE_TRAFFIC:
-      Debug("vv_quic_crypto", "server_handshake_traffic");
+      Debug("vv_quic_crypto", "%s", 
QUIC_SERVER_HANDSHAKE_TRAFFIC_SECRET_LABEL.data());
+      break;
+    case SSL_KEY_CLIENT_APPLICATION_TRAFFIC:
+      Debug("vv_quic_crypto", "%s", QUIC_CLIENT_TRAFFIC_SECRET_LABEL.data());
       break;
     case SSL_KEY_SERVER_APPLICATION_TRAFFIC:
-      Debug("vv_quic_crypto", "server_application_traffic");
+      Debug("vv_quic_crypto", "%s", QUIC_SERVER_TRAFFIC_SECRET_LABEL.data());
       break;
     default:
       break;
@@ -329,8 +391,12 @@ QUICTLS::update_key_materials_on_key_cb(int name, const 
uint8_t *secret, size_t
 }
 
 QUICTLS::QUICTLS(QUICPacketProtectionKeyInfo &pp_key_info, SSL_CTX *ssl_ctx, 
NetVConnectionContext_t 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)
+                 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)
 {
   ink_assert(this->_netvc_context != NET_VCONNECTION_UNSET);
 
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index 982bb8a..5094613 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -1372,6 +1372,8 @@ 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}
+  ,
   // Transport Parameters
   {RECT_CONFIG, "proxy.config.quic.no_activity_timeout_in", RECD_INT, "30", 
RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL}
   ,

Reply via email to