Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion iocore/net/QUICNetVConnection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
21 changes: 17 additions & 4 deletions iocore/net/quic/QUICConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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");
Expand Down Expand Up @@ -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;
}

//
Expand Down
6 changes: 4 additions & 2 deletions iocore/net/quic/QUICConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class QUICConfigParams : public ConfigInfo

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;

Expand Down Expand Up @@ -100,7 +101,8 @@ class QUICConfigParams : public ConfigInfo

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;

Expand Down
18 changes: 18 additions & 0 deletions iocore/net/quic/QUICGlobals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "QUICGlobals.h"

#include <cstring>
#include <fstream>

#include "P_SSLNextProtocolSet.h"

Expand Down Expand Up @@ -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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How many times will this function be called? Doesn't it overwrite this file every time?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 times for each session. The app open mode seeks to the eos before write, iiuc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it open and close the file 9 times, it doesn't sound great.
Also, in that case, does it mean I need to remove the file before I start new session?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's no ideal, but it not big deal for traffic_quic. For origin server side connection or server side connection, this could be problem. But when we support it, it needs some changes to dump keys for each connections. And proxy.config.quic.client.session_file has same problem. So these should be fixed in same time and it's out of scope from this PR.

As long as you're using wireshark, you don't need to remove. It can find the correct key.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then please create an issue or put a TODO comment for the future work at least. I'm not going to stop you but I don't like leaving a trap like this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roger.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed as #5263


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*/)
{
Expand Down
1 change: 1 addition & 0 deletions iocore/net/quic/QUICGlobals.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class QUIC
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);

Expand Down
6 changes: 6 additions & 0 deletions iocore/net/quic/QUICTLS.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions iocore/net/quic/QUICTLS.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -58,6 +58,7 @@ class QUICTLS : public QUICHandshakeProtocol
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();
Expand All @@ -79,8 +80,6 @@ class QUICTLS : public QUICHandshakeProtocol
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);
Expand All @@ -94,6 +93,8 @@ class QUICTLS : public QUICHandshakeProtocol
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;
Expand Down
90 changes: 78 additions & 12 deletions iocore/net/quic/QUICTLS_openssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 2 additions & 0 deletions mgmt/RecordsConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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}
,
Expand Down