MINOR: quic: Add traces about QUIC TLS key update

Dump the secret used to derive the next one during a key update initiated by the
client and dump the resulted new secret and the new key and iv to be used to
decryption Application level packets.

Also add a trace when the key update is supposed to be initiated on haproxy side.

This has already helped in diagnosing an issue evealed by the key update interop
test with xquic as client.

Must be backported to 2.7.
This commit is contained in:
Frédéric Lécaille 2023-02-23 20:38:23 +01:00
parent 720277843b
commit 51a7caf921
4 changed files with 75 additions and 12 deletions

View File

@ -225,6 +225,7 @@ enum quic_pkt_type {
#define QUIC_EV_CONN_ELEVELSEL (1ULL << 47)
#define QUIC_EV_CONN_RCV (1ULL << 48)
#define QUIC_EV_CONN_KILL (1ULL << 49)
#define QUIC_EV_CONN_KP (1ULL << 50)
/* Similar to kernel min()/max() definitions. */
#define QUIC_MIN(a, b) ({ \

View File

@ -31,6 +31,8 @@
void quic_tls_keys_hexdump(struct buffer *buf,
const struct quic_tls_secrets *secs);
void quic_tls_kp_keys_hexdump(struct buffer *buf,
const struct quic_tls_kp *kp);
void quic_tls_secret_hexdump(struct buffer *buf,
const unsigned char *secret, size_t secret_len);

View File

@ -253,6 +253,16 @@ static inline void enc_debug_info_init(struct enc_debug_info *edi,
edi->pn = pn;
}
/* Used only for QUIC TLS key phase traces */
struct quic_kp_trace {
const unsigned char *rx_sec;
size_t rx_seclen;
const struct quic_tls_kp *rx;
const unsigned char *tx_sec;
size_t tx_seclen;
const struct quic_tls_kp *tx;
};
/* Trace callback for QUIC.
* These traces always expect that arg1, if non-null, is of type connection.
*/
@ -310,6 +320,27 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace
quic_tls_secret_hexdump(&trace_buf, tx_sec, 32);
quic_tls_keys_hexdump(&trace_buf, &tls_ctx->tx);
}
if ((mask & QUIC_EV_CONN_KP) && qc) {
/* Initial read & write secrets. */
const struct quic_kp_trace *kp = a2;
if (kp) {
if (kp->rx) {
chunk_appendf(&trace_buf, "\n RX kp");
if (kp->rx_sec)
quic_tls_secret_hexdump(&trace_buf, kp->rx_sec, kp->rx_seclen);
quic_tls_kp_keys_hexdump(&trace_buf, kp->rx);
}
if (kp->tx) {
chunk_appendf(&trace_buf, "\n TX kp");
if (kp->tx_sec)
quic_tls_secret_hexdump(&trace_buf, kp->tx_sec, kp->tx_seclen);
quic_tls_kp_keys_hexdump(&trace_buf, kp->tx);
}
}
}
if (mask & (QUIC_EV_CONN_RSEC|QUIC_EV_CONN_RWSEC)) {
const enum ssl_encryption_level_t *level = a2;
@ -819,25 +850,34 @@ static inline void qc_set_timer(struct quic_conn *qc)
static int quic_tls_key_update(struct quic_conn *qc)
{
struct quic_tls_ctx *tls_ctx = &qc->els[QUIC_TLS_ENC_LEVEL_APP].tls_ctx;
struct quic_tls_secrets *rx, *tx;
struct quic_tls_secrets *rx = &tls_ctx->rx;
struct quic_tls_secrets *tx = &tls_ctx->tx;
/* Used only for the traces */
struct quic_kp_trace kp_trace = {
.rx_sec = rx->secret,
.rx_seclen = rx->secretlen,
.tx_sec = tx->secret,
.tx_seclen = tx->secretlen,
};
/* The next key phase secrets to be derived */
struct quic_tls_kp *nxt_rx = &qc->ku.nxt_rx;
struct quic_tls_kp *nxt_tx = &qc->ku.nxt_tx;
const struct quic_version *ver =
qc->negotiated_version ? qc->negotiated_version : qc->original_version;
int ret = 0;
TRACE_ENTER(QUIC_EV_CONN_RWSEC, qc);
TRACE_ENTER(QUIC_EV_CONN_KP, qc);
tls_ctx = &qc->els[QUIC_TLS_ENC_LEVEL_APP].tls_ctx;
rx = &tls_ctx->rx;
tx = &tls_ctx->tx;
nxt_rx = &qc->ku.nxt_rx;
nxt_tx = &qc->ku.nxt_tx;
TRACE_PRINTF(TRACE_LEVEL_DEVELOPER, QUIC_EV_CONN_SPPKTS, qc, 0, 0, 0,
"nxt_rx->secretlen=%llu rx->secretlen=%llu",
(ull)nxt_rx->secretlen, (ull)rx->secretlen);
/* Prepare new RX secrets */
if (!quic_tls_sec_update(rx->md, ver, nxt_rx->secret, nxt_rx->secretlen,
rx->secret, rx->secretlen)) {
TRACE_ERROR("New RX secret update failed", QUIC_EV_CONN_RWSEC, qc);
TRACE_ERROR("New RX secret update failed", QUIC_EV_CONN_KP, qc);
goto leave;
}
@ -845,14 +885,15 @@ static int quic_tls_key_update(struct quic_conn *qc)
nxt_rx->key, nxt_rx->keylen,
nxt_rx->iv, nxt_rx->ivlen, NULL, 0,
nxt_rx->secret, nxt_rx->secretlen)) {
TRACE_ERROR("New RX key derivation failed", QUIC_EV_CONN_RWSEC, qc);
TRACE_ERROR("New RX key derivation failed", QUIC_EV_CONN_KP, qc);
goto leave;
}
kp_trace.rx = nxt_rx;
/* Prepare new TX secrets */
if (!quic_tls_sec_update(tx->md, ver, nxt_tx->secret, nxt_tx->secretlen,
tx->secret, tx->secretlen)) {
TRACE_ERROR("New TX secret update failed", QUIC_EV_CONN_RWSEC, qc);
TRACE_ERROR("New TX secret update failed", QUIC_EV_CONN_KP, qc);
goto leave;
}
@ -860,17 +901,18 @@ static int quic_tls_key_update(struct quic_conn *qc)
nxt_tx->key, nxt_tx->keylen,
nxt_tx->iv, nxt_tx->ivlen, NULL, 0,
nxt_tx->secret, nxt_tx->secretlen)) {
TRACE_ERROR("New TX key derivation failed", QUIC_EV_CONN_RWSEC, qc);
TRACE_ERROR("New TX key derivation failed", QUIC_EV_CONN_KP, qc);
goto leave;
}
kp_trace.tx = nxt_tx;
if (nxt_rx->ctx) {
EVP_CIPHER_CTX_free(nxt_rx->ctx);
nxt_rx->ctx = NULL;
}
if (!quic_tls_rx_ctx_init(&nxt_rx->ctx, tls_ctx->rx.aead, nxt_rx->key)) {
TRACE_ERROR("could not initial RX TLS cipher context", QUIC_EV_CONN_RWSEC, qc);
TRACE_ERROR("could not initial RX TLS cipher context", QUIC_EV_CONN_KP, qc);
goto leave;
}
@ -880,13 +922,13 @@ static int quic_tls_key_update(struct quic_conn *qc)
}
if (!quic_tls_rx_ctx_init(&nxt_tx->ctx, tls_ctx->tx.aead, nxt_tx->key)) {
TRACE_ERROR("could not initial RX TLS cipher context", QUIC_EV_CONN_RWSEC, qc);
TRACE_ERROR("could not initial RX TLS cipher context", QUIC_EV_CONN_KP, qc);
goto leave;
}
ret = 1;
leave:
TRACE_LEAVE(QUIC_EV_CONN_RWSEC, qc);
TRACE_LEAVE(QUIC_EV_CONN_KP, qc, &kp_trace);
return ret;
}
@ -1543,6 +1585,7 @@ static int qc_pkt_decrypt(struct quic_conn *qc, struct quic_enc_level *qel,
}
else if (pkt->pn > qel->pktns->rx.largest_pn) {
/* Next key phase */
TRACE_PROTO("Key phase changed", QUIC_EV_CONN_RXPKT, qc);
kp_changed = 1;
rx_ctx = qc->ku.nxt_rx.ctx;
rx_iv = qc->ku.nxt_rx.iv;

View File

@ -57,6 +57,23 @@ void quic_tls_keys_hexdump(struct buffer *buf,
chunk_appendf(buf, "%02x", secs->hp_key[i]);
}
/* Dump the RX/TX secrets of <kp> QUIC TLS key phase */
void quic_tls_kp_keys_hexdump(struct buffer *buf,
const struct quic_tls_kp *kp)
{
int i;
chunk_appendf(buf, "\n secret=");
for (i = 0; i < kp->secretlen; i++)
chunk_appendf(buf, "%02x", kp->secret[i]);
chunk_appendf(buf, "\n key=");
for (i = 0; i < kp->keylen; i++)
chunk_appendf(buf, "%02x", kp->key[i]);
chunk_appendf(buf, "\n iv=");
for (i = 0; i < kp->ivlen; i++)
chunk_appendf(buf, "%02x", kp->iv[i]);
}
/* Dump <secret> TLS secret. */
void quic_tls_secret_hexdump(struct buffer *buf,
const unsigned char *secret, size_t secret_len)