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}
,