diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index 3e1435aa8..eb05fd537 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -597,7 +597,17 @@ struct quic_conn { struct eb_root cids; /* tree of quic_connection_id - used to match a received packet DCID with a connection */ uint64_t next_cid_seq_num; - struct quic_enc_level els[QUIC_TLS_ENC_LEVEL_MAX]; + /* Initial encryption level */ + struct quic_enc_level *iel; + /* 0-RTT encryption level */ + struct quic_enc_level *eel; + /* Handshake encryption level */ + struct quic_enc_level *hel; + /* 1-RTT encryption level */ + struct quic_enc_level *ael; + /* List of allocated QUIC TLS encryption level */ + struct list qel_list; + struct quic_pktns *ipktns; struct quic_pktns *hpktns; struct quic_pktns *apktns; diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index 6f259900d..c48b043a7 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -54,6 +54,7 @@ int ssl_quic_initial_ctx(struct bind_conf *bind_conf); struct quic_cstream *quic_cstream_new(struct quic_conn *qc); void quic_cstream_free(struct quic_cstream *cs); void quic_free_arngs(struct quic_conn *qc, struct quic_arngs *arngs); +struct quic_cstream *quic_cstream_new(struct quic_conn *qc); /* Return the long packet type matching with version and */ static inline int quic_pkt_type(int type, uint32_t version) diff --git a/include/haproxy/quic_tls-t.h b/include/haproxy/quic_tls-t.h index b871c904f..71f8932fd 100644 --- a/include/haproxy/quic_tls-t.h +++ b/include/haproxy/quic_tls-t.h @@ -217,6 +217,7 @@ struct quic_tls_ctx { }; struct quic_enc_level { + struct list list; /* Encryption level, as defined by the TLS stack. */ enum ssl_encryption_level_t level; /* TLS encryption context (AEAD only) */ diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h index a7bebc668..0c6aff9be 100644 --- a/include/haproxy/quic_tls.h +++ b/include/haproxy/quic_tls.h @@ -31,13 +31,15 @@ #include void quic_pktns_release(struct quic_conn *qc, struct quic_pktns **pktns); +int qc_enc_level_alloc(struct quic_conn *qc, struct quic_pktns **pktns, + struct quic_enc_level **qel, enum ssl_encryption_level_t level); +void qc_enc_level_free(struct quic_conn *qc, struct quic_enc_level **qel); + void quic_tls_keys_hexdump(struct buffer *buf, const struct quic_tls_secrets *secs); void quic_tls_kp_keys_hexdump(struct buffer *buf, const struct quic_tls_kp *kp); -int quic_conn_enc_level_init(struct quic_conn *qc, - enum quic_tls_enc_level level); void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel); void quic_tls_secret_hexdump(struct buffer *buf, const unsigned char *secret, size_t secret_len); @@ -181,7 +183,10 @@ static inline struct quic_pktns **ssl_to_quic_pktns(struct quic_conn *qc, return NULL; } } -/* These following functions map TLS implementation encryption level to ours */ + +/* Map TLS stack encryption level to our internal QUIC TLS encryption level + * if succeded, or -1 if failed. + */ static inline enum quic_tls_enc_level ssl_to_quic_enc_level(enum ssl_encryption_level_t level) { switch (level) { @@ -198,6 +203,47 @@ static inline enum quic_tls_enc_level ssl_to_quic_enc_level(enum ssl_encryption_ } } +/* Return the address of the QUIC TLS encryption level associated to TLS + * stack encryption level and attached to QUIC connection if succeeded, or + * NULL if failed. + */ +static inline struct quic_enc_level **ssl_to_qel_addr(struct quic_conn *qc, + enum ssl_encryption_level_t level) +{ + switch (level) { + case ssl_encryption_initial: + return &qc->iel; + case ssl_encryption_early_data: + return &qc->eel; + case ssl_encryption_handshake: + return &qc->hel; + case ssl_encryption_application: + return &qc->ael; + default: + return NULL; + } +} + +/* Return the QUIC TLS encryption level associated to internal encryption + * level attached to QUIC connection if succeeded, or NULL if failed. + */ +static inline struct quic_enc_level *qc_quic_enc_level(const struct quic_conn *qc, + enum quic_tls_enc_level level) +{ + switch (level) { + case QUIC_TLS_ENC_LEVEL_INITIAL: + return qc->iel; + case QUIC_TLS_ENC_LEVEL_EARLY_DATA: + return qc->eel; + case QUIC_TLS_ENC_LEVEL_HANDSHAKE: + return qc->hel; + case QUIC_TLS_ENC_LEVEL_APP: + return qc->ael; + default: + return NULL; + } +} + /* These two following functions map our encryption level to the TLS implementation ones. */ static inline enum ssl_encryption_level_t quic_to_ssl_enc_level(enum quic_tls_enc_level level) { @@ -309,13 +355,13 @@ static inline char quic_enc_level_char(enum quic_tls_enc_level level) static inline char quic_enc_level_char_from_qel(const struct quic_enc_level *qel, const struct quic_conn *qc) { - if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]) + if (qel == qc->iel) return 'I'; - else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_EARLY_DATA]) + else if (qel == qc->eel) return 'E'; - else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]) + else if (qel == qc->hel) return 'H'; - else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_APP]) + else if (qel == qc->ael) return 'A'; return '-'; } @@ -499,17 +545,25 @@ static inline enum quic_tls_pktns quic_tls_pktns(enum quic_tls_enc_level level) } } -/* Reset all members of to default values. */ +/* Reset all members of to default values, ->hp_key[] excepted */ static inline void quic_tls_ctx_reset(struct quic_tls_ctx *ctx) { ctx->rx.ctx = NULL; + ctx->rx.aead = NULL; + ctx->rx.md = NULL; ctx->rx.hp_ctx = NULL; + ctx->rx.hp = NULL; + ctx->rx.secret = NULL; ctx->rx.iv = NULL; ctx->rx.key = NULL; ctx->rx.pn = 0; ctx->tx.ctx = NULL; + ctx->tx.aead = NULL; + ctx->tx.md = NULL; ctx->tx.hp_ctx = NULL; + ctx->tx.hp = NULL; + ctx->tx.secret = NULL; ctx->tx.iv = NULL; ctx->tx.key = NULL; /* Not used on the TX path. */ @@ -850,13 +904,13 @@ static inline int quic_tls_ku_init(struct quic_conn *qc) /* Return 1 if has RX secrets, 0 if not. */ static inline int quic_tls_has_rx_sec(const struct quic_enc_level *qel) { - return !!qel->tls_ctx.rx.key; + return qel && !!qel->tls_ctx.rx.key; } /* Return 1 if has TX secrets, 0 if not. */ static inline int quic_tls_has_tx_sec(const struct quic_enc_level *qel) { - return !!qel->tls_ctx.tx.key; + return qel && !!qel->tls_ctx.tx.key; } #endif /* USE_QUIC */ diff --git a/src/quic_conn.c b/src/quic_conn.c index a1d655085..f44945af2 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -227,9 +227,6 @@ DECLARE_STATIC_POOL(pool_head_quic_cstream, "quic_cstream", sizeof(struct quic_c DECLARE_POOL(pool_head_quic_frame, "quic_frame", sizeof(struct quic_frame)); DECLARE_STATIC_POOL(pool_head_quic_arng, "quic_arng", sizeof(struct quic_arng_node)); -static int quic_conn_enc_level_init(struct quic_conn *qc, - struct quic_pktns *pktns, - enum quic_tls_enc_level level); static struct quic_connection_id *new_quic_cid(struct eb_root *root, struct quic_conn *qc, const struct quic_cid *odcid, @@ -320,16 +317,15 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace } if ((mask & QUIC_EV_CONN_ISEC) && qc) { /* Initial read & write secrets. */ - enum quic_tls_enc_level level = QUIC_TLS_ENC_LEVEL_INITIAL; const unsigned char *rx_sec = a2; const unsigned char *tx_sec = a3; - tls_ctx = &qc->els[level].tls_ctx; - chunk_appendf(&trace_buf, "\n RX el=%c", quic_enc_level_char(level)); + tls_ctx = &qc->iel->tls_ctx; + chunk_appendf(&trace_buf, "\n RX el=I"); if (rx_sec) quic_tls_secret_hexdump(&trace_buf, rx_sec, 32); quic_tls_keys_hexdump(&trace_buf, &tls_ctx->rx); - chunk_appendf(&trace_buf, "\n TX el=%c", quic_enc_level_char(level)); + chunk_appendf(&trace_buf, "\n TX el=I"); if (tx_sec) quic_tls_secret_hexdump(&trace_buf, tx_sec, 32); quic_tls_keys_hexdump(&trace_buf, &tls_ctx->tx); @@ -360,12 +356,11 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace if (level) { enum quic_tls_enc_level lvl = ssl_to_quic_enc_level(*level); + struct quic_enc_level *qel = qc_quic_enc_level(qc, lvl); chunk_appendf(&trace_buf, "\n RX el=%c", quic_enc_level_char(lvl)); - if (quic_tls_has_rx_sec(&qc->els[lvl])) { - tls_ctx = &qc->els[lvl].tls_ctx; - quic_tls_keys_hexdump(&trace_buf, &tls_ctx->rx); - } + if (quic_tls_has_rx_sec(qel)) + quic_tls_keys_hexdump(&trace_buf, &qel->tls_ctx.rx); else chunk_appendf(&trace_buf, " (none)"); } @@ -376,11 +371,11 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace if (level) { enum quic_tls_enc_level lvl = ssl_to_quic_enc_level(*level); + struct quic_enc_level *qel = qc_quic_enc_level(qc, lvl); chunk_appendf(&trace_buf, "\n TX el=%c", quic_enc_level_char(lvl)); - if (quic_tls_has_tx_sec(&qc->els[lvl])) { - tls_ctx = &qc->els[lvl].tls_ctx; - quic_tls_keys_hexdump(&trace_buf, &tls_ctx->tx); + if (quic_tls_has_tx_sec(qel)) { + quic_tls_keys_hexdump(&trace_buf, &qel->tls_ctx.tx); } else chunk_appendf(&trace_buf, " (none)"); @@ -908,7 +903,7 @@ static inline void qc_set_timer(struct quic_conn *qc) */ static int quic_tls_key_update(struct quic_conn *qc) { - struct quic_tls_ctx *tls_ctx = &qc->els[QUIC_TLS_ENC_LEVEL_APP].tls_ctx; + struct quic_tls_ctx *tls_ctx = &qc->ael->tls_ctx; struct quic_tls_secrets *rx = &tls_ctx->rx; struct quic_tls_secrets *tx = &tls_ctx->tx; /* Used only for the traces */ @@ -998,7 +993,7 @@ static int quic_tls_key_update(struct quic_conn *qc) */ static void quic_tls_rotate_keys(struct quic_conn *qc) { - struct quic_tls_ctx *tls_ctx = &qc->els[QUIC_TLS_ENC_LEVEL_APP].tls_ctx; + struct quic_tls_ctx *tls_ctx = &qc->ael->tls_ctx; unsigned char *curr_secret, *curr_iv, *curr_key; EVP_CIPHER_CTX *curr_ctx; @@ -1050,30 +1045,26 @@ int ha_quic_set_encryption_secrets(SSL *ssl, enum ssl_encryption_level_t level, const uint8_t *read_secret, const uint8_t *write_secret, size_t secret_len) { + int ret = 0; struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); - enum quic_tls_enc_level tel = ssl_to_quic_enc_level(level); - struct quic_enc_level *qel = &qc->els[tel]; - struct quic_tls_ctx *tls_ctx = &qel->tls_ctx; + struct quic_enc_level **qel = ssl_to_qel_addr(qc, level); + struct quic_pktns **pktns = ssl_to_quic_pktns(qc, level); + struct quic_tls_ctx *tls_ctx; const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); struct quic_tls_secrets *rx = NULL, *tx = NULL; const struct quic_version *ver = qc->negotiated_version ? qc->negotiated_version : qc->original_version; - int ret = 0; TRACE_ENTER(QUIC_EV_CONN_RWSEC, qc); BUG_ON(secret_len > QUIC_TLS_SECRET_LEN); - if (!qel->pktns) { - struct quic_pktns **pktns = ssl_to_quic_pktns(qc, level); - - if (pktns == NULL || - !quic_pktns_init(qc, pktns) || - !quic_conn_enc_level_init(qc, *pktns, tel)) { - TRACE_ERROR("Could not initialized the packet number space", QUIC_EV_CONN_ADDDATA, qc); - goto leave; - } + if (!*qel && !qc_enc_level_alloc(qc, pktns, qel, level)) { + TRACE_PROTO("Could not allocated an encryption level", QUIC_EV_CONN_ADDDATA, qc); + goto out; } + tls_ctx = &(*qel)->tls_ctx; + if (qc->flags & QUIC_FL_CONN_TO_KILL) { TRACE_PROTO("connection to be killed", QUIC_EV_CONN_ADDDATA, qc); goto out; @@ -1366,12 +1357,11 @@ int quic_set_app_ops(struct quic_conn *qc, const unsigned char *alpn, size_t alp int ha_quic_add_handshake_data(SSL *ssl, enum ssl_encryption_level_t level, const uint8_t *data, size_t len) { - struct quic_conn *qc; - enum quic_tls_enc_level tel; - struct quic_enc_level *qel; int ret = 0; + struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); + struct quic_enc_level **qel = ssl_to_qel_addr(qc, level); + struct quic_pktns **pktns = ssl_to_quic_pktns(qc, level); - qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); TRACE_ENTER(QUIC_EV_CONN_ADDDATA, qc); if (qc->flags & QUIC_FL_CONN_TO_KILL) { @@ -1384,25 +1374,10 @@ int ha_quic_add_handshake_data(SSL *ssl, enum ssl_encryption_level_t level, goto out; } - tel = ssl_to_quic_enc_level(level); - if (tel == -1) { - TRACE_ERROR("Wrong encryption level", QUIC_EV_CONN_ADDDATA, qc); + if (!*qel && !qc_enc_level_alloc(qc, pktns, qel, level)) goto leave; - } - qel = &qc->els[tel]; - if (!qel->pktns) { - struct quic_pktns **pktns = ssl_to_quic_pktns(qc, level); - - if (pktns == NULL || - !quic_pktns_init(qc, pktns) || - !quic_conn_enc_level_init(qc, *pktns, tel)) { - TRACE_ERROR("Could not initialized the packet number space", QUIC_EV_CONN_ADDDATA, qc); - goto leave; - } - } - - if (!quic_crypto_data_cpy(qc, qel, data, len)) { + if (!quic_crypto_data_cpy(qc, *qel, data, len)) { TRACE_ERROR("Could not bufferize", QUIC_EV_CONN_ADDDATA, qc); goto leave; } @@ -2767,8 +2742,8 @@ static void qc_prep_hdshk_fast_retrans(struct quic_conn *qc, struct list itmp = LIST_HEAD_INIT(itmp); struct list htmp = LIST_HEAD_INIT(htmp); - struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; - struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; + struct quic_enc_level *iqel = qc->iel; + struct quic_enc_level *hqel = qc->hel; struct quic_enc_level *qel = iqel; struct eb_root *pkts; struct eb64_node *node; @@ -2869,7 +2844,7 @@ static int qc_h3_request_reject(struct quic_conn *qc, uint64_t id) { int ret = 0; struct quic_frame *ss, *rs; - struct quic_enc_level *qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; + struct quic_enc_level *qel = qc->ael; const uint64_t app_error_code = H3_REQUEST_REJECTED; TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); @@ -2976,7 +2951,7 @@ static int qc_handle_crypto_frm(struct quic_conn *qc, /* Nothing to do */ TRACE_PROTO("Already received CRYPTO data", QUIC_EV_CONN_RXPKT, qc, pkt, &cfdebug); - if (qc_is_listener(qc) && qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL] && + if (qc_is_listener(qc) && qel == qc->iel && !(qc->flags & QUIC_FL_CONN_HANDSHAKE_SPEED_UP)) *fast_retrans = 1; goto done; @@ -3045,7 +3020,7 @@ static int qc_build_new_connection_id_frm(struct quic_conn *qc, TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); - qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; + qel = qc->ael; frm = qc_frm_alloc(QUIC_FT_NEW_CONNECTION_ID); if (!frm) { TRACE_ERROR("frame allocation error", QUIC_EV_CONN_IO_CB, qc); @@ -3361,8 +3336,8 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt, qel->pktns->flags |= QUIC_FL_PKTNS_PKT_RECEIVED; if (fast_retrans) { - struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; - struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; + struct quic_enc_level *iqel = qc->iel; + struct quic_enc_level *hqel = qc->hel; TRACE_PROTO("speeding up handshake completion", QUIC_EV_CONN_PRSHPKT, qc); qc_prep_hdshk_fast_retrans(qc, &iqel->pktns->tx.frms, &hqel->pktns->tx.frms); @@ -3375,14 +3350,14 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt, */ if (pkt->type == QUIC_PACKET_TYPE_HANDSHAKE && qc_is_listener(qc)) { if (qc->state >= QUIC_HS_ST_SERVER_INITIAL) { - if (!(qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].tls_ctx.flags & + if (!(qc->iel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_DCD)) { - quic_tls_discard_keys(&qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]); + quic_tls_discard_keys(qc->iel); TRACE_PROTO("discarding Initial pktns", QUIC_EV_CONN_PRSHPKT, qc); - quic_pktns_discard(qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].pktns, qc); + quic_pktns_discard(qc->iel->pktns, qc); qc_set_timer(qc); - qc_el_rx_pkts_del(&qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]); - qc_release_pktns_frms(qc, qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].pktns); + qc_el_rx_pkts_del(qc->iel); + qc_release_pktns_frms(qc, qc->iel->pktns); } if (qc->state < QUIC_HS_ST_SERVER_HANDSHAKE) qc->state = QUIC_HS_ST_SERVER_HANDSHAKE; @@ -3454,9 +3429,7 @@ static int qc_may_build_pkt(struct quic_conn *qc, struct list *frms, struct quic_enc_level *qel, int cc, int probe, int *must_ack) { - int force_ack = - qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL] || - qel == &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; + int force_ack = qel == qc->iel || qel == qc->hel; int nb_aepkts_since_last_ack = qel->pktns->rx.nb_aepkts_since_last_ack; /* An acknowledgement must be sent if this has been forced by the caller, @@ -3507,7 +3480,7 @@ static int qc_prep_app_pkts(struct quic_conn *qc, struct buffer *buf, TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc); - qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; + qel = qc->ael; total = 0; pos = (unsigned char *)b_tail(buf); while (b_contig_space(buf) >= (int)qc->path->mtu + dg_headlen) { @@ -3603,7 +3576,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf, BUG_ON_HOT(buf->head || buf->data); total = 0; - qel = &qc->els[tel]; + qel = qc_quic_enc_level(qc, tel); frms = tel_frms; dglen = 0; padding = 0; @@ -3629,7 +3602,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf, if (tel != next_tel && next_tel != QUIC_TLS_ENC_LEVEL_NONE) { tel = next_tel; frms = next_tel_frms; - qel = &qc->els[tel]; + qel = qc_quic_enc_level(qc, tel); /* Build a new datagram */ prv_pkt = NULL; TRACE_DEVEL("next encryption level selected", QUIC_EV_CONN_PHPKTS, qc); @@ -3673,7 +3646,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf, if (qc->negotiated_version) { ver = qc->negotiated_version; - if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]) + if (qel == qc->iel) tls_ctx = &qc->negotiated_ictx; else tls_ctx = &qel->tls_ctx; @@ -3726,12 +3699,12 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf, */ if (qc->state == QUIC_HS_ST_CLIENT_INITIAL && pkt_type == QUIC_PACKET_TYPE_HANDSHAKE) { - quic_tls_discard_keys(&qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]); + quic_tls_discard_keys(qc->iel); TRACE_PROTO("discarding Initial pktns", QUIC_EV_CONN_PHPKTS, qc); - quic_pktns_discard(qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].pktns, qc); + quic_pktns_discard(qc->iel->pktns, qc); qc_set_timer(qc); - qc_el_rx_pkts_del(&qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]); - qc_release_pktns_frms(qc, qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].pktns); + qc_el_rx_pkts_del(qc->iel); + qc_release_pktns_frms(qc, qc->iel->pktns); qc->state = QUIC_HS_ST_CLIENT_HANDSHAKE; } /* If the data for the current encryption level have all been sent, @@ -3743,11 +3716,11 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf, if (tel == QUIC_TLS_ENC_LEVEL_HANDSHAKE && next_tel == tel) next_tel = QUIC_TLS_ENC_LEVEL_APP; tel = next_tel; + qel = qc_quic_enc_level(qc, tel); if (tel == QUIC_TLS_ENC_LEVEL_APP) - frms = &qc->els[tel].pktns->tx.frms; + frms = &qel->pktns->tx.frms; else frms = next_tel_frms; - qel = &qc->els[tel]; if (!LIST_ISEMPTY(frms)) { /* If there is data for the next level, do not * consume a datagram. @@ -4188,7 +4161,7 @@ static int quic_build_post_handshake_frames(struct quic_conn *qc) TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc); - qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; + qel = qc->ael; /* Only servers must send a HANDSHAKE_DONE frame. */ if (qc_is_listener(qc)) { frm = qc_frm_alloc(QUIC_FT_HANDSHAKE_DONE); @@ -4473,7 +4446,7 @@ static inline void qc_handle_spin_bit(struct quic_conn *qc, struct quic_rx_packe { uint64_t largest_pn = qel->pktns->rx.largest_pn; - if (qel != &qc->els[QUIC_TLS_ENC_LEVEL_APP] || largest_pn == -1 || + if (qel != qc->ael || largest_pn == -1 || pkt->pn <= largest_pn) return; @@ -4497,12 +4470,10 @@ static inline void qc_handle_spin_bit(struct quic_conn *qc, struct quic_rx_packe static inline void qc_rm_hp_pkts(struct quic_conn *qc, struct quic_enc_level *el) { struct quic_rx_packet *pqpkt, *pkttmp; - struct quic_enc_level *app_qel; TRACE_ENTER(QUIC_EV_CONN_ELRMHP, qc); - app_qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; /* A server must not process incoming 1-RTT packets before the handshake is complete. */ - if (el == app_qel && qc_is_listener(qc) && qc->state < QUIC_HS_ST_COMPLETE) { + if (el == qc->ael && qc_is_listener(qc) && qc->state < QUIC_HS_ST_COMPLETE) { TRACE_PROTO("RX hp not removed (handshake not completed)", QUIC_EV_CONN_ELRMHP, qc); goto out; @@ -4679,15 +4650,12 @@ int qc_treat_rx_pkts(struct quic_conn *qc, struct quic_enc_level *cur_el, static int qc_qel_may_rm_hp(struct quic_conn *qc, struct quic_enc_level *qel) { int ret = 0; - enum quic_tls_enc_level tel; TRACE_ENTER(QUIC_EV_CONN_TRMHP, qc); if (!qel) goto cant_rm_hp; - tel = ssl_to_quic_enc_level(qel->level); - /* check if tls secrets are available */ if (qel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_DCD) { TRACE_PROTO("Discarded keys", QUIC_EV_CONN_TRMHP, qc); @@ -4699,13 +4667,13 @@ static int qc_qel_may_rm_hp(struct quic_conn *qc, struct quic_enc_level *qel) goto cant_rm_hp; } - if (tel == QUIC_TLS_ENC_LEVEL_APP && qc->state < QUIC_HS_ST_COMPLETE) { + if (qel == qc->ael && qc->state < QUIC_HS_ST_COMPLETE) { TRACE_PROTO("handshake not complete", QUIC_EV_CONN_TRMHP, qc); goto cant_rm_hp; } /* check if the connection layer is ready before using app level */ - if ((tel == QUIC_TLS_ENC_LEVEL_APP || tel == QUIC_TLS_ENC_LEVEL_EARLY_DATA) && + if ((qel == qc->ael || qel == qc->eel) && qc->mux_state == QC_MUX_NULL) { TRACE_PROTO("connection layer not ready", QUIC_EV_CONN_TRMHP, qc); goto cant_rm_hp; @@ -4847,9 +4815,8 @@ int qc_send_mux(struct quic_conn *qc, struct list *frms) /* Try to send post handshake frames first unless on 0-RTT. */ if ((qc->flags & QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS) && qc->state >= QUIC_HS_ST_COMPLETE) { - struct quic_enc_level *qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; quic_build_post_handshake_frames(qc); - qc_send_app_pkts(qc, &qel->pktns->tx.frms); + qc_send_app_pkts(qc, &qc->ael->pktns->tx.frms); } TRACE_STATE("preparing data (from MUX)", QUIC_EV_CONN_TXPKT, qc); @@ -4925,9 +4892,9 @@ int qc_send_hdshk_pkts(struct quic_conn *qc, int old_data, static int qc_dgrams_retransmit(struct quic_conn *qc) { int ret = 0; - struct quic_enc_level *iqel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; - struct quic_enc_level *hqel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; - struct quic_enc_level *aqel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; + struct quic_enc_level *iqel = qc->iel; + struct quic_enc_level *hqel = qc->hel; + struct quic_enc_level *aqel = qc->ael; TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); @@ -5035,7 +5002,7 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc); - qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP]; + qel = qc->ael; TRACE_STATE("connection handshake state", QUIC_EV_CONN_IO_CB, qc, &qc->state); if (qc_test_fd(qc)) @@ -5097,6 +5064,19 @@ static int qc_need_sending(struct quic_conn *qc, struct quic_enc_level *qel) !LIST_ISEMPTY(&qel->pktns->tx.frms); } +static int qc_prep_hpkts(struct quic_conn *qc, struct buffer *buf, + struct quic_enc_level *qel, struct quic_enc_level *next_qel) +{ + enum quic_tls_enc_level next_tel = + next_qel ? ssl_to_quic_enc_level(next_qel->level) : QUIC_TLS_ENC_LEVEL_NONE; + struct list *next_frms = + next_qel ? &next_qel->pktns->tx.frms : NULL; + + return qc_prep_pkts(qc, buf, + ssl_to_quic_enc_level(qel->level), &qel->pktns->tx.frms, + next_tel, next_frms); +} + /* QUIC connection packet handler task. */ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) { @@ -5111,7 +5091,7 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc); - eqel = &qc->els[QUIC_TLS_ENC_LEVEL_EARLY_DATA]; + eqel = qc->eel; st = qc->state; TRACE_PROTO("connection state", QUIC_EV_CONN_IO_CB, qc, &st); @@ -5132,7 +5112,7 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) qc_rcv_buf(qc); if (st >= QUIC_HS_ST_COMPLETE && - qc_el_rx_pkts(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])) { + qc_el_rx_pkts(qc->hel)) { TRACE_DEVEL("remaining Handshake packets", QUIC_EV_CONN_PHPKTS, qc); /* There may be remaining Handshake packets to treat and acknowledge. */ tel = QUIC_TLS_ENC_LEVEL_HANDSHAKE; @@ -5141,8 +5121,8 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) else if (!quic_get_tls_enc_levels(&tel, &next_tel, qc, st, zero_rtt)) goto out; - qel = &qc->els[tel]; - next_qel = next_tel == QUIC_TLS_ENC_LEVEL_NONE ? NULL : &qc->els[next_tel]; + qel = qc_quic_enc_level(qc, tel); + next_qel = next_tel == QUIC_TLS_ENC_LEVEL_NONE ? NULL : qc_quic_enc_level(qc, next_tel); next_level: /* Treat packets waiting for header packet protection decryption */ @@ -5174,18 +5154,17 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) st = qc->state; if (st >= QUIC_HS_ST_COMPLETE) { - if (!(qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].tls_ctx.flags & - QUIC_FL_TLS_SECRETS_DCD)) { + if (!(qc->hel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_DCD)) { /* Discard the Handshake keys. */ - quic_tls_discard_keys(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]); + quic_tls_discard_keys(qc->hel); TRACE_PROTO("discarding Handshake pktns", QUIC_EV_CONN_PHPKTS, qc); - quic_pktns_discard(qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].pktns, qc); + quic_pktns_discard(qc->hel->pktns, qc); qc_set_timer(qc); - qc_el_rx_pkts_del(&qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]); - qc_release_pktns_frms(qc, qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].pktns); + qc_el_rx_pkts_del(qc->hel); + qc_release_pktns_frms(qc, qc->hel->pktns); } - if (qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) { + if (qc->hel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED) { /* There may be remaining handshake to build (acks) */ st = QUIC_HS_ST_SERVER_HANDSHAKE; } @@ -5216,8 +5195,9 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) BUG_ON_HOT(b_data(buf)); b_reset(buf); - ret = qc_prep_pkts(qc, buf, tel, &qc->els[tel].pktns->tx.frms, - next_tel, &qc->els[next_tel].pktns->tx.frms); + ret = qc_prep_hpkts(qc, buf, + qc_quic_enc_level(qc, tel), + qc_quic_enc_level(qc, next_tel)); if (ret == -1) { qc_txb_release(qc); goto out; @@ -5386,13 +5366,10 @@ struct task *qc_process_timer(struct task *task, void *ctx, unsigned int state) } } else if (!qc_is_listener(qc) && qc->state <= QUIC_HS_ST_COMPLETE) { - struct quic_enc_level *iel = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL]; - struct quic_enc_level *hel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; - - if (quic_tls_has_tx_sec(hel)) - hel->pktns->tx.pto_probe = 1; - if (quic_tls_has_tx_sec(iel)) - iel->pktns->tx.pto_probe = 1; + if (quic_tls_has_tx_sec(qc->hel)) + qc->hel->pktns->tx.pto_probe = 1; + if (quic_tls_has_tx_sec(qc->iel)) + qc->iel->pktns->tx.pto_probe = 1; } tasklet_wakeup(qc->wait_event.tasklet); @@ -5480,7 +5457,6 @@ static struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, struct quic_conn *qc; struct listener *l = NULL; struct quic_cc_algo *cc_algo = NULL; - struct quic_tls_ctx *ictx, *app_ctx; TRACE_ENTER(QUIC_EV_CONN_INIT); @@ -5526,30 +5502,15 @@ static struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, quic_tls_ku_reset(&qc->ku.nxt_rx); quic_tls_ku_reset(&qc->ku.nxt_tx); - /* Encryption level: required to safely call quic_conn_enc_level_uninit() - * from quic_conn_release(). - */ - for (i = 0; i < QUIC_TLS_ENC_LEVEL_MAX; i++) { - struct quic_enc_level *qel = &qc->els[i]; - struct quic_tls_ctx *ctx = &qel->tls_ctx; - - quic_tls_ctx_reset(ctx); - qel->tx.crypto.nb_buf = 0; - qel->tx.crypto.bufs = NULL; - qel->cstream = NULL; - qel->pktns = NULL; - } - + /* Encryption levels */ + qc->iel = qc->eel = qc->hel = qc->ael = NULL; + LIST_INIT(&qc->qel_list); /* Packet number spaces */ qc->ipktns = qc->hpktns = qc->apktns = NULL; LIST_INIT(&qc->pktns_list); quic_tls_ctx_reset(&qc->negotiated_ictx); - app_ctx = &qc->els[QUIC_TLS_ENC_LEVEL_APP].tls_ctx; - app_ctx->rx.secret = NULL; - app_ctx->tx.secret = NULL; - /* Required to safely call quic_conn_prx_cntrs_update() from quic_conn_release(). */ qc->prx_counters = NULL; @@ -5607,12 +5568,7 @@ static struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, /* Select our SCID which is the first CID with 0 as sequence number. */ qc->scid = conn_id->cid; - /* Initial packet number spaces initialization. */ - if (!quic_pktns_init(qc, &qc->ipktns)) - goto err; - - /* Initial encryption level initialization */ - if (!quic_conn_enc_level_init(qc, qc->ipktns, QUIC_TLS_ENC_LEVEL_INITIAL)) { + if (!qc_enc_level_alloc(qc, &qc->ipktns, &qc->iel, ssl_encryption_initial)) { TRACE_ERROR("Could not initialize an encryption level", QUIC_EV_CONN_INIT, qc); goto err; } @@ -5678,8 +5634,7 @@ static struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, !quic_conn_init_idle_timer_task(qc)) goto err; - ictx = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].tls_ctx; - if (!qc_new_isecs(qc, ictx,qc->original_version, dcid->data, dcid->len, 1)) + if (!qc_new_isecs(qc, &qc->iel->tls_ctx, qc->original_version, dcid->data, dcid->len, 1)) goto err; /* Counters initialization */ @@ -5728,10 +5683,8 @@ static inline void quic_conn_prx_cntrs_update(struct quic_conn *qc) */ void quic_conn_release(struct quic_conn *qc) { - int i; struct ssl_sock_ctx *conn_ctx; struct eb64_node *node; - struct quic_tls_ctx *app_tls_ctx; struct quic_rx_packet *pkt, *pktback; TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); @@ -5792,15 +5745,20 @@ void quic_conn_release(struct quic_conn *qc) } quic_tls_ku_free(qc); - for (i = 0; i < QUIC_TLS_ENC_LEVEL_MAX; i++) { - quic_tls_ctx_secs_free(&qc->els[i].tls_ctx); - quic_conn_enc_level_uninit(qc, &qc->els[i]); - } - quic_tls_ctx_secs_free(&qc->negotiated_ictx); + if (qc->ael) { + struct quic_tls_ctx *actx = &qc->ael->tls_ctx; - app_tls_ctx = &qc->els[QUIC_TLS_ENC_LEVEL_APP].tls_ctx; - pool_free(pool_head_quic_tls_secret, app_tls_ctx->rx.secret); - pool_free(pool_head_quic_tls_secret, app_tls_ctx->tx.secret); + /* Secrets used by keyupdate */ + pool_free(pool_head_quic_tls_secret, actx->rx.secret); + pool_free(pool_head_quic_tls_secret, actx->tx.secret); + } + + qc_enc_level_free(qc, &qc->iel); + qc_enc_level_free(qc, &qc->eel); + qc_enc_level_free(qc, &qc->hel); + qc_enc_level_free(qc, &qc->ael); + + quic_tls_ctx_secs_free(&qc->negotiated_ictx); quic_pktns_release(qc, &qc->ipktns); quic_pktns_release(qc, &qc->hpktns); @@ -6092,7 +6050,7 @@ static inline int qc_try_rm_hp(struct quic_conn *qc, pn = beg + pkt->pn_offset; tel = quic_packet_type_enc_level(pkt->type); - qel = &qc->els[tel]; + qel = qc_quic_enc_level(qc, tel); if (qc_qel_may_rm_hp(qc, qel)) { struct quic_tls_ctx *tls_ctx = qc_select_tls_ctx(qc, qel, pkt); @@ -7802,8 +7760,7 @@ static void qc_build_cc_frm(struct quic_conn *qc, struct quic_enc_level *qel, if (qc->err.app) { - if (unlikely(qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL] || - qel == &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])) { + if (unlikely(qel == qc->iel || qel == qc->hel)) { /* RFC 9000 10.2.3. Immediate Close during the Handshake * * Sending a CONNECTION_CLOSE of type 0x1d in an Initial or Handshake diff --git a/src/quic_tls.c b/src/quic_tls.c index 99cd50589..cb4c37fb2 100644 --- a/src/quic_tls.c +++ b/src/quic_tls.c @@ -106,20 +106,23 @@ void quic_tls_secret_hexdump(struct buffer *buf, * Returns 1 if succeeded, 0 if not. On error the caller is responsible to use * quic_conn_enc_level_uninit() to cleanup partially allocated content. */ -int quic_conn_enc_level_init(struct quic_conn *qc, - enum quic_tls_enc_level level) +static int quic_conn_enc_level_init(struct quic_conn *qc, + struct quic_enc_level **el, + struct quic_pktns *pktns, + enum ssl_encryption_level_t level) { int ret = 0; struct quic_enc_level *qel; TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc); - qel = &qc->els[level]; - qel->level = quic_to_ssl_enc_level(level); - qel->tls_ctx.rx.aead = qel->tls_ctx.tx.aead = NULL; - qel->tls_ctx.rx.md = qel->tls_ctx.tx.md = NULL; - qel->tls_ctx.rx.hp = qel->tls_ctx.tx.hp = NULL; - qel->tls_ctx.flags = 0; + qel = pool_alloc(pool_head_quic_enc_level); + if (!qel) + goto leave; + + qel->pktns = pktns; + qel->level = level; + quic_tls_ctx_reset(&qel->tls_ctx); qel->rx.pkts = EB_ROOT; LIST_INIT(&qel->rx.pqpkts); @@ -140,7 +143,7 @@ int quic_conn_enc_level_init(struct quic_conn *qc, qel->tx.crypto.sz = 0; qel->tx.crypto.offset = 0; /* No CRYPTO data for early data TLS encryption level */ - if (level == QUIC_TLS_ENC_LEVEL_EARLY_DATA) + if (level == ssl_encryption_early_data) qel->cstream = NULL; else { qel->cstream = quic_cstream_new(qc); @@ -148,6 +151,8 @@ int quic_conn_enc_level_init(struct quic_conn *qc, goto leave; } + LIST_APPEND(&qc->qel_list, &qel->list); + *el = qel; ret = 1; leave: TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); @@ -173,6 +178,48 @@ void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc); } +/* Allocate a QUIC TLS encryption with as TLS stack encryption to be + * attached to QUIC connection. Also allocate the associated packet number + * space object with as address to be attached to if not already + * allocated. + * Return 1 if succeeded, 0 if not. + */ +int qc_enc_level_alloc(struct quic_conn *qc, struct quic_pktns **pktns, + struct quic_enc_level **qel, enum ssl_encryption_level_t level) +{ + int ret = 0; + + BUG_ON(!qel || !pktns); + BUG_ON(*qel && !*pktns); + + if (!*pktns && !quic_pktns_init(qc, pktns)) + goto leave; + + if (!*qel && !quic_conn_enc_level_init(qc, qel, *pktns, level)) + goto leave; + + ret = 1; + leave: + return ret; +} + +/* Free the memory allocated to the encryption level attached to connection + * with as pointer address. Also remove it from the list of the encryption + * levels attached to this connection and reset its value to NULL. + * Never fails. + */ +void qc_enc_level_free(struct quic_conn *qc, struct quic_enc_level **qel) +{ + if (!*qel) + return; + + quic_tls_ctx_secs_free(&(*qel)->tls_ctx); + quic_conn_enc_level_uninit(qc, *qel); + LIST_DEL_INIT(&(*qel)->list); + pool_free(pool_head_quic_enc_level, *qel); + *qel = NULL; +} + int quic_hkdf_extract(const EVP_MD *md, unsigned char *buf, size_t buflen, const unsigned char *key, size_t keylen,