mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-05 22:56:57 +02:00
MINOR: quic-be: address validation support implementation (RETRY)
- Add ->retry_token and ->retry_token_len new quic_conn struct members to store the retry tokens. These objects are allocated by quic_rx_packet_parse() and released by quic_conn_release(). - Add <pool_head_quic_retry_token> new pool for these tokens. - Implement quic_retry_packet_check() to check the integrity tag of these tokens upon RETRY packets receipt. quic_tls_generate_retry_integrity_tag() is called by this new function. It has been modified to pass the address where the tag must be generated - Add <resend> new parameter to quic_pktns_discard(). This function is called to discard the packet number spaces where the already TX packets and frames are attached to. <resend> allows the caller to prevent this function to release the in flight TX packets/frames. The frames are requeued to be resent. - Modify quic_rx_pkt_parse() to handle the RETRY packets. What must be done upon such packets receipt is: - store the retry token, - store the new peer SCID as the DCID of the connection. Note that the peer will modify again its SCID. This is why this SCID is also stored as the ODCID which must be matched with the peer retry_source_connection_id transport parameter, - discard the Initial packet number space without flagging it as discarded and prevent retransmissions calling qc_set_timer(), - modify the TLS cryptographic cipher contexts (RX/TX), - wakeup the I/O handler to send new Initial packets asap. - Modify quic_transport_param_decode() to handle the retry_source_connection_id transport parameter as a QUIC client. Then its caller is modified to check this transport parameter matches with the SCID sent by the peer with the RETRY packet.
This commit is contained in:
parent
8a25fcd36e
commit
194e3bc2d5
@ -356,6 +356,10 @@ struct quic_conn {
|
|||||||
*/
|
*/
|
||||||
uint64_t hash64;
|
uint64_t hash64;
|
||||||
|
|
||||||
|
/* QUIC client only retry token received from servers RETRY packet */
|
||||||
|
unsigned char *retry_token;
|
||||||
|
size_t retry_token_len;
|
||||||
|
|
||||||
/* Initial encryption level */
|
/* Initial encryption level */
|
||||||
struct quic_enc_level *iel;
|
struct quic_enc_level *iel;
|
||||||
/* 0-RTT encryption level */
|
/* 0-RTT encryption level */
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#include <haproxy/quic_rx-t.h>
|
#include <haproxy/quic_rx-t.h>
|
||||||
#include <haproxy/quic_sock-t.h>
|
#include <haproxy/quic_sock-t.h>
|
||||||
|
|
||||||
|
extern struct pool_head *pool_head_quic_retry_token;
|
||||||
|
|
||||||
struct listener;
|
struct listener;
|
||||||
|
|
||||||
int quic_generate_retry_token(unsigned char *token, size_t len,
|
int quic_generate_retry_token(unsigned char *token, size_t len,
|
||||||
@ -28,6 +30,9 @@ int quic_retry_token_check(struct quic_rx_packet *pkt,
|
|||||||
struct listener *l,
|
struct listener *l,
|
||||||
struct quic_conn *qc,
|
struct quic_conn *qc,
|
||||||
struct quic_cid *odcid);
|
struct quic_cid *odcid);
|
||||||
|
int quic_retry_packet_check(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
||||||
|
const unsigned char *beg, const unsigned char *end,
|
||||||
|
const unsigned char *pos, size_t *retry_token_len);
|
||||||
|
|
||||||
#endif /* USE_QUIC */
|
#endif /* USE_QUIC */
|
||||||
#endif /* _HAPROXY_QUIC_RETRY_H */
|
#endif /* _HAPROXY_QUIC_RETRY_H */
|
||||||
|
@ -74,7 +74,8 @@ int quic_tls_decrypt(unsigned char *buf, size_t len,
|
|||||||
const unsigned char *key, const unsigned char *iv);
|
const unsigned char *key, const unsigned char *iv);
|
||||||
|
|
||||||
int quic_tls_generate_retry_integrity_tag(unsigned char *odcid, unsigned char odcid_len,
|
int quic_tls_generate_retry_integrity_tag(unsigned char *odcid, unsigned char odcid_len,
|
||||||
unsigned char *buf, size_t len,
|
const unsigned char *buf, size_t len,
|
||||||
|
unsigned char *tag,
|
||||||
const struct quic_version *qv);
|
const struct quic_version *qv);
|
||||||
|
|
||||||
int quic_tls_derive_keys(const QUIC_AEAD *aead, const EVP_CIPHER *hp,
|
int quic_tls_derive_keys(const QUIC_AEAD *aead, const EVP_CIPHER *hp,
|
||||||
@ -536,7 +537,8 @@ static inline int quic_pktns_init(struct quic_conn *qc, struct quic_pktns **p)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void quic_pktns_tx_pkts_release(struct quic_pktns *pktns, struct quic_conn *qc)
|
static inline void quic_pktns_tx_pkts_release(struct quic_pktns *pktns,
|
||||||
|
struct quic_conn *qc, int resend)
|
||||||
{
|
{
|
||||||
struct eb64_node *node;
|
struct eb64_node *node;
|
||||||
|
|
||||||
@ -557,7 +559,11 @@ static inline void quic_pktns_tx_pkts_release(struct quic_pktns *pktns, struct q
|
|||||||
qc_frm_unref(frm, qc);
|
qc_frm_unref(frm, qc);
|
||||||
LIST_DEL_INIT(&frm->list);
|
LIST_DEL_INIT(&frm->list);
|
||||||
quic_tx_packet_refdec(frm->pkt);
|
quic_tx_packet_refdec(frm->pkt);
|
||||||
qc_frm_free(qc, &frm);
|
if (!resend)
|
||||||
|
qc_frm_free(qc, &frm);
|
||||||
|
else
|
||||||
|
LIST_APPEND(&pktns->tx.frms, &frm->list);
|
||||||
|
|
||||||
}
|
}
|
||||||
eb64_delete(&pkt->pn_node);
|
eb64_delete(&pkt->pn_node);
|
||||||
quic_tx_packet_refdec(pkt);
|
quic_tx_packet_refdec(pkt);
|
||||||
@ -572,9 +578,12 @@ static inline void quic_pktns_tx_pkts_release(struct quic_pktns *pktns, struct q
|
|||||||
* connection.
|
* connection.
|
||||||
* Note that all the non acknowledged TX packets and their frames are freed.
|
* Note that all the non acknowledged TX packets and their frames are freed.
|
||||||
* Always succeeds.
|
* Always succeeds.
|
||||||
|
* <resend> boolean must be 1 to resend the frames which are in flight.
|
||||||
|
* This is only used to resend the Initial packet frames upon a RETRY
|
||||||
|
* packet receipt (backend only option).
|
||||||
*/
|
*/
|
||||||
static inline void quic_pktns_discard(struct quic_pktns *pktns,
|
static inline void quic_pktns_discard(struct quic_pktns *pktns,
|
||||||
struct quic_conn *qc)
|
struct quic_conn *qc, int resend)
|
||||||
{
|
{
|
||||||
TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
|
TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
|
||||||
|
|
||||||
@ -590,7 +599,7 @@ static inline void quic_pktns_discard(struct quic_pktns *pktns,
|
|||||||
pktns->tx.loss_time = TICK_ETERNITY;
|
pktns->tx.loss_time = TICK_ETERNITY;
|
||||||
pktns->tx.pto_probe = 0;
|
pktns->tx.pto_probe = 0;
|
||||||
pktns->tx.in_flight = 0;
|
pktns->tx.in_flight = 0;
|
||||||
quic_pktns_tx_pkts_release(pktns, qc);
|
quic_pktns_tx_pkts_release(pktns, qc, resend);
|
||||||
|
|
||||||
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
|
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include <haproxy/quic_enc.h>
|
#include <haproxy/quic_enc.h>
|
||||||
#include <haproxy/quic_loss.h>
|
#include <haproxy/quic_loss.h>
|
||||||
#include <haproxy/quic_rx.h>
|
#include <haproxy/quic_rx.h>
|
||||||
|
#include <haproxy/quic_retry.h>
|
||||||
#include <haproxy/quic_ssl.h>
|
#include <haproxy/quic_ssl.h>
|
||||||
#include <haproxy/quic_sock.h>
|
#include <haproxy/quic_sock.h>
|
||||||
#include <haproxy/quic_stats.h>
|
#include <haproxy/quic_stats.h>
|
||||||
@ -841,7 +842,7 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
|
|||||||
if (discard_hpktns) {
|
if (discard_hpktns) {
|
||||||
/* Discard the Handshake packet number space. */
|
/* Discard the Handshake packet number space. */
|
||||||
TRACE_PROTO("discarding Handshake pktns", QUIC_EV_CONN_PHPKTS, qc);
|
TRACE_PROTO("discarding Handshake pktns", QUIC_EV_CONN_PHPKTS, qc);
|
||||||
quic_pktns_discard(qc->hel->pktns, qc);
|
quic_pktns_discard(qc->hel->pktns, qc, 0);
|
||||||
qc_set_timer(qc);
|
qc_set_timer(qc);
|
||||||
qc_el_rx_pkts_del(qc->hel);
|
qc_el_rx_pkts_del(qc->hel);
|
||||||
qc_release_pktns_frms(qc, qc->hel->pktns);
|
qc_release_pktns_frms(qc, qc->hel->pktns);
|
||||||
@ -921,7 +922,7 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
|
|||||||
qc->hpktns && qc->hpktns->tx.in_flight > 0) {
|
qc->hpktns && qc->hpktns->tx.in_flight > 0) {
|
||||||
/* Discard the Initial packet number space. */
|
/* Discard the Initial packet number space. */
|
||||||
TRACE_PROTO("discarding Initial pktns", QUIC_EV_CONN_PRSHPKT, qc);
|
TRACE_PROTO("discarding Initial pktns", QUIC_EV_CONN_PRSHPKT, qc);
|
||||||
quic_pktns_discard(qc->ipktns, qc);
|
quic_pktns_discard(qc->ipktns, qc, 0);
|
||||||
qc_set_timer(qc);
|
qc_set_timer(qc);
|
||||||
qc_el_rx_pkts_del(qc->iel);
|
qc_el_rx_pkts_del(qc->iel);
|
||||||
qc_release_pktns_frms(qc, qc->ipktns);
|
qc_release_pktns_frms(qc, qc->ipktns);
|
||||||
@ -1167,6 +1168,8 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
|
|||||||
#ifdef HAVE_OPENSSL_QUIC
|
#ifdef HAVE_OPENSSL_QUIC
|
||||||
qc->prot_level = OSSL_RECORD_PROTECTION_LEVEL_NONE;
|
qc->prot_level = OSSL_RECORD_PROTECTION_LEVEL_NONE;
|
||||||
#endif
|
#endif
|
||||||
|
qc->retry_token = NULL;
|
||||||
|
qc->retry_token_len = 0;
|
||||||
/* Encryption levels */
|
/* Encryption levels */
|
||||||
qc->iel = qc->eel = qc->hel = qc->ael = NULL;
|
qc->iel = qc->eel = qc->hel = qc->ael = NULL;
|
||||||
LIST_INIT(&qc->qel_list);
|
LIST_INIT(&qc->qel_list);
|
||||||
@ -1198,8 +1201,6 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
|
|||||||
qc->flags = QUIC_FL_CONN_PEER_VALIDATED_ADDR;
|
qc->flags = QUIC_FL_CONN_PEER_VALIDATED_ADDR;
|
||||||
qc->state = QUIC_HS_ST_CLIENT_INITIAL;
|
qc->state = QUIC_HS_ST_CLIENT_INITIAL;
|
||||||
|
|
||||||
memset(&qc->odcid, 0, sizeof qc->odcid);
|
|
||||||
qc->odcid.len = 0;
|
|
||||||
/* This is the original connection ID from the peer server
|
/* This is the original connection ID from the peer server
|
||||||
* point of view.
|
* point of view.
|
||||||
*/
|
*/
|
||||||
@ -1208,6 +1209,9 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
|
|||||||
|
|
||||||
qc->dcid.len = sizeof(qc->dcid.data);
|
qc->dcid.len = sizeof(qc->dcid.data);
|
||||||
|
|
||||||
|
memcpy(&qc->odcid, qc->dcid.data, sizeof(qc->dcid.data));
|
||||||
|
qc->odcid.len = qc->dcid.len;
|
||||||
|
|
||||||
conn_cid = new_quic_cid(qc->cids, qc, NULL, NULL);
|
conn_cid = new_quic_cid(qc->cids, qc, NULL, NULL);
|
||||||
if (!conn_cid)
|
if (!conn_cid)
|
||||||
goto err;
|
goto err;
|
||||||
@ -1576,6 +1580,9 @@ int quic_conn_release(struct quic_conn *qc)
|
|||||||
pool_free(pool_head_quic_tls_secret, actx->tx.secret);
|
pool_free(pool_head_quic_tls_secret, actx->tx.secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool_free(pool_head_quic_retry_token, qc->retry_token);
|
||||||
|
qc->retry_token = NULL;
|
||||||
|
qc->retry_token_len = 0;
|
||||||
qc_enc_level_free(qc, &qc->iel);
|
qc_enc_level_free(qc, &qc->iel);
|
||||||
qc_enc_level_free(qc, &qc->eel);
|
qc_enc_level_free(qc, &qc->eel);
|
||||||
qc_enc_level_free(qc, &qc->hel);
|
qc_enc_level_free(qc, &qc->hel);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <haproxy/clock.h>
|
#include <haproxy/clock.h>
|
||||||
|
#include <haproxy/errors.h>
|
||||||
#include <haproxy/global.h>
|
#include <haproxy/global.h>
|
||||||
#include <haproxy/quic_retry.h>
|
#include <haproxy/quic_retry.h>
|
||||||
#include <haproxy/quic_tls.h>
|
#include <haproxy/quic_tls.h>
|
||||||
@ -11,6 +12,9 @@
|
|||||||
|
|
||||||
/* Salt length used to derive retry token secret */
|
/* Salt length used to derive retry token secret */
|
||||||
#define QUIC_RETRY_TOKEN_SALTLEN 16 /* bytes */
|
#define QUIC_RETRY_TOKEN_SALTLEN 16 /* bytes */
|
||||||
|
#define QUIC_RETRY_TOKEN_MAXLEN 256 /* bytes */
|
||||||
|
|
||||||
|
struct pool_head *pool_head_quic_retry_token;
|
||||||
|
|
||||||
/* Copy <saddr> socket address data into <buf> buffer.
|
/* Copy <saddr> socket address data into <buf> buffer.
|
||||||
* This is the responsibility of the caller to check the output buffer is big
|
* This is the responsibility of the caller to check the output buffer is big
|
||||||
@ -319,4 +323,71 @@ int quic_retry_token_check(struct quic_rx_packet *pkt,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* QUIC client only function.
|
||||||
|
* Check the integrity tag of <pkt> retry packet received on <qc> connection
|
||||||
|
* with <beg> and <end> as packet payload delimiters. <pos> is the retry token position.
|
||||||
|
* Return 1 if succeeded, 0 if not.
|
||||||
|
*/
|
||||||
|
int quic_retry_packet_check(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
||||||
|
const unsigned char *beg, const unsigned char *end,
|
||||||
|
const unsigned char *pos, size_t *retry_token_len)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
unsigned char tag[QUIC_TLS_TAG_LEN];
|
||||||
|
ssize_t toklen;
|
||||||
|
|
||||||
|
TRACE_ENTER(QUIC_EV_CONN_SPKT, qc);
|
||||||
|
|
||||||
|
if (!pkt->version) {
|
||||||
|
TRACE_PROTO("retry packet without version", QUIC_EV_CONN_SPKT);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end - beg <= QUIC_LONG_PACKET_MINLEN +
|
||||||
|
pkt->scid.len + pkt->dcid.len + QUIC_TLS_TAG_LEN ||
|
||||||
|
end - pos <= QUIC_TLS_TAG_LEN) {
|
||||||
|
TRACE_PROTO("Too short retry packet", QUIC_EV_CONN_SPKT);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quic_tls_generate_retry_integrity_tag(qc->odcid.data, qc->odcid.len,
|
||||||
|
beg, end - beg - QUIC_TLS_TAG_LEN,
|
||||||
|
tag, pkt->version)) {
|
||||||
|
TRACE_PROTO("retry integrity tag faild", QUIC_EV_CONN_SPKT, qc);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(tag, end - QUIC_TLS_TAG_LEN, QUIC_TLS_TAG_LEN) != 0) {
|
||||||
|
TRACE_PROTO("retry integrity tag mismatch", QUIC_EV_CONN_SPKT, qc);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
toklen = end - pos - QUIC_TLS_TAG_LEN;
|
||||||
|
if (toklen <= 0 || toklen > QUIC_RETRY_TOKEN_MAXLEN) {
|
||||||
|
TRACE_PROTO("wrong retry token size", QUIC_EV_CONN_SPKT, qc);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*retry_token_len = (size_t)toklen;
|
||||||
|
ret = 1;
|
||||||
|
leave:
|
||||||
|
TRACE_LEAVE(QUIC_EV_CONN_SPKT, qc);
|
||||||
|
return ret;
|
||||||
|
err:
|
||||||
|
TRACE_DEVEL("leaving on error", QUIC_EV_CONN_SPKT, qc);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create_quic_retry_token_pool(void)
|
||||||
|
{
|
||||||
|
pool_head_quic_retry_token =
|
||||||
|
create_pool("quic_retry_token", QUIC_RETRY_TOKEN_MAXLEN, MEM_F_SHARED|MEM_F_EXACT);
|
||||||
|
if (!pool_head_quic_retry_token) {
|
||||||
|
ha_warning("error on QUIC retry token buffer pool allocation.\n");
|
||||||
|
return ERR_FATAL|ERR_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_POST_CHECK(create_quic_retry_token_pool);
|
||||||
|
@ -1191,7 +1191,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
|||||||
if (qc->ipktns && !quic_tls_pktns_is_dcd(qc, qc->ipktns)) {
|
if (qc->ipktns && !quic_tls_pktns_is_dcd(qc, qc->ipktns)) {
|
||||||
/* Discard the handshake packet number space. */
|
/* Discard the handshake packet number space. */
|
||||||
TRACE_PROTO("discarding Initial pktns", QUIC_EV_CONN_PRSHPKT, qc);
|
TRACE_PROTO("discarding Initial pktns", QUIC_EV_CONN_PRSHPKT, qc);
|
||||||
quic_pktns_discard(qc->ipktns, qc);
|
quic_pktns_discard(qc->ipktns, qc, 0);
|
||||||
qc_set_timer(qc);
|
qc_set_timer(qc);
|
||||||
qc_el_rx_pkts_del(qc->iel);
|
qc_el_rx_pkts_del(qc->iel);
|
||||||
qc_release_pktns_frms(qc, qc->ipktns);
|
qc_release_pktns_frms(qc, qc->ipktns);
|
||||||
@ -1967,8 +1967,7 @@ static int quic_rx_pkt_parse(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Retry of Version Negotiation packets are only sent by servers */
|
/* Retry of Version Negotiation packets are only sent by servers */
|
||||||
if (pkt->type == QUIC_PACKET_TYPE_RETRY ||
|
if (l && (pkt->type == QUIC_PACKET_TYPE_RETRY || (pkt->version && !pkt->version->num))) {
|
||||||
(pkt->version && !pkt->version->num)) {
|
|
||||||
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
|
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
@ -1987,10 +1986,10 @@ static int quic_rx_pkt_parse(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
|||||||
goto drop_silent;
|
goto drop_silent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For Initial packets, and for servers (QUIC clients connections),
|
|
||||||
* there is no Initial connection IDs storage.
|
|
||||||
*/
|
|
||||||
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
|
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
|
||||||
|
/* For Initial packets, and for servers (QUIC clients connections),
|
||||||
|
* there is no Initial connection IDs storage.
|
||||||
|
*/
|
||||||
uint64_t token_len;
|
uint64_t token_len;
|
||||||
|
|
||||||
if (!quic_dec_int(&token_len, (const unsigned char **)&pos, end) ||
|
if (!quic_dec_int(&token_len, (const unsigned char **)&pos, end) ||
|
||||||
@ -2011,6 +2010,47 @@ static int quic_rx_pkt_parse(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
|||||||
pkt->token_len = token_len;
|
pkt->token_len = token_len;
|
||||||
pos += pkt->token_len;
|
pos += pkt->token_len;
|
||||||
}
|
}
|
||||||
|
else if (pkt->type == QUIC_PACKET_TYPE_RETRY) {
|
||||||
|
if (!quic_retry_packet_check(qc, pkt, beg, end, pos, &qc->retry_token_len))
|
||||||
|
/* TODO: should close the connection? */
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
qc->retry_token = pool_alloc(pool_head_quic_retry_token);
|
||||||
|
if (!qc->retry_token) {
|
||||||
|
TRACE_ERROR("retry token allocation failed", QUIC_EV_CONN_LPKT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(qc->retry_token, pos, qc->retry_token_len);
|
||||||
|
/* Save the peer Retry source connection ID into the connection ODCID.
|
||||||
|
* This is also this connection DCID (or even the first ODCID value).
|
||||||
|
* It can be erased because used only to check the retry integrity
|
||||||
|
* tag. Then, it will be matched against the retry_source_connection_id
|
||||||
|
* transport parameter which will be sent by the server.
|
||||||
|
*/
|
||||||
|
memcpy(qc->odcid.data, pkt->scid.data, pkt->scid.len);
|
||||||
|
qc->odcid.len = pkt->scid.len;
|
||||||
|
/* Copy the peer scid to be the destination of the next Initial packet */
|
||||||
|
memcpy(qc->dcid.data, pkt->scid.data, pkt->scid.len);
|
||||||
|
qc->dcid.len = pkt->scid.len;
|
||||||
|
/* Initial packet number space discarding without releasing
|
||||||
|
* the existing frames (not already sent).
|
||||||
|
*/
|
||||||
|
quic_pktns_discard(qc->ipktns, qc, 1);
|
||||||
|
qc_set_timer(qc);
|
||||||
|
qc_el_rx_pkts_del(qc->iel);
|
||||||
|
/* Reset the DISCARDED flag for Initial packet number space */
|
||||||
|
qc->flags &= ~QUIC_FL_CONN_IPKTNS_DCD;
|
||||||
|
/* Change the Initial TLS cryptographic context */
|
||||||
|
quic_tls_ctx_secs_free(&qc->iel->tls_ctx);
|
||||||
|
if (!qc_new_isecs(qc, &qc->iel->tls_ctx, qc->original_version,
|
||||||
|
qc->dcid.data, qc->dcid.len, !!l))
|
||||||
|
goto drop_silent;
|
||||||
|
|
||||||
|
tasklet_wakeup(qc->wait_event.tasklet);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto drop_silent;
|
||||||
|
}
|
||||||
else if (pkt->type != QUIC_PACKET_TYPE_0RTT) {
|
else if (pkt->type != QUIC_PACKET_TYPE_0RTT) {
|
||||||
if (pkt->dcid.len != QUIC_HAP_CID_LEN) {
|
if (pkt->dcid.len != QUIC_HAP_CID_LEN) {
|
||||||
TRACE_PROTO("Packet dropped",
|
TRACE_PROTO("Packet dropped",
|
||||||
|
@ -95,7 +95,7 @@ void quic_pktns_release(struct quic_conn *qc, struct quic_pktns **pktns)
|
|||||||
if (!*pktns)
|
if (!*pktns)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
quic_pktns_tx_pkts_release(*pktns, qc);
|
quic_pktns_tx_pkts_release(*pktns, qc, 0);
|
||||||
qc_release_pktns_frms(qc, *pktns);
|
qc_release_pktns_frms(qc, *pktns);
|
||||||
quic_free_arngs(qc, &(*pktns)->rx.arngs);
|
quic_free_arngs(qc, &(*pktns)->rx.arngs);
|
||||||
LIST_DEL_INIT(&(*pktns)->list);
|
LIST_DEL_INIT(&(*pktns)->list);
|
||||||
@ -1005,14 +1005,15 @@ int quic_tls_derive_token_secret(const EVP_MD *md,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generate the AEAD tag for the Retry packet <pkt> of <pkt_len> bytes and
|
/* Generate the AEAD tag for the Retry packet <pkt> of <pkt_len> bytes and
|
||||||
* write it to <tag>. The tag is written just after the <pkt> area. It should
|
* write it to <tag>. The tag is written at <tag> address. It should
|
||||||
* be at least 16 bytes longs. <odcid> is the CID of the Initial packet
|
* be at least 16 bytes longs. <odcid> is the CID of the Initial packet
|
||||||
* received which triggers the Retry.
|
* received which triggers the Retry.
|
||||||
*
|
*
|
||||||
* Returns non-zero on success else zero.
|
* Returns non-zero on success else zero.
|
||||||
*/
|
*/
|
||||||
int quic_tls_generate_retry_integrity_tag(unsigned char *odcid, unsigned char odcid_len,
|
int quic_tls_generate_retry_integrity_tag(unsigned char *odcid, unsigned char odcid_len,
|
||||||
unsigned char *pkt, size_t pkt_len,
|
const unsigned char *pkt, size_t pkt_len,
|
||||||
|
unsigned char *tag,
|
||||||
const struct quic_version *qv)
|
const struct quic_version *qv)
|
||||||
{
|
{
|
||||||
const EVP_CIPHER *evp = EVP_aes_128_gcm();
|
const EVP_CIPHER *evp = EVP_aes_128_gcm();
|
||||||
@ -1020,8 +1021,6 @@ int quic_tls_generate_retry_integrity_tag(unsigned char *odcid, unsigned char od
|
|||||||
|
|
||||||
/* encryption buffer - not used as only AEAD tag generation is proceed */
|
/* encryption buffer - not used as only AEAD tag generation is proceed */
|
||||||
unsigned char *out = NULL;
|
unsigned char *out = NULL;
|
||||||
/* address to store the AEAD tag */
|
|
||||||
unsigned char *tag = pkt + pkt_len;
|
|
||||||
int outlen, ret = 0;
|
int outlen, ret = 0;
|
||||||
|
|
||||||
ctx = EVP_CIPHER_CTX_new();
|
ctx = EVP_CIPHER_CTX_new();
|
||||||
|
@ -400,7 +400,13 @@ quic_transport_param_decode(struct quic_transport_params *p, int server,
|
|||||||
if (!server)
|
if (!server)
|
||||||
return QUIC_TP_DEC_ERR_INVAL;
|
return QUIC_TP_DEC_ERR_INVAL;
|
||||||
|
|
||||||
/* TODO implement parsing for client side */
|
if (len > sizeof p->retry_source_connection_id.data)
|
||||||
|
return QUIC_TP_DEC_ERR_TRUNC;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
memcpy(p->retry_source_connection_id.data, *buf, len);
|
||||||
|
p->retry_source_connection_id.len = len;
|
||||||
|
*buf += len;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*buf += len;
|
*buf += len;
|
||||||
@ -753,6 +759,12 @@ int quic_transport_params_store(struct quic_conn *qc, int server,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server && (qc->odcid.len != tx_params->retry_source_connection_id.len ||
|
||||||
|
memcmp(qc->odcid.data, tx_params->retry_source_connection_id.data, qc->odcid.len) != 0)) {
|
||||||
|
TRACE_ERROR("retry_source_connection_id mismatch", QUIC_EV_TRANSP_PARAMS, qc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the connection from transport parameters received */
|
/* Update the connection from transport parameters received */
|
||||||
if (tx_params->version_information.negotiated_version &&
|
if (tx_params->version_information.negotiated_version &&
|
||||||
tx_params->version_information.negotiated_version != qc->original_version)
|
tx_params->version_information.negotiated_version != qc->original_version)
|
||||||
|
@ -1304,7 +1304,7 @@ int send_retry(int fd, struct sockaddr_storage *addr,
|
|||||||
/* token integrity tag */
|
/* token integrity tag */
|
||||||
if ((sizeof(buf) - i < QUIC_TLS_TAG_LEN) ||
|
if ((sizeof(buf) - i < QUIC_TLS_TAG_LEN) ||
|
||||||
!quic_tls_generate_retry_integrity_tag(pkt->dcid.data,
|
!quic_tls_generate_retry_integrity_tag(pkt->dcid.data,
|
||||||
pkt->dcid.len, buf, i, qv)) {
|
pkt->dcid.len, buf, i, buf + i, qv)) {
|
||||||
TRACE_ERROR("quic_tls_generate_retry_integrity_tag() failed", QUIC_EV_CONN_TXPKT);
|
TRACE_ERROR("quic_tls_generate_retry_integrity_tag() failed", QUIC_EV_CONN_TXPKT);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1809,10 +1809,14 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end,
|
|||||||
|
|
||||||
/* Encode the token length (0) for an Initial packet. */
|
/* Encode the token length (0) for an Initial packet. */
|
||||||
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
|
if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
|
||||||
if (end <= pos)
|
if (!quic_enc_int(&pos, end, qc->retry_token_len) ||
|
||||||
|
end - pos <= qc->retry_token_len)
|
||||||
goto no_room;
|
goto no_room;
|
||||||
|
|
||||||
*pos++ = 0;
|
if (qc->retry_token_len) {
|
||||||
|
memcpy(pos, qc->retry_token, qc->retry_token_len);
|
||||||
|
pos += qc->retry_token_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
head_len = pos - beg;
|
head_len = pos - beg;
|
||||||
|
Loading…
Reference in New Issue
Block a user