diff --git a/include/haproxy/quic_tls-t.h b/include/haproxy/quic_tls-t.h index 237b8c6113..73320f7d20 100644 --- a/include/haproxy/quic_tls-t.h +++ b/include/haproxy/quic_tls-t.h @@ -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. */ diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h index 5a736110be..47946cc22d 100644 --- a/include/haproxy/quic_tls.h +++ b/include/haproxy/quic_tls.h @@ -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 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 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 + * 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 f5ecae108f..cd2a2c8043 100644 --- a/include/haproxy/xprt_quic-t.h +++ b/include/haproxy/xprt_quic-t.h @@ -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; diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 2f23eae4d4..b1e48ebb9f 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -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];