]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: Add structures to maintain key phase information
authorFrédéric Lécaille <flecaille@haproxy.com>
Tue, 30 Nov 2021 09:59:37 +0000 (10:59 +0100)
committerFrédéric Lécaille <flecaille@haproxy.com>
Tue, 30 Nov 2021 10:51:12 +0000 (11:51 +0100)
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.

include/haproxy/quic_tls-t.h
include/haproxy/quic_tls.h
include/haproxy/xprt_quic-t.h
src/xprt_quic.c

index 237b8c6113db193bcd0cbf063011b21a4f8e26a3..73320f7d2037bcf35d8c0c604ed91765a1cf13b8 100644 (file)
@@ -91,6 +91,20 @@ enum quic_tls_pktns {
 
 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. */
index 5a736110be75d750fd8844f22e16ece74bf914d7..47946cc22d5b5fdad6cbeca8f7ed83339e73d851 100644 (file)
@@ -520,6 +520,65 @@ static inline int qc_new_isecs(struct quic_conn *qc,
        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 */
 
index f5ecae108f6e4d1752d3ab9308a7aab43c116cc3..cd2a2c804329aaeb6f708a5e03de66da79193b15 100644 (file)
@@ -689,6 +689,11 @@ struct quic_conn {
                __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;
index 2f23eae4d4f536e28b909715cfd557f9d1bb695f..b1e48ebb9fce6515766022e1209ad87a92579dc7 100644 (file)
@@ -3205,6 +3205,10 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
        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];