MINOR: quic: Add structures to maintain key phase information
When running Key Update process, we must maintain much information
especially when the key phase bit has been toggled by the peer as
it is possible that it is due to late packets. This patch adds
quic_tls_kp new structure to do so. They are used to store
previous and next secrets, keys and IVs associated to the previous
and next RX key phase. We also need the next TX key phase information
to be able to encrypt packets for the next key phase.
diff --git a/include/haproxy/quic_tls-t.h b/include/haproxy/quic_tls-t.h
index 237b8c6..73320f7 100644
--- a/include/haproxy/quic_tls-t.h
+++ b/include/haproxy/quic_tls-t.h
@@ -91,6 +91,20 @@
extern unsigned char initial_salt[20];
+#define QUIC_FL_TLS_KP_BIT_SET (1 << 0)
+/* Key phase used for Key Update */
+struct quic_tls_kp {
+ unsigned char *secret;
+ size_t secretlen;
+ unsigned char *iv;
+ size_t ivlen;
+ unsigned char *key;
+ size_t keylen;
+ uint64_t count;
+ int64_t pn;
+ unsigned char flags;
+};
+
/* Flag to be used when TLS secrets have been set. */
#define QUIC_FL_TLS_SECRETS_SET (1 << 0)
/* Flag to be used when TLS secrets have been discarded. */
diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h
index 5a73611..47946cc 100644
--- a/include/haproxy/quic_tls.h
+++ b/include/haproxy/quic_tls.h
@@ -520,6 +520,65 @@
return 0;
}
+/* Release the memory allocated for all the key update key phase
+ * structures for <qc> QUIC connection.
+ * Always succeeds.
+ */
+static inline void quic_tls_ku_free(struct quic_conn *qc)
+{
+ pool_free(pool_head_quic_tls_secret, qc->ku.prv_rx.secret);
+ pool_free(pool_head_quic_tls_iv, qc->ku.prv_rx.iv);
+ pool_free(pool_head_quic_tls_key, qc->ku.prv_rx.key);
+ pool_free(pool_head_quic_tls_secret, qc->ku.nxt_rx.secret);
+ pool_free(pool_head_quic_tls_iv, qc->ku.nxt_rx.iv);
+ pool_free(pool_head_quic_tls_key, qc->ku.nxt_rx.key);
+ pool_free(pool_head_quic_tls_secret, qc->ku.nxt_tx.secret);
+ pool_free(pool_head_quic_tls_iv, qc->ku.nxt_tx.iv);
+ pool_free(pool_head_quic_tls_key, qc->ku.nxt_tx.key);
+}
+
+/* Initialize <kp> key update secrets, allocating the required memory.
+ * Return 1 if all the secrets could be allocated, 0 if not.
+ * This is the responsability of the caller to release the memory
+ * allocated by this function in case of failure.
+ */
+static inline int quic_tls_kp_init(struct quic_tls_kp *kp)
+{
+ kp->count = 0;
+ kp->pn = 0;
+ kp->flags = 0;
+ kp->secret = pool_alloc(pool_head_quic_tls_secret);
+ kp->secretlen = QUIC_TLS_SECRET_LEN;
+ kp->iv = pool_alloc(pool_head_quic_tls_iv);
+ kp->ivlen = QUIC_TLS_IV_LEN;
+ kp->key = pool_alloc(pool_head_quic_tls_key);
+ kp->keylen = QUIC_TLS_KEY_LEN;
+
+ return kp->secret && kp->iv && kp->key;
+}
+
+/* Initialize all the key update key phase structures for <qc>
+ * QUIC connection, allocating the required memory.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static inline int quic_tls_ku_init(struct quic_conn *qc)
+{
+ struct quic_tls_kp *prv_rx = &qc->ku.prv_rx;
+ struct quic_tls_kp *nxt_rx = &qc->ku.nxt_rx;
+ struct quic_tls_kp *nxt_tx = &qc->ku.nxt_tx;
+
+ if (!quic_tls_kp_init(prv_rx) ||
+ !quic_tls_kp_init(nxt_rx) ||
+ !quic_tls_kp_init(nxt_tx))
+ goto err;
+
+ return 1;
+
+ err:
+ quic_tls_ku_free(qc);
+ return 0;
+}
+
#endif /* USE_QUIC */
#endif /* _PROTO_QUIC_TLS_H */
diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h
index f5ecae1..cd2a2c8 100644
--- a/include/haproxy/xprt_quic-t.h
+++ b/include/haproxy/xprt_quic-t.h
@@ -689,6 +689,11 @@
__decl_thread(HA_RWLOCK_T buf_rwlock);
struct list pkt_list;
} rx;
+ struct {
+ struct quic_tls_kp prv_rx;
+ struct quic_tls_kp nxt_rx;
+ struct quic_tls_kp nxt_tx;
+ } ku;
unsigned int max_ack_delay;
struct quic_path paths[1];
struct quic_path *path;
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index 2f23eae..b1e48eb 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -3205,6 +3205,10 @@
qc->rx.buf = b_make(buf_area, QUIC_CONN_RX_BUFSZ, 0, 0);
HA_RWLOCK_INIT(&qc->rx.buf_rwlock);
LIST_INIT(&qc->rx.pkt_list);
+ if (!quic_tls_ku_init(qc)) {
+ TRACE_PROTO("Key update initialization failed", QUIC_EV_CONN_INIT);
+ goto err;
+ }
/* XXX TO DO: Only one path at this time. */
qc->path = &qc->paths[0];