You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2017/11/16 03:25:27 UTC
[trafficserver] branch quic-latest updated: Use AEAD instead of
FNV-1a
This is an automated email from the ASF dual-hosted git repository.
maskit 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 4232178 Use AEAD instead of FNV-1a
4232178 is described below
commit 4232178f07465b8fc7d59d7c42ed58757d64713d
Author: Masakazu Kitajo <ma...@apache.org>
AuthorDate: Wed Nov 15 10:29:34 2017 +0900
Use AEAD instead of FNV-1a
---
.gitignore | 1 +
iocore/net/P_QUICNetVConnection.h | 10 +-
iocore/net/QUICNetVConnection.cc | 172 +++++++--------
iocore/net/quic/Makefile.am | 5 +
iocore/net/quic/QUICCrypto.cc | 244 ++++++---------------
iocore/net/quic/QUICCrypto.h | 50 ++---
iocore/net/quic/QUICCrypto_openssl.cc | 74 ++++---
iocore/net/quic/QUICHandshake.cc | 14 +-
iocore/net/quic/QUICKeyGenerator.cc | 105 +++++++++
iocore/net/quic/QUICKeyGenerator.h | 75 +++++++
.../net/quic/QUICKeyGenerator_openssl.cc | 35 ++-
iocore/net/quic/QUICPacket.cc | 88 ++++++--
iocore/net/quic/QUICPacket.h | 15 +-
iocore/net/quic/QUICTypes.cc | 14 --
iocore/net/quic/QUICTypes.h | 8 +-
iocore/net/quic/test/Makefile.am | 26 +++
iocore/net/quic/test/test_QUICKeyGenerator.cc | 107 +++++++++
lib/ts/HKDF.cc | 11 +-
lib/ts/HKDF.h | 2 +-
lib/ts/HKDF_openssl.cc | 19 +-
20 files changed, 649 insertions(+), 426 deletions(-)
diff --git a/.gitignore b/.gitignore
index 31be23b..e50a04b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,6 +97,7 @@ iocore/net/quic/test/test_QUICStream
iocore/net/quic/test/test_QUICStreamState
iocore/net/quic/test/test_QUICStreamManager
iocore/net/quic/test/test_QUICTransportParameters
+iocore/net/quic/test/test_QUICKeyGenerator
iocore/net/quic/test/test_QUICCrypto
iocore/net/quic/test/test_QUICLossDetector
iocore/net/quic/test/test_QUICTypeUtil
diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h
index 431ff76..b59bc03 100644
--- a/iocore/net/P_QUICNetVConnection.h
+++ b/iocore/net/P_QUICNetVConnection.h
@@ -103,9 +103,10 @@ class SSLNextProtocolSet;
* v
* state_handshake()
* | READ:
- * | _state_handshake_process_initial_client_packet()
- * | _state_handshake_process_client_cleartext_packet()
- * | _state_handshake_process_zero_rtt_protected_packet()
+ * | _state_handshake_process__packet()
+ * | _state_handshake_process_initial_client_packet()
+ * | _state_handshake_process_client_cleartext_packet()
+ * | _state_handshake_process_zero_rtt_protected_packet()
* | WRITE:
* | _state_common_send_packet()
* v
@@ -236,6 +237,7 @@ private:
QUICErrorUPtr _recv_and_ack(const uint8_t *payload, uint16_t size, QUICPacketNumber packet_numm);
+ QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet);
QUICErrorUPtr _state_handshake_process_initial_client_packet(QUICPacketUPtr packet);
QUICErrorUPtr _state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet);
QUICErrorUPtr _state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet);
@@ -249,7 +251,7 @@ private:
void _init_flow_control_params(const std::shared_ptr<const QUICTransportParameters> &local_tp,
const std::shared_ptr<const QUICTransportParameters> &remote_tp);
void _handle_error(QUICErrorUPtr error);
- QUICPacketUPtr _dequeue_recv_packet();
+ QUICPacketUPtr _dequeue_recv_packet(QUICPacketCreationResult &result);
QUICStatelessToken _token;
};
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index 29833c6..48edd88 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -381,36 +381,15 @@ QUICNetVConnection::state_handshake(int event, Event *data)
switch (event) {
case QUIC_EVENT_PACKET_READ_READY: {
- QUICPacketUPtr p = this->_dequeue_recv_packet();
- if (!p) {
- break;
- }
- net_activity(this, this_ethread());
-
- switch (p->type()) {
- case QUICPacketType::CLIENT_INITIAL: {
- error = this->_state_handshake_process_initial_client_packet(std::move(p));
- break;
- }
- case QUICPacketType::CLIENT_CLEARTEXT: {
- error = this->_state_handshake_process_client_cleartext_packet(std::move(p));
- break;
- }
- case QUICPacketType::ZERO_RTT_PROTECTED: {
- error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(p));
- break;
- }
- case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0:
- case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1:
- // Postpone processing the packet
- this->_quic_packet_recv_queue.push(std::move(p));
- this_ethread()->schedule_imm_local(this, event);
- break;
- default:
- error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
- break;
+ QUICPacketCreationResult result;
+ QUICPacketUPtr packet = this->_dequeue_recv_packet(result);
+ if (result == QUICPacketCreationResult::NOT_READY) {
+ error = QUICErrorUPtr(new QUICNoError());
+ } else if (result == QUICPacketCreationResult::FAILED) {
+ error = QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED));
+ } else {
+ error = this->_state_handshake_process_packet(std::move(packet));
}
-
break;
}
case QUIC_EVENT_PACKET_WRITE_READY: {
@@ -640,6 +619,27 @@ QUICNetVConnection::largest_acked_packet_number()
}
QUICErrorUPtr
+QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet)
+{
+ QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
+ switch (packet->type()) {
+ case QUICPacketType::CLIENT_INITIAL:
+ error = this->_state_handshake_process_initial_client_packet(std::move(packet));
+ break;
+ case QUICPacketType::CLIENT_CLEARTEXT:
+ error = this->_state_handshake_process_client_cleartext_packet(std::move(packet));
+ break;
+ case QUICPacketType::ZERO_RTT_PROTECTED:
+ error = this->_state_handshake_process_zero_rtt_protected_packet(std::move(packet));
+ break;
+ default:
+ error = QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
+ break;
+ }
+ return error;
+}
+
+QUICErrorUPtr
QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPtr packet)
{
if (packet->size() < MINIMUM_INITIAL_CLIENT_PACKET_SIZE) {
@@ -651,23 +651,17 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt
// Start handshake
QUICErrorUPtr error = this->_handshake_handler->start(packet.get(), &this->_packet_factory);
if (this->_handshake_handler->is_version_negotiated()) {
- // Check integrity (QUIC-TLS-04: 6.1. Integrity Check Processing)
- if (packet->has_valid_fnv1a_hash()) {
- bool should_send_ack;
- error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack);
- if (error->cls != QUICErrorClass::NONE) {
- return error;
- }
- error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received());
- Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64,
- static_cast<uint64_t>(this->_quic_connection_id), this->_local_flow_controller->current_offset(),
- this->_local_flow_controller->current_limit());
- if (error->cls != QUICErrorClass::NONE) {
- return error;
- }
- } else {
- DebugQUICCon("Invalid FNV-1a hash value");
- // Discard the packet
+ bool should_send_ack;
+ error = this->_frame_dispatcher->receive_frames(packet->payload(), packet->payload_size(), should_send_ack);
+ if (error->cls != QUICErrorClass::NONE) {
+ return error;
+ }
+ error = this->_local_flow_controller->update(this->_stream_manager->total_offset_received());
+ Debug("quic_flow_ctrl", "Connection [%" PRIx64 "] [LOCAL] %" PRIu64 "/%" PRIu64,
+ static_cast<uint64_t>(this->_quic_connection_id), this->_local_flow_controller->current_offset(),
+ this->_local_flow_controller->current_limit());
+ if (error->cls != QUICErrorClass::NONE) {
+ return error;
}
}
return error;
@@ -676,23 +670,12 @@ QUICNetVConnection::_state_handshake_process_initial_client_packet(QUICPacketUPt
QUICErrorUPtr
QUICNetVConnection::_state_handshake_process_client_cleartext_packet(QUICPacketUPtr packet)
{
- QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
-
- // The payload of this packet contains STREAM frames and could contain PADDING and ACK frames
- if (packet->has_valid_fnv1a_hash()) {
- error = this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number());
- } else {
- DebugQUICCon("Invalid FNV-1a hash value");
- // Discard the packet
- }
- return error;
+ return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number());
}
QUICErrorUPtr
QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacketUPtr packet)
{
- // TODO: Decrypt the packet
- // decrypt(payload, p);
// TODO: Not sure what we have to do
return QUICErrorUPtr(new QUICNoError());
}
@@ -700,29 +683,19 @@ QUICNetVConnection::_state_handshake_process_zero_rtt_protected_packet(QUICPacke
QUICErrorUPtr
QUICNetVConnection::_state_connection_established_process_packet(QUICPacketUPtr packet)
{
- // TODO: fix size
- size_t max_plain_txt_len = 2048;
- ats_unique_buf plain_txt = ats_unique_malloc(max_plain_txt_len);
- size_t plain_txt_len = 0;
-
- if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, packet->payload(), packet->payload_size(),
- packet->packet_number(), packet->header(), packet->header_size(), packet->key_phase())) {
- DebugQUICCon("Decrypt Packet, pkt_num: %" PRIu64 ", header_len: %hu, payload_len: %zu", packet->packet_number(),
- packet->header_size(), plain_txt_len);
- return this->_recv_and_ack(plain_txt.get(), plain_txt_len, packet->packet_number());
- } else {
- DebugQUICCon("Decrypt Error");
- return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED));
- }
+ return this->_recv_and_ack(packet->payload(), packet->payload_size(), packet->packet_number());
}
QUICErrorUPtr
QUICNetVConnection::_state_common_receive_packet()
{
QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError());
- QUICPacketUPtr p = this->_dequeue_recv_packet();
- if (!p) {
- return error;
+ QUICPacketCreationResult result;
+ QUICPacketUPtr p = this->_dequeue_recv_packet(result);
+ if (result == QUICPacketCreationResult::FAILED) {
+ return QUICConnectionErrorUPtr(new QUICConnectionError(QUICTransErrorCode::TLS_FATAL_ALERT_GENERATED));
+ } else if (result == QUICPacketCreationResult::NOT_READY) {
+ return QUICErrorUPtr(new QUICNoError());
}
net_activity(this, this_ethread());
@@ -964,32 +937,39 @@ QUICNetVConnection::_handle_error(QUICErrorUPtr error)
}
QUICPacketUPtr
-QUICNetVConnection::_dequeue_recv_packet()
+QUICNetVConnection::_dequeue_recv_packet(QUICPacketCreationResult &result)
{
QUICPacketUPtr quic_packet = QUICPacketUPtr(nullptr, &QUICPacketDeleter::delete_null_packet);
UDPPacket *udp_packet = this->_packet_recv_queue.dequeue();
- if (udp_packet) {
- ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength());
- IOBufferBlock *b = udp_packet->getIOBlockChain();
- size_t written = 0;
- while (b) {
- memcpy(pkt.get() + written, b->buf(), b->read_avail());
- written += b->read_avail();
- b = b->next.get();
- }
- udp_packet->free();
- quic_packet = QUICPacketFactory::create(std::move(pkt), written, this->largest_received_packet_number());
+ if (!udp_packet) {
+ result = QUICPacketCreationResult::NOT_READY;
+ return quic_packet;
}
+ net_activity(this, this_ethread());
- if (this->_quic_packet_recv_queue.size() > 0) {
- QUICPacketUPtr p = std::move(this->_quic_packet_recv_queue.front());
- this->_quic_packet_recv_queue.pop();
- this->_quic_packet_recv_queue.push(std::move(quic_packet));
- quic_packet.reset(p.release());
- }
- if (quic_packet) {
- DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()),
- quic_packet->packet_number(), quic_packet->size());
+ // Create a QUIC packet
+ ats_unique_buf pkt = ats_unique_malloc(udp_packet->getPktLength());
+ IOBufferBlock *b = udp_packet->getIOBlockChain();
+ size_t written = 0;
+ while (b) {
+ memcpy(pkt.get() + written, b->buf(), b->read_avail());
+ written += b->read_avail();
+ b = b->next.get();
+ }
+ quic_packet = this->_packet_factory.create(std::move(pkt), written, this->largest_received_packet_number(), result);
+ if (result == QUICPacketCreationResult::NOT_READY) {
+ DebugQUICCon("Not ready to decrypt the packet");
+ // Retry later
+ this->_packet_recv_queue.enqueue(udp_packet);
+ this_ethread()->schedule_imm_local(this, QUIC_EVENT_PACKET_READ_READY);
+ } else {
+ udp_packet->free();
+ if (result == QUICPacketCreationResult::SUCCESS) {
+ DebugQUICCon("type=%s pkt_num=%" PRIu64 " size=%u", QUICDebugNames::packet_type(quic_packet->type()), quic_packet->packet_number(), quic_packet->size());
+ } else {
+ DebugQUICCon("Failed to decrypt the packet");
+ }
}
+
return quic_packet;
}
diff --git a/iocore/net/quic/Makefile.am b/iocore/net/quic/Makefile.am
index 3fc2585..62df5dd 100644
--- a/iocore/net/quic/Makefile.am
+++ b/iocore/net/quic/Makefile.am
@@ -36,8 +36,10 @@ noinst_LIBRARIES = libquic.a
if OPENSSL_IS_BORINGSSL
QUICCrypto_impl = QUICCrypto_boringssl.cc
+QUICKeyGenerator_impl = QUICKeyGenerator_boringssl.cc
else
QUICCrypto_impl = QUICCrypto_openssl.cc
+QUICKeyGenerator_impl = QUICKeyGenerator_openssl.cc
endif
libquic_a_SOURCES = \
@@ -56,6 +58,9 @@ libquic_a_SOURCES = \
QUICHandshake.cc \
QUICCrypto.cc \
$(QUICCrypto_impl) \
+ QUICKeyGenerator.cc \
+ $(QUICKeyGenerator_impl) \
+ QUICKeyGenerator.cc \
QUICTransportParameters.cc \
QUICAckFrameCreator.cc \
QUICConfig.cc \
diff --git a/iocore/net/quic/QUICCrypto.cc b/iocore/net/quic/QUICCrypto.cc
index 3c6446d..ec020a8 100644
--- a/iocore/net/quic/QUICCrypto.cc
+++ b/iocore/net/quic/QUICCrypto.cc
@@ -34,44 +34,41 @@
constexpr static char tag[] = "quic_crypto";
-// constexpr static ts::StringView _exporter_label_0_rtt("EXPORTER-QUIC 0-RTT Secret", ts::StringView::literal);
-constexpr static ts::string_view exporter_label_client_1_rtt("EXPORTER-QUIC client 1-RTT Secret"_sv);
-constexpr static ts::string_view exporter_label_server_1_rtt("EXPORTER-QUIC server 1-RTT Secret"_sv);
-
-// [quic-tls draft-05] "tls13 " + Label
-// constexpr static ts::StringView expand_label_client_1_rtt("tls13 QUIC client 1-RTT secret", ts::StringView::literal);
-// constexpr static ts::StringView expand_label_server_1_rtt("tls13 QUIC server 1-RTT secret", ts::StringView::literal);
-constexpr static ts::string_view expand_label_key("tls13 key"_sv);
-constexpr static ts::string_view expand_label_iv("tls13 iv"_sv);
-
//
// QUICPacketProtection
//
QUICPacketProtection::~QUICPacketProtection()
{
- delete this->_phase_0_key;
- delete this->_phase_1_key;
}
void
-QUICPacketProtection::set_key(KeyMaterial *km, QUICKeyPhase phase)
+QUICPacketProtection::set_key(std::unique_ptr<KeyMaterial>km, QUICKeyPhase phase)
{
this->_key_phase = phase;
- if (phase == QUICKeyPhase::PHASE_0) {
- this->_phase_0_key = km;
- } else {
- this->_phase_1_key = km;
+ switch(phase) {
+ case QUICKeyPhase::PHASE_0:
+ this->_phase_0_key = std::move(km);
+ break;
+ case QUICKeyPhase::PHASE_1:
+ this->_phase_1_key = std::move(km);
+ break;
+ case QUICKeyPhase::CLEARTEXT:
+ this->_cleartext_key = std::move(km);
+ break;
}
}
-const KeyMaterial *
+const KeyMaterial&
QUICPacketProtection::get_key(QUICKeyPhase phase) const
{
- if (phase == QUICKeyPhase::PHASE_0) {
- return this->_phase_0_key;
- } else {
- return this->_phase_1_key;
+ switch(phase) {
+ case QUICKeyPhase::PHASE_0:
+ return *this->_phase_0_key;
+ case QUICKeyPhase::PHASE_1:
+ return *this->_phase_1_key;
+ case QUICKeyPhase::CLEARTEXT:
+ return *this->_cleartext_key;
}
}
@@ -100,7 +97,6 @@ QUICCrypto::QUICCrypto(SSL *ssl, NetVConnectionContext_t nvc_ctx) : _ssl(ssl), _
QUICCrypto::~QUICCrypto()
{
- delete this->_hkdf;
delete this->_client_pp;
delete this->_server_pp;
}
@@ -160,88 +156,55 @@ QUICCrypto::is_handshake_finished() const
}
int
-QUICCrypto::setup_session()
+QUICCrypto::initialize_key_materials(QUICConnectionId cid)
{
+ this->_aead = _get_evp_aead();
+
+ std::unique_ptr<KeyMaterial> km;
+ // for decryption
+ km = this->_keygen_for_client.generate(cid);
+ this->_client_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT);
+ // for encryption
+ km = this->_keygen_for_server.generate(cid);
+ this->_server_pp->set_key(std::move(km), QUICKeyPhase::CLEARTEXT);
+ return 1;
+}
+
+int
+QUICCrypto::update_key_materials()
+{
+ QUICKeyPhase next_key_phase;
+ switch (this->_client_pp->key_phase()) {
+ case QUICKeyPhase::PHASE_0:
+ next_key_phase = QUICKeyPhase::PHASE_1;
+ break;
+ case QUICKeyPhase::PHASE_1:
+ next_key_phase = QUICKeyPhase::PHASE_0;
+ break;
+ case QUICKeyPhase::CLEARTEXT:
+ next_key_phase = QUICKeyPhase::PHASE_0;
+ break;
+ }
const SSL_CIPHER *cipher = SSL_get_current_cipher(this->_ssl);
- this->_digest = _get_handshake_digest(cipher);
- this->_aead = _get_evp_aead(cipher);
- this->_hkdf = new HKDF(this->_digest);
+ this->_aead = _get_evp_aead();
- size_t secret_len = EVP_MD_size(this->_digest);
+ size_t secret_len = EVP_MD_size(_get_handshake_digest(cipher));
size_t key_len = _get_aead_key_len(this->_aead);
size_t iv_len = std::max(static_cast<size_t>(8), _get_aead_nonce_len(this->_aead));
- int r = 0;
-
- r = _export_client_keymaterial(secret_len, key_len, iv_len);
- if (r != 1) {
- return r;
- }
-
- r = _export_server_keymaterial(secret_len, key_len, iv_len);
- if (r != 1) {
- return r;
- }
+ std::unique_ptr<KeyMaterial> km;
+ // for decryption
+ km = this->_keygen_for_client.generate();
+ this->_client_pp->set_key(std::move(km), next_key_phase);
+ // for encryption
+ km = this->_keygen_for_server.generate();
+ this->_server_pp->set_key(std::move(km), next_key_phase);
Debug(tag, "Negotiated ciper: %s, secret_len: %zu, key_len: %zu, iv_len: %zu", SSL_CIPHER_get_name(cipher), secret_len, key_len,
iv_len);
return 1;
}
-/**
- * update client_pp_secret_<N+1> and keying material
- */
-int
-QUICCrypto::update_client_keymaterial()
-{
- return 0;
- // KeyMaterial *km_n = nullptr;
- // KeyMaterial *km_n_1 = new KeyMaterial(km_n->secret_len, km_n->key_len, km_n->iv_len);
- // uint8_t secret[256] = {0};
- // int r = 0;
-
- // r = _hkdf_expand_label(secret, km_n->secret_len, km_n->secret, km_n->secret_len, _expand_label_client_1_rtt,
- // sizeof(_expand_label_client_1_rtt), this->_digest);
- // if (r != 1) {
- // return r;
- // }
-
- // r = km_n_1->init(this->_aead, this->_digest, secret);
- // if (r != 1) {
- // return r;
- // }
- // this->_server_pp->set_key(km_n_1, new_key_phase);
-
- // return 1;
-}
-
-/**
- * update server_pp_secret_<N+1> and keying material
- */
-int
-QUICCrypto::update_server_keymaterial()
-{
- return 0;
- // KeyMaterial *km_n = nullptr;
- // KeyMaterial *km_n_1 = new KeyMaterial(km_n->secret_len, km_n->key_len, km_n->iv_len);
- // uint8_t secret[256] = {0};
- // int r = 0;
-
- // r = _hkdf_expand_label(secret, km_n->secret_len, km_n->secret, km_n->secret_len, _expand_label_server_1_rtt,
- // sizeof(_expand_label_server_1_rtt), this->_digest);
- // if (r != 1) {
- // return r;
- // }
-
- // r = km_n_1->init(this->_aead, this->_digest, secret);
- // if (r != 1) {
- // return r;
- // }
- // this->_server_pp->set_key(km_n_1, new_key_phase);
-
- // return 1;
-}
-
SSL *
QUICCrypto::ssl_handle()
{
@@ -252,15 +215,15 @@ bool
QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len,
uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const
{
- const KeyMaterial *km = nullptr;
+ QUICPacketProtection *pp = nullptr;
switch (this->_netvc_context) {
case NET_VCONNECTION_IN: {
- km = this->_server_pp->get_key(phase);
+ pp = this->_server_pp;
break;
}
case NET_VCONNECTION_OUT: {
- km = this->_client_pp->get_key(phase);
+ pp = this->_client_pp;
break;
}
default:
@@ -268,24 +231,23 @@ QUICCrypto::encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len,
return false;
}
- size_t tag_len = _get_aead_tag_len(SSL_get_current_cipher(this->_ssl));
- return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, km->key, km->key_len, km->iv,
- km->iv_len, tag_len);
+ size_t tag_len = this->_get_aead_tag_len();
+ return _encrypt(cipher, cipher_len, max_cipher_len, plain, plain_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len);
}
bool
QUICCrypto::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len,
uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const
{
- const KeyMaterial *km = nullptr;
+ QUICPacketProtection *pp = nullptr;
switch (this->_netvc_context) {
case NET_VCONNECTION_IN: {
- km = this->_client_pp->get_key(phase);
+ pp = this->_client_pp;
break;
}
case NET_VCONNECTION_OUT: {
- km = this->_server_pp->get_key(phase);
+ pp = this->_server_pp;
break;
}
default:
@@ -293,82 +255,8 @@ QUICCrypto::decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, con
return false;
}
- size_t tag_len = _get_aead_tag_len(SSL_get_current_cipher(this->_ssl));
- return _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, km->key, km->key_len, km->iv,
- km->iv_len, tag_len);
-}
-
-int
-QUICCrypto::_export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const
-{
- return SSL_export_keying_material(this->_ssl, dst, dst_len, label, label_len, reinterpret_cast<const uint8_t *>(""), 0, 1);
-}
-
-/**
- * export client_pp_secret_0 and keying material
- */
-int
-QUICCrypto::_export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len)
-{
- KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len);
- int r = 0;
-
- r = _export_secret(km->secret, secret_len, exporter_label_client_1_rtt.data(), exporter_label_client_1_rtt.size());
- if (r != 1) {
- Debug(tag, "Failed to export secret");
- return r;
- }
-
- r = this->_hkdf->expand_label(km->key, &key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(),
- EVP_MD_size(this->_digest));
- if (r != 1) {
- Debug(tag, "Failed to expand label for key");
- return r;
- }
-
- r = this->_hkdf->expand_label(km->iv, &iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(),
- EVP_MD_size(this->_digest));
- if (r != 1) {
- Debug(tag, "Failed to expand label for iv");
- return r;
- }
-
- this->_client_pp->set_key(km, QUICKeyPhase::PHASE_0);
-
- return 1;
-}
-
-/**
- * export server_pp_secret_0 and keying material
- */
-int
-QUICCrypto::_export_server_keymaterial(size_t secret_len, size_t key_len, size_t iv_len)
-{
- KeyMaterial *km = new KeyMaterial(secret_len, key_len, iv_len);
- int r = 0;
-
- r = _export_secret(km->secret, secret_len, exporter_label_server_1_rtt.data(), exporter_label_server_1_rtt.size());
- if (r != 1) {
- return r;
- }
-
- r = this->_hkdf->expand_label(km->key, &key_len, km->secret, secret_len, expand_label_key.data(), expand_label_key.size(),
- EVP_MD_size(this->_digest));
- if (r != 1) {
- Debug(tag, "Failed to expand label for key");
- return r;
- }
-
- r = this->_hkdf->expand_label(km->iv, &iv_len, km->secret, secret_len, expand_label_iv.data(), expand_label_iv.size(),
- EVP_MD_size(this->_digest));
- if (r != 1) {
- Debug(tag, "Failed to expand label for iv");
- return r;
- }
-
- this->_server_pp->set_key(km, QUICKeyPhase::PHASE_0);
-
- return 1;
+ size_t tag_len = this->_get_aead_tag_len();
+ return _decrypt(plain, plain_len, max_plain_len, cipher, cipher_len, pkt_num, ad, ad_len, pp->get_key(phase), tag_len);
}
/**
diff --git a/iocore/net/quic/QUICCrypto.h b/iocore/net/quic/QUICCrypto.h
index 3e8e0fd..8f5888a 100644
--- a/iocore/net/quic/QUICCrypto.h
+++ b/iocore/net/quic/QUICCrypto.h
@@ -23,7 +23,7 @@
#pragma once
-#include "ts/HKDF.h"
+#include "QUICKeyGenerator.h"
#include <openssl/ssl.h>
#ifdef OPENSSL_IS_BORINGSSL
@@ -37,32 +37,20 @@
#include "I_NetVConnection.h"
#include "QUICTypes.h"
-struct KeyMaterial {
- KeyMaterial(size_t secret_len, size_t key_len, size_t iv_len) : secret_len(secret_len), key_len(key_len), iv_len(iv_len) {}
- uint8_t secret[EVP_MAX_MD_SIZE] = {0};
- // These constant sizes are not enough somehow
- // uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
- // uint8_t iv[EVP_MAX_IV_LENGTH] = {0};
- uint8_t key[512] = {0};
- uint8_t iv[512] = {0};
- size_t secret_len = 0;
- size_t key_len = 0;
- size_t iv_len = 0;
-};
-
class QUICPacketProtection
{
public:
QUICPacketProtection(){};
~QUICPacketProtection();
- void set_key(KeyMaterial *km, QUICKeyPhase phase);
- const KeyMaterial *get_key(QUICKeyPhase phase) const;
+ void set_key(std::unique_ptr<KeyMaterial> km, QUICKeyPhase phase);
+ const KeyMaterial& get_key(QUICKeyPhase phase) const;
QUICKeyPhase key_phase() const;
private:
- KeyMaterial *_phase_0_key = nullptr;
- KeyMaterial *_phase_1_key = nullptr;
- QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED;
+ std::unique_ptr<KeyMaterial> _cleartext_key = nullptr;
+ std::unique_ptr<KeyMaterial> _phase_0_key = nullptr;
+ std::unique_ptr<KeyMaterial> _phase_1_key = nullptr;
+ QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT;
};
class QUICCrypto
@@ -73,7 +61,8 @@ public:
bool handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint8_t *in, size_t in_len);
bool is_handshake_finished() const;
- int setup_session();
+ int initialize_key_materials(QUICConnectionId cid);
+ int update_key_materials();
bool encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len, uint64_t pkt_num,
const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const;
bool decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, uint64_t pkt_num,
@@ -85,31 +74,25 @@ public:
SSL *ssl_handle();
private:
- HKDF *_hkdf = nullptr;
- int _export_secret(uint8_t *dst, size_t dst_len, const char *label, size_t label_len) const;
- int _export_client_keymaterial(size_t secret_len, size_t key_len, size_t iv_len);
- int _export_server_keymaterial(size_t secret_len, size_t key_len, size_t iv_len);
+ QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT);
+ QUICKeyGenerator _keygen_for_server = QUICKeyGenerator(QUICKeyGenerator::Context::SERVER);
void _gen_nonce(uint8_t *nonce, size_t &nonce_len, uint64_t pkt_num, const uint8_t *iv, size_t iv_len) const;
- int _hkdf_expand_label(const uint8_t *dst, size_t dst_len, const uint8_t *secret, size_t secret_len, const char *label,
- size_t label_len, const EVP_MD *digest);
#ifdef OPENSSL_IS_BORINGSSL
- const EVP_AEAD *_get_evp_aead(const SSL_CIPHER *cipher) const;
+ const EVP_AEAD *_get_evp_aead() const;
size_t _get_aead_key_len(const EVP_AEAD *aead) const;
size_t _get_aead_nonce_len(const EVP_AEAD *aead) const;
#else
- const EVP_CIPHER *_get_evp_aead(const SSL_CIPHER *cipher) const;
+ const EVP_CIPHER *_get_evp_aead() const;
size_t _get_aead_key_len(const EVP_CIPHER *aead) const;
size_t _get_aead_nonce_len(const EVP_CIPHER *aead) const;
#endif // OPENSSL_IS_BORINGSSL
const EVP_MD *_get_handshake_digest(const SSL_CIPHER *cipher) const;
- size_t _get_aead_tag_len(const SSL_CIPHER *cipher) const;
+ size_t _get_aead_tag_len() const;
bool _encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len,
- uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv,
- size_t iv_len, size_t tag_len) const;
+ uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const;
bool _decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len, uint64_t pkt_num,
- const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len,
- size_t tag_len) const;
+ const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const;
SSL *_ssl = nullptr;
#ifdef OPENSSL_IS_BORINGSSL
@@ -117,7 +100,6 @@ private:
#else
const EVP_CIPHER *_aead = nullptr;
#endif // OPENSSL_IS_BORINGSSL
- const EVP_MD *_digest = nullptr;
QUICPacketProtection *_client_pp = nullptr;
QUICPacketProtection *_server_pp = nullptr;
NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET;
diff --git a/iocore/net/quic/QUICCrypto_openssl.cc b/iocore/net/quic/QUICCrypto_openssl.cc
index b2858f3..10a9052 100644
--- a/iocore/net/quic/QUICCrypto_openssl.cc
+++ b/iocore/net/quic/QUICCrypto_openssl.cc
@@ -31,21 +31,25 @@
static constexpr char tag[] = "quic_crypto";
const EVP_CIPHER *
-QUICCrypto::_get_evp_aead(const SSL_CIPHER *cipher) const
+QUICCrypto::_get_evp_aead() const
{
- switch (SSL_CIPHER_get_id(cipher)) {
- case TLS1_3_CK_AES_128_GCM_SHA256:
+ if (this->is_handshake_finished()) {
+ switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) {
+ case TLS1_3_CK_AES_128_GCM_SHA256:
+ return EVP_aes_128_gcm();
+ case TLS1_3_CK_AES_256_GCM_SHA384:
+ return EVP_aes_256_gcm();
+ case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+ return EVP_chacha20_poly1305();
+ case TLS1_3_CK_AES_128_CCM_SHA256:
+ case TLS1_3_CK_AES_128_CCM_8_SHA256:
+ return EVP_aes_128_ccm();
+ default:
+ ink_assert(false);
+ return nullptr;
+ }
+ } else {
return EVP_aes_128_gcm();
- case TLS1_3_CK_AES_256_GCM_SHA384:
- return EVP_aes_256_gcm();
- case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
- return EVP_chacha20_poly1305();
- case TLS1_3_CK_AES_128_CCM_SHA256:
- case TLS1_3_CK_AES_128_CCM_8_SHA256:
- return EVP_aes_128_ccm();
- default:
- ink_assert(false);
- return nullptr;
}
}
@@ -67,21 +71,25 @@ QUICCrypto::_get_handshake_digest(const SSL_CIPHER *cipher) const
}
size_t
-QUICCrypto::_get_aead_tag_len(const SSL_CIPHER *cipher) const
+QUICCrypto::_get_aead_tag_len() const
{
- switch (SSL_CIPHER_get_id(cipher)) {
- case TLS1_3_CK_AES_128_GCM_SHA256:
- case TLS1_3_CK_AES_256_GCM_SHA384:
+ if (this->is_handshake_finished()) {
+ switch (SSL_CIPHER_get_id(SSL_get_current_cipher(this->_ssl))) {
+ case TLS1_3_CK_AES_128_GCM_SHA256:
+ case TLS1_3_CK_AES_256_GCM_SHA384:
+ return EVP_GCM_TLS_TAG_LEN;
+ case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+ return EVP_CHACHAPOLY_TLS_TAG_LEN;
+ case TLS1_3_CK_AES_128_CCM_SHA256:
+ return EVP_CCM_TLS_TAG_LEN;
+ case TLS1_3_CK_AES_128_CCM_8_SHA256:
+ return EVP_CCM8_TLS_TAG_LEN;
+ default:
+ ink_assert(false);
+ return -1;
+ }
+ } else {
return EVP_GCM_TLS_TAG_LEN;
- case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
- return EVP_CHACHAPOLY_TLS_TAG_LEN;
- case TLS1_3_CK_AES_128_CCM_SHA256:
- return EVP_CCM_TLS_TAG_LEN;
- case TLS1_3_CK_AES_128_CCM_8_SHA256:
- return EVP_CCM8_TLS_TAG_LEN;
- default:
- ink_assert(false);
- return -1;
}
}
@@ -99,12 +107,11 @@ QUICCrypto::_get_aead_nonce_len(const EVP_CIPHER *aead) const
bool
QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len, const uint8_t *plain, size_t plain_len,
- uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv,
- size_t iv_len, size_t tag_len) const
+ uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const
{
uint8_t nonce[EVP_MAX_IV_LENGTH] = {0};
size_t nonce_len = 0;
- _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len);
+ _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len);
EVP_CIPHER_CTX *aead_ctx;
int len;
@@ -118,7 +125,7 @@ QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len,
if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
return false;
}
- if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ if (!EVP_EncryptInit_ex(aead_ctx, nullptr, nullptr, km.key, nonce)) {
return false;
}
if (!EVP_EncryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
@@ -149,12 +156,11 @@ QUICCrypto::_encrypt(uint8_t *cipher, size_t &cipher_len, size_t max_cipher_len,
bool
QUICCrypto::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len,
- uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const uint8_t *key, size_t key_len, const uint8_t *iv,
- size_t iv_len, size_t tag_len) const
+ uint64_t pkt_num, const uint8_t *ad, size_t ad_len, const KeyMaterial &km, size_t tag_len) const
{
uint8_t nonce[EVP_MAX_IV_LENGTH] = {0};
size_t nonce_len = 0;
- _gen_nonce(nonce, nonce_len, pkt_num, iv, iv_len);
+ _gen_nonce(nonce, nonce_len, pkt_num, km.iv, km.iv_len);
EVP_CIPHER_CTX *aead_ctx;
int len;
@@ -168,7 +174,7 @@ QUICCrypto::_decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, co
if (!EVP_CIPHER_CTX_ctrl(aead_ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, nullptr)) {
return false;
}
- if (!EVP_DecryptInit_ex(aead_ctx, nullptr, nullptr, key, nonce)) {
+ if (!EVP_DecryptInit_ex(aead_ctx, nullptr, nullptr, km.key, nonce)) {
return false;
}
if (!EVP_DecryptUpdate(aead_ctx, nullptr, &len, ad, ad_len)) {
diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc
index b23609f..c33f3b6 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -89,6 +89,7 @@ QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStateless
this->_crypto = new QUICCrypto(this->_ssl, qc->direction());
this->_version_negotiator = new QUICVersionNegotiator();
+ this->_crypto->initialize_key_materials(this->_client_qc->connection_id());
this->_load_local_transport_parameters();
SET_HANDLER(&QUICHandshake::state_read_client_hello);
@@ -321,12 +322,10 @@ QUICHandshake::_process_client_hello()
I_WANNA_DUMP_THIS_BUF(msg, msg_len);
// <----- DEBUG -----
- QUICCrypto *crypto = this->_crypto;
-
uint8_t server_hello[MAX_HANDSHAKE_MSG_LEN] = {0};
size_t server_hello_len = 0;
bool result = false;
- result = crypto->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len);
+ result = this->_crypto->handshake(server_hello, server_hello_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len);
if (result) {
// ----- DEBUG ----->
@@ -365,12 +364,10 @@ QUICHandshake::_process_client_finished()
I_WANNA_DUMP_THIS_BUF(msg, msg_len);
// <----- DEBUG -----
- QUICCrypto *crypto = this->_crypto;
-
uint8_t out[MAX_HANDSHAKE_MSG_LEN] = {0};
size_t out_len = 0;
bool result = false;
- result = crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len);
+ result = this->_crypto->handshake(out, out_len, MAX_HANDSHAKE_MSG_LEN, msg, msg_len);
if (result) {
// ----- DEBUG ----->
@@ -398,10 +395,7 @@ QUICHandshake::_process_client_finished()
QUICErrorUPtr
QUICHandshake::_process_handshake_complete()
{
- QUICCrypto *crypto = this->_crypto;
- int r = crypto->setup_session();
-
- if (r) {
+ if (this->_crypto->update_key_materials()) {
DebugQHS("Keying Materials are exported");
} else {
DebugQHS("Failed to export Keying Materials");
diff --git a/iocore/net/quic/QUICKeyGenerator.cc b/iocore/net/quic/QUICKeyGenerator.cc
new file mode 100644
index 0000000..49277ed
--- /dev/null
+++ b/iocore/net/quic/QUICKeyGenerator.cc
@@ -0,0 +1,105 @@
+/** @file
+ *
+ * A key generator for QUIC connection
+ *
+ * @section license License
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "QUICKeyGenerator.h"
+#include "ts/HKDF.h"
+
+constexpr static uint8_t QUIC_VERSION_1_SALT[] = {
+ 0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca,
+ 0x1e, 0x9d, 0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65,
+ 0x18, 0xc3, 0x66, 0x39,
+};
+constexpr static ts::string_view LABEL_FOR_CLIENT_CLEARTEXT_SECRET("QUIC client cleartext Secret"_sv);
+constexpr static ts::string_view LABEL_FOR_SERVER_CLEARTEXT_SECRET("QUIC server cleartext Secret"_sv);
+constexpr static ts::string_view LABEL_FOR_KEY("key"_sv);
+constexpr static ts::string_view LABEL_FOR_IV("iv"_sv);
+
+std::unique_ptr<KeyMaterial>
+QUICKeyGenerator::generate(QUICConnectionId cid)
+{
+ std::unique_ptr<KeyMaterial> km = std::make_unique<KeyMaterial>();
+
+ const EVP_MD *md= EVP_sha256();
+ const QUIC_EVP_CIPHER *cipher = this->_get_cipher_for_cleartext();
+ uint8_t cleartext_secret[256];
+ size_t cleartext_secret_len = sizeof(cleartext_secret);
+ uint8_t client_connection_id[8];
+ size_t cid_len = 0;
+ HKDF hkdf(md);
+
+ QUICTypeUtil::write_QUICConnectionId(cid, 8, client_connection_id, &cid_len);
+ if (hkdf.extract(cleartext_secret, &cleartext_secret_len, QUIC_VERSION_1_SALT, sizeof(QUIC_VERSION_1_SALT), client_connection_id, 8) != 1) {
+ return nullptr;
+ }
+
+ switch (this->_ctx) {
+ case Context::CLIENT:
+ this->_generate(
+ km->key, &km->key_len, km->iv, &km->iv_len,
+ hkdf,
+ cleartext_secret, cleartext_secret_len,
+ LABEL_FOR_CLIENT_CLEARTEXT_SECRET.data(), LABEL_FOR_CLIENT_CLEARTEXT_SECRET.length(),
+ md, cipher);
+ break;
+ case Context::SERVER:
+ this->_generate(
+ km->key, &km->key_len, km->iv, &km->iv_len,
+ hkdf,
+ cleartext_secret, cleartext_secret_len,
+ LABEL_FOR_SERVER_CLEARTEXT_SECRET.data(), LABEL_FOR_SERVER_CLEARTEXT_SECRET.length(),
+ md, cipher);
+ break;
+ }
+
+ return km;
+}
+
+std::unique_ptr<KeyMaterial>
+QUICKeyGenerator::generate()
+{
+ return 0;
+}
+
+int
+QUICKeyGenerator::_generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *base_secret, size_t base_secret_len, const char *label, size_t label_len, const EVP_MD *md, const QUIC_EVP_CIPHER *cipher)
+{
+ uint8_t secret[256];
+ size_t secret_len = sizeof(secret);
+ hkdf.expand_label(secret, &secret_len, base_secret, base_secret_len, reinterpret_cast<const char *>(label), label_len, "", 0, EVP_MD_size(md));
+ this->_generate_key(key, key_len, hkdf, secret, secret_len, this->_get_key_len(cipher));
+ this->_generate_iv(iv, iv_len, hkdf, secret, secret_len, this->_get_iv_len(cipher));
+
+ return 0;
+}
+
+int
+QUICKeyGenerator::_generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const
+{
+ return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_KEY.data(), LABEL_FOR_KEY.length(), "", 0, key_length);
+}
+
+int
+QUICKeyGenerator::_generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const
+{
+ return hkdf.expand_label(out, out_len, secret, secret_len, LABEL_FOR_IV.data(), LABEL_FOR_IV.length(), "", 0, iv_length);
+}
diff --git a/iocore/net/quic/QUICKeyGenerator.h b/iocore/net/quic/QUICKeyGenerator.h
new file mode 100644
index 0000000..a8e8c32
--- /dev/null
+++ b/iocore/net/quic/QUICKeyGenerator.h
@@ -0,0 +1,75 @@
+/** @file
+ *
+ * A key generator for QUIC connection
+ *
+ * @section license License
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <openssl/evp.h>
+#include "QUICTypes.h"
+#include "ts/HKDF.h"
+
+#ifdef OPENSSL_IS_BORINGSSL
+typedef EVP_AEAD QUIC_EVP_CIPHER;
+#else
+typedef EVP_CIPHER QUIC_EVP_CIPHER;
+#endif // OPENSSL_IS_BORINGSSL
+
+struct KeyMaterial {
+ // These constant sizes are not enough somehow
+ // uint8_t key[EVP_MAX_KEY_LENGTH] = {0};
+ // uint8_t iv[EVP_MAX_IV_LENGTH] = {0};
+ uint8_t key[512] = {0};
+ uint8_t iv[512] = {0};
+ size_t key_len = 512;
+ size_t iv_len = 512;
+};
+
+class QUICKeyGenerator
+{
+public:
+ enum class Context {
+ SERVER, CLIENT
+ };
+
+ QUICKeyGenerator(Context ctx) : _ctx(ctx) {}
+
+ /*
+ * Gnerate a key and an IV for Cleartext
+ */
+ std::unique_ptr<KeyMaterial> generate(QUICConnectionId cid);
+
+ /*
+ * Generate a key and an IV for Packet Protection
+ *
+ * On the first call, this generates a secret with the constatnt label and generate a key material with the secret.
+ * On the following call, this regenerates a new secret based on the last secret and genereate a new key material with the new secret.
+ */
+ std::unique_ptr<KeyMaterial> generate();
+
+private:
+ Context _ctx = Context::SERVER;
+ int _generate(uint8_t *key, size_t *key_len, uint8_t *iv, size_t *iv_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const EVP_MD *md, const QUIC_EVP_CIPHER *cipher);
+ int _generate_key(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t key_length) const;
+ int _generate_iv(uint8_t *out, size_t *out_len, HKDF &hkdf, const uint8_t *secret, size_t secret_len, size_t iv_length) const;
+ size_t _get_key_len(const QUIC_EVP_CIPHER *cipher) const;
+ size_t _get_iv_len(const QUIC_EVP_CIPHER *cipher) const;
+ const QUIC_EVP_CIPHER *_get_cipher_for_cleartext() const;
+};
diff --git a/lib/ts/HKDF.cc b/iocore/net/quic/QUICKeyGenerator_openssl.cc
similarity index 54%
copy from lib/ts/HKDF.cc
copy to iocore/net/quic/QUICKeyGenerator_openssl.cc
index fe01117..a7fb4ac 100644
--- a/lib/ts/HKDF.cc
+++ b/iocore/net/quic/QUICKeyGenerator_openssl.cc
@@ -1,6 +1,6 @@
/** @file
*
- * HKDF utility (common part)
+ * A key generator for QUIC connection (OpenSSL specific parts)
*
* @section license License
*
@@ -20,25 +20,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "HKDF.h"
-#include <cstdio>
-#include <cstring>
+#include "QUICKeyGenerator.h"
-int
-HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len,
- uint16_t length)
+size_t
+QUICKeyGenerator::_get_key_len(const QUIC_EVP_CIPHER *cipher) const
{
- // Create HKDF label
- uint8_t hkdf_label[512]; // 2 + 255 + 255
- // Length
- hkdf_label[0] = (length >> 8) & 0xFF;
- hkdf_label[1] = length & 0xFF;
- // "tls13 " + Label
- int hkdf_label_len = sprintf(reinterpret_cast<char *>(hkdf_label + 2), "tls13 %.*s", static_cast<int>(label_len), label);
- // Always 0
- hkdf_label[hkdf_label_len] = 0;
- ++hkdf_label_len;
+ return EVP_CIPHER_key_length(cipher);
+}
- this->expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length);
- return 1;
+size_t
+QUICKeyGenerator::_get_iv_len(const QUIC_EVP_CIPHER *cipher) const
+{
+ return EVP_CIPHER_iv_length(cipher);
+}
+
+const QUIC_EVP_CIPHER *
+QUICKeyGenerator::_get_cipher_for_cleartext() const
+{
+ return EVP_aes_128_gcm();
}
diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc
index 95572cd..82e0b74 100644
--- a/iocore/net/quic/QUICPacket.cc
+++ b/iocore/net/quic/QUICPacket.cc
@@ -174,6 +174,16 @@ QUICPacketLongHeader::payload() const
}
}
+uint16_t
+QUICPacketHeader::payload_size() const
+{
+ if (this->_buf) {
+ return this->_buf_len - this->length();
+ } else {
+ return this->_payload_len;
+ }
+}
+
bool
QUICPacketLongHeader::has_key_phase() const
{
@@ -233,7 +243,6 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICPacketNumb
this->_key_phase = QUICKeyPhase::PHASE_1;
} else {
ink_assert(false);
- this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED;
}
}
@@ -254,11 +263,8 @@ QUICPacketShortHeader::QUICPacketShortHeader(QUICPacketType type, QUICConnection
this->_key_phase = QUICKeyPhase::PHASE_0;
} else if (type == QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1) {
this->_key_phase = QUICKeyPhase::PHASE_1;
- } else if (type == QUICPacketType::STATELESS_RESET) {
- this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED;
} else {
ink_assert(false);
- this->_key_phase = QUICKeyPhase::PHASE_UNINITIALIZED;
}
}
@@ -445,10 +451,12 @@ QUICPacketShortHeader::store(uint8_t *buf, size_t *len) const
//
// QUICPacket
//
-QUICPacket::QUICPacket(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number)
+QUICPacket::QUICPacket(QUICPacketHeader *header, ats_unique_buf unprotected_payload, size_t unprotected_payload_len, QUICPacketNumber base_packet_number)
{
- this->_size = len;
- this->_header = QUICPacketHeader::load(reinterpret_cast<const uint8_t *>(buf.release()), len, base_packet_number);
+ this->_size = unprotected_payload_len;
+ this->_header = header;
+ this->_unprotected_payload = std::move(unprotected_payload);
+ this->_unprotected_payload_len = unprotected_payload_len;
}
QUICPacket::QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number,
@@ -577,7 +585,6 @@ QUICPacket::header_size() const
uint16_t
QUICPacket::payload_size() const
{
- // FIXME Protected packets may / may not contain something at the end
if (this->type() == QUICPacketType::STATELESS_RESET) {
return this->_size - this->_header->length();
} else if (this->type() != QUICPacketType::ZERO_RTT_PROTECTED && this->type() != QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0 &&
@@ -608,8 +615,8 @@ QUICPacket::store(uint8_t *buf, size_t *len) const
memcpy(buf + *len, this->payload(), this->payload_size());
*len += this->payload_size();
- fnv1a(buf, *len, buf + *len);
- *len += FNV1A_HASH_LEN;
+ // fnv1a(buf, *len, buf + *len);
+ // *len += FNV1A_HASH_LEN;
} else {
ink_assert(this->_protected_payload);
memcpy(buf + *len, this->_protected_payload.get(), this->_protected_payload_size);
@@ -623,14 +630,6 @@ QUICPacket::store_header(uint8_t *buf, size_t *len) const
this->_header->store(buf, len);
}
-bool
-QUICPacket::has_valid_fnv1a_hash() const
-{
- uint8_t hash[FNV1A_HASH_LEN];
- fnv1a(reinterpret_cast<const uint8_t *>(this->_header->buf()), this->size() - FNV1A_HASH_LEN, hash);
- return memcmp(this->_header->buf() + this->size() - FNV1A_HASH_LEN, hash, 8) == 0;
-}
-
void
QUICPacket::set_protected_payload(ats_unique_buf cipher_txt, size_t cipher_txt_len)
{
@@ -691,10 +690,55 @@ QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, si
// QUICPacketFactory
//
QUICPacketUPtr
-QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number)
-{
- QUICPacket *packet = quicPacketAllocator.alloc();
- new (packet) QUICPacket(std::move(buf), len, base_packet_number);
+QUICPacketFactory::create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result)
+{
+ size_t max_plain_txt_len = 2048;
+ ats_unique_buf plain_txt = ats_unique_malloc(max_plain_txt_len);
+ size_t plain_txt_len = 0;
+
+ QUICPacketHeader *header = QUICPacketHeader::load(buf.release(), len, base_packet_number);
+
+ switch (header->type()) {
+ case QUICPacketType::VERSION_NEGOTIATION:
+ case QUICPacketType::STATELESS_RESET:
+ // These packets are unprotected. Just copy the payload
+ memcpy(plain_txt.get(), header->payload(), header->payload_size());
+ plain_txt_len = header->payload_size();
+ result = QUICPacketCreationResult::SUCCESS;
+ break;
+ case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_0:
+ case QUICPacketType::ONE_RTT_PROTECTED_KEY_PHASE_1:
+ if (this->_crypto->is_handshake_finished()) {
+ if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(),
+ header->packet_number(), header->buf(), header->length(), header->key_phase())) {
+ result = QUICPacketCreationResult::SUCCESS;
+ } else {
+ result = QUICPacketCreationResult::FAILED;
+ }
+ } else {
+ result = QUICPacketCreationResult::NOT_READY;
+ }
+ break;
+ case QUICPacketType::CLIENT_INITIAL:
+ case QUICPacketType::CLIENT_CLEARTEXT:
+ case QUICPacketType::SERVER_CLEARTEXT:
+ if (this->_crypto->decrypt(plain_txt.get(), plain_txt_len, max_plain_txt_len, header->payload(), header->payload_size(),
+ header->packet_number(), header->buf(), header->length(), QUICKeyPhase::CLEARTEXT)) {
+ result = QUICPacketCreationResult::SUCCESS;
+ } else {
+ result = QUICPacketCreationResult::FAILED;
+ }
+ default:
+ result = QUICPacketCreationResult::FAILED;
+ break;
+ }
+
+ QUICPacket *packet = nullptr;
+ if (result == QUICPacketCreationResult::SUCCESS) {
+ packet = quicPacketAllocator.alloc();
+ new (packet) QUICPacket(header, std::move(plain_txt), plain_txt_len, base_packet_number);
+ }
+
return QUICPacketUPtr(packet, &QUICPacketDeleter::delete_packet);
}
diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h
index 987b90e..1874447 100644
--- a/iocore/net/quic/QUICPacket.h
+++ b/iocore/net/quic/QUICPacket.h
@@ -39,13 +39,14 @@
class QUICPacketHeader
{
public:
- QUICPacketHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : _buf(buf), _base_packet_number(base) {}
+ QUICPacketHeader(const uint8_t *buf, size_t len, QUICPacketNumber base) : _buf(buf), _buf_len(len), _base_packet_number(base) {}
const uint8_t *buf();
virtual QUICPacketType type() const = 0;
virtual QUICConnectionId connection_id() const = 0;
virtual QUICPacketNumber packet_number() const = 0;
virtual QUICVersion version() const = 0;
virtual const uint8_t *payload() const = 0;
+ uint16_t payload_size() const;
virtual QUICKeyPhase key_phase() const = 0;
virtual uint16_t length() const = 0;
virtual void store(uint8_t *buf, size_t *len) const = 0;
@@ -65,9 +66,10 @@ protected:
QUICPacketHeader(){};
const uint8_t *_buf = nullptr;
+ size_t _buf_len = 0;
ats_unique_buf _payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); });
QUICPacketType _type = QUICPacketType::UNINITIALIZED;
- QUICKeyPhase _key_phase = QUICKeyPhase::PHASE_UNINITIALIZED;
+ QUICKeyPhase _key_phase = QUICKeyPhase::CLEARTEXT;
QUICConnectionId _connection_id = 0;
QUICPacketNumber _packet_number = 0;
QUICPacketNumber _base_packet_number = 0;
@@ -129,7 +131,7 @@ class QUICPacket
{
public:
QUICPacket(){};
- QUICPacket(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number);
+ QUICPacket(QUICPacketHeader *header, ats_unique_buf unprotected_payload, size_t unprotected_payload_len, QUICPacketNumber base_packet_number);
QUICPacket(QUICPacketType type, QUICConnectionId connection_id, QUICPacketNumber packet_number,
QUICPacketNumber base_packet_number, QUICVersion version, ats_unique_buf payload, size_t len, bool retransmittable);
QUICPacket(QUICPacketType type, QUICPacketNumber packet_number, QUICPacketNumber base_packet_number, ats_unique_buf payload,
@@ -152,7 +154,6 @@ public:
uint16_t payload_size() const;
void store(uint8_t *buf, size_t *len) const;
void store_header(uint8_t *buf, size_t *len) const;
- bool has_valid_fnv1a_hash() const;
QUICKeyPhase key_phase() const;
static uint8_t calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base);
static bool encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len);
@@ -164,6 +165,8 @@ private:
ats_unique_buf _protected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); });
size_t _size = 0;
size_t _protected_payload_size = 0;
+ ats_unique_buf _unprotected_payload = ats_unique_buf(nullptr, [](void *p) { ats_free(p); });
+ size_t _unprotected_payload_len = 0;
QUICPacketHeader *_header;
bool _is_retransmittable = false;
};
@@ -205,7 +208,7 @@ public:
class QUICPacketFactory
{
public:
- static QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number);
+ QUICPacketUPtr create(ats_unique_buf buf, size_t len, QUICPacketNumber base_packet_number, QUICPacketCreationResult &result);
QUICPacketUPtr create_version_negotiation_packet(const QUICPacket *packet_sent_by_client, QUICPacketNumber base_packet_number);
QUICPacketUPtr create_server_cleartext_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number,
ats_unique_buf payload, size_t len, bool retransmittable);
@@ -222,5 +225,3 @@ private:
QUICCrypto *_crypto = nullptr;
QUICPacketNumberGenerator _packet_number_generator;
};
-
-void fnv1a(const uint8_t *data, size_t len, uint8_t *hash);
diff --git a/iocore/net/quic/QUICTypes.cc b/iocore/net/quic/QUICTypes.cc
index 7427d6a..27fa72c 100644
--- a/iocore/net/quic/QUICTypes.cc
+++ b/iocore/net/quic/QUICTypes.cc
@@ -147,20 +147,6 @@ QUICTypeUtil::write_uint_as_nbytes(uint64_t value, uint8_t n, uint8_t *buf, size
*len = n;
}
-void
-fnv1a(const uint8_t *data, size_t len, uint8_t *hash)
-{
- uint64_t h = 0xcbf29ce484222325ULL;
- uint64_t prime = 0x100000001b3ULL;
- size_t n;
-
- for (size_t i = 0; i < len; ++i) {
- h ^= data[i];
- h *= prime;
- }
- return QUICTypeUtil::write_uint_as_nbytes(h, 8, hash, &n);
-}
-
uint16_t
QUICError::code()
{
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index 2e78939..ee8dbbe 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -113,7 +113,13 @@ enum class QUICVersionNegotiationStatus {
enum class QUICKeyPhase : int {
PHASE_0 = 0,
PHASE_1,
- PHASE_UNINITIALIZED,
+ CLEARTEXT,
+};
+
+enum class QUICPacketCreationResult {
+ SUCCESS,
+ FAILED,
+ NOT_READY,
};
enum class QUICErrorClass {
diff --git a/iocore/net/quic/test/Makefile.am b/iocore/net/quic/test/Makefile.am
index 5b75729..f43d35d 100644
--- a/iocore/net/quic/test/Makefile.am
+++ b/iocore/net/quic/test/Makefile.am
@@ -26,6 +26,7 @@ check_PROGRAMS = \
test_QUICStream \
test_QUICStreamManager \
test_QUICTransportParameters \
+ test_QUICKeyGenerator \
test_QUICCrypto \
test_QUICLossDetector \
test_QUICTypeUtil \
@@ -50,8 +51,10 @@ AM_CPPFLAGS += \
@OPENSSL_INCLUDES@
if OPENSSL_IS_BORINGSSL
+QUICKeyGenerator_impl = ../QUICKeyGenerator_boringssl.cc
QUICCrypto_impl = ../QUICCrypto_boringssl.cc
else
+QUICKeyGenerator_impl = ../QUICKeyGenerator_openssl.cc
QUICCrypto_impl = ../QUICCrypto_openssl.cc
endif
@@ -317,6 +320,29 @@ test_QUICTransportParameters_LDADD = \
$(top_builddir)/iocore/eventsystem/libinkevent.a
#
+# test_QUICKeyGenerator
+#
+test_QUICKeyGenerator_CPPFLAGS = \
+ $(AM_CPPFLAGS)
+
+test_QUICKeyGenerator_LDFLAGS = \
+ @AM_LDFLAGS@ \
+ @OPENSSL_LDFLAGS@
+
+test_QUICKeyGenerator_LDADD = \
+ @OPENSSL_LIBS@ \
+ $(top_builddir)/lib/ts/libtsutil.la \
+ $(top_builddir)/proxy/shared/libUglyLogStubs.a \
+ $(top_builddir)/iocore/eventsystem/libinkevent.a
+
+test_QUICKeyGenerator_SOURCES = \
+ main.cc \
+ test_QUICKeyGenerator.cc \
+ ../QUICKeyGenerator.cc \
+ $(QUICKeyGenerator_impl) \
+ ../QUICTypes.cc
+
+#
# test_QUICCrypto
#
test_QUICCrypto_CPPFLAGS = \
diff --git a/iocore/net/quic/test/test_QUICKeyGenerator.cc b/iocore/net/quic/test/test_QUICKeyGenerator.cc
new file mode 100644
index 0000000..cdae44a2
--- /dev/null
+++ b/iocore/net/quic/test/test_QUICKeyGenerator.cc
@@ -0,0 +1,107 @@
+/** @file
+ *
+ * A brief file description
+ *
+ * @section license License
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "catch.hpp"
+
+#include <cstring>
+
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/base.h>
+#endif
+
+#include <openssl/ssl.h>
+
+#include "Mock.h"
+#include "QUICKeyGenerator.h"
+
+void
+print_hex(const uint8_t *v, size_t len)
+{
+ for (size_t i = 0; i < len; i++) {
+ std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast<uint32_t>(v[i]) << " ";
+
+ if (i != 0 && (i + 1) % 32 == 0 && i != len - 1) {
+ std::cout << std::endl;
+ }
+ }
+
+ std::cout << std::endl;
+
+ return;
+}
+
+TEST_CASE("QUICKeyGenerator", "[quic]")
+{
+
+ SECTION("CLIENT Cleartext")
+ {
+ QUICKeyGenerator keygen(QUICKeyGenerator::Context::CLIENT);
+
+ QUICConnectionId cid = 0x8394c8f03e515708;
+ uint8_t expected_client_key[] = {
+ 0x2e, 0xbd, 0x78, 0x00, 0xdb, 0xed, 0x20, 0x10,
+ 0xe5, 0xa2, 0x1c, 0x4a, 0xd2, 0x4b, 0x4e, 0xc3
+ };
+ uint8_t expected_client_iv[] = {
+ 0x55, 0x44, 0x0d, 0x5f, 0xf7, 0x50, 0x3d, 0xe4,
+ 0x99, 0x7b, 0xfd, 0x6b
+ };
+ uint8_t actual_client_key[128];
+ size_t actual_client_key_len = sizeof(actual_client_key);
+ uint8_t actual_client_iv[128];
+ size_t actual_client_iv_len = sizeof(actual_client_iv);
+
+ keygen.generate(cid, actual_client_key, &actual_client_key_len, actual_client_iv, &actual_client_iv_len);
+
+ CHECK(actual_client_key_len == sizeof(expected_client_key));
+ CHECK(memcmp(actual_client_key, expected_client_key, sizeof(expected_client_key)) == 0);
+ CHECK(actual_client_iv_len == sizeof(expected_client_iv));
+ CHECK(memcmp(actual_client_iv, expected_client_iv, sizeof(expected_client_iv)) == 0);
+ }
+
+ SECTION("SERVER Cleartext")
+ {
+ QUICKeyGenerator keygen(QUICKeyGenerator::Context::SERVER);
+
+ QUICConnectionId cid = 0x8394c8f03e515708;
+ uint8_t expected_server_key[] = {
+ 0xc8, 0xea, 0x1b, 0xc1, 0x71, 0xe5, 0x2b, 0xae,
+ 0x71, 0xfb, 0x78, 0x39, 0x52, 0xc7, 0xb8, 0xfc
+ };
+ uint8_t expected_server_iv[] = {
+ 0x57, 0x82, 0x3b, 0x85, 0x2c, 0x7e, 0xf9, 0xe3,
+ 0x80, 0x2b, 0x69, 0x0b
+ };
+ uint8_t actual_server_key[128];
+ size_t actual_server_key_len = sizeof(actual_server_key);
+ uint8_t actual_server_iv[128];
+ size_t actual_server_iv_len = sizeof(actual_server_iv);
+
+ keygen.generate(cid, actual_server_key, &actual_server_key_len, actual_server_iv, &actual_server_iv_len);
+
+ CHECK(actual_server_key_len == sizeof(expected_server_key));
+ CHECK(memcmp(actual_server_key, expected_server_key, sizeof(expected_server_key)) == 0);
+ CHECK(actual_server_iv_len == sizeof(expected_server_iv));
+ CHECK(memcmp(actual_server_iv, expected_server_iv, sizeof(expected_server_iv)) == 0);
+ }
+}
diff --git a/lib/ts/HKDF.cc b/lib/ts/HKDF.cc
index fe01117..6da55c4 100644
--- a/lib/ts/HKDF.cc
+++ b/lib/ts/HKDF.cc
@@ -26,18 +26,19 @@
int
HKDF::expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len,
- uint16_t length)
+ const char *hash_value, size_t hash_value_len, uint16_t length)
{
// Create HKDF label
uint8_t hkdf_label[512]; // 2 + 255 + 255
+ int hkdf_label_len = 0;
// Length
hkdf_label[0] = (length >> 8) & 0xFF;
hkdf_label[1] = length & 0xFF;
+ hkdf_label_len += 2;
// "tls13 " + Label
- int hkdf_label_len = sprintf(reinterpret_cast<char *>(hkdf_label + 2), "tls13 %.*s", static_cast<int>(label_len), label);
- // Always 0
- hkdf_label[hkdf_label_len] = 0;
- ++hkdf_label_len;
+ hkdf_label_len += sprintf(reinterpret_cast<char *>(hkdf_label + hkdf_label_len), "%ctls13 %.*s", static_cast<int>(6 + label_len), static_cast<int>(label_len), label);
+ // Hash Value
+ hkdf_label_len += sprintf(reinterpret_cast<char *>(hkdf_label + hkdf_label_len), "%c%.*s", static_cast<int>(hash_value_len), static_cast<int>(hash_value_len), hash_value);
this->expand(dst, dst_len, secret, secret_len, hkdf_label, hkdf_label_len, length);
return 1;
diff --git a/lib/ts/HKDF.h b/lib/ts/HKDF.h
index e659ada..2905299 100644
--- a/lib/ts/HKDF.h
+++ b/lib/ts/HKDF.h
@@ -40,7 +40,7 @@ public:
// This function is technically a part of TLS 1.3
int expand_label(uint8_t *dst, size_t *dst_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len,
- uint16_t length);
+ const char *hash_value, size_t hash_value_len, uint16_t length);
private:
const EVP_MD *_digest = nullptr;
diff --git a/lib/ts/HKDF_openssl.cc b/lib/ts/HKDF_openssl.cc
index af0e87f..d8ff3e4 100644
--- a/lib/ts/HKDF_openssl.cc
+++ b/lib/ts/HKDF_openssl.cc
@@ -25,12 +25,16 @@
HKDF::HKDF(const EVP_MD *digest) : _digest(digest)
{
- this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
+ // XXX We cannot reuse pctx now due to a bug in OpenSSL
+ // this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
}
int
HKDF::extract(uint8_t *dst, size_t *dst_len, const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len)
{
+ // XXX See comments in the constructor
+ this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
+
if (EVP_PKEY_derive_init(this->_pctx) != 1) {
return -1;
}
@@ -49,13 +53,23 @@ HKDF::extract(uint8_t *dst, size_t *dst_len, const uint8_t *salt, size_t salt_le
if (EVP_PKEY_derive(this->_pctx, dst, dst_len) != 1) {
return -6;
}
+
+ /// XXX See comments in constuctor.
+ EVP_PKEY_CTX_free(this->_pctx);
+
return 1;
+
+ // XXX See comments in the constructor
+ EVP_PKEY_CTX_free(this->_pctx);
}
int
HKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len,
uint16_t length)
{
+ // XXX See comments in the constructor
+ this->_pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
+
if (EVP_PKEY_derive_init(this->_pctx) != 1) {
return -1;
}
@@ -76,5 +90,8 @@ HKDF::expand(uint8_t *dst, size_t *dst_len, const uint8_t *prk, size_t prk_len,
return -7;
}
+ // XXX See comments in the constructor
+ EVP_PKEY_CTX_free(this->_pctx);
+
return 1;
}
--
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].