MEDIUM: quic: separate path for rx and tx with set_encryption_secrets
With quicTLS the set_encruption_secrets callback is always called with
the read_secret and the write_secret.
However this is not the case with libreSSL, which uses the
set_read_secret()/set_write_secret() mecanism. It still provides the
set_encryption_secrets() callback, which is called with a NULL
parameter for the write_secret during the read, and for the read_secret
during the write.
The exchange key was not designed in haproxy to be called separately for
read and write, so this patch allow calls with read or write key to
NULL.
diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h
index 02e155d..df836d5 100644
--- a/include/haproxy/quic_tls.h
+++ b/include/haproxy/quic_tls.h
@@ -420,14 +420,24 @@
*/
static inline int quic_tls_ctx_keys_alloc(struct quic_tls_ctx *ctx)
{
+ if (ctx->rx.key)
+ goto write;
+
if (!(ctx->rx.iv = pool_alloc(pool_head_quic_tls_iv)) ||
- !(ctx->rx.key = pool_alloc(pool_head_quic_tls_key)) ||
- !(ctx->tx.iv = pool_alloc(pool_head_quic_tls_iv)) ||
+ !(ctx->rx.key = pool_alloc(pool_head_quic_tls_key)))
+ goto err;
+
+ write:
+ if (ctx->tx.key)
+ goto out;
+
+ if (!(ctx->tx.iv = pool_alloc(pool_head_quic_tls_iv)) ||
!(ctx->tx.key = pool_alloc(pool_head_quic_tls_key)))
goto err;
ctx->rx.ivlen = ctx->tx.ivlen = QUIC_TLS_IV_LEN;
ctx->rx.keylen = ctx->tx.keylen = QUIC_TLS_KEY_LEN;
+out:
return 1;
err:
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index 4cfd60f..042bd17 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -919,6 +919,9 @@
rx->md = tx->md = tls_md(cipher);
rx->hp = tx->hp = tls_hp(cipher);
+ if (!read_secret)
+ goto write;
+
if (!quic_tls_derive_keys(rx->aead, rx->hp, rx->md, ver, rx->key, rx->keylen,
rx->iv, rx->ivlen, rx->hp_key, sizeof rx->hp_key,
read_secret, secret_len)) {
@@ -945,6 +948,8 @@
quic_accept_push_qc(qc);
}
+write:
+
if (!write_secret)
goto out;
@@ -977,17 +982,17 @@
goto leave;
}
- memcpy(rx->secret, read_secret, secret_len);
- rx->secretlen = secret_len;
- memcpy(tx->secret, write_secret, secret_len);
- tx->secretlen = secret_len;
+ if (read_secret) {
+ memcpy(rx->secret, read_secret, secret_len);
+ rx->secretlen = secret_len;
+ }
+ if (write_secret) {
+ memcpy(tx->secret, write_secret, secret_len);
+ tx->secretlen = secret_len;
+ }
/* Initialize all the secret keys lengths */
prv_rx->secretlen = nxt_rx->secretlen = nxt_tx->secretlen = secret_len;
/* Prepare the next key update */
- if (!quic_tls_key_update(qc)) {
- // trace already emitted by function above
- goto leave;
- }
}
out:
@@ -2258,6 +2263,11 @@
else {
qc->state = QUIC_HS_ST_COMPLETE;
}
+
+ if (!quic_tls_key_update(qc)) {
+ TRACE_ERROR("quic_tls_key_update() failed", QUIC_EV_CONN_IO_CB, qc);
+ goto leave;
+ }
} else {
ssl_err = SSL_process_quic_post_handshake(ctx->ssl);
if (ssl_err != 1) {