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.
This commit is contained in:
Frédéric Lécaille 2021-11-30 10:59:37 +01:00
parent 39484de813
commit 40df78f116
4 changed files with 82 additions and 0 deletions

View 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. */

View 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 */

View 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;

View 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];