BUG/MEDIUM: quic: missing check of dcid for init pkt including a token
RFC 9000, 17.2.5.1:
"The client MUST use the value from the Source Connection ID
field of the Retry packet in the Destination Connection ID
field of subsequent packets that it sends."
There was no control of this and we could accept a different
dcid on init packets containing a valid token.
The randomized value used as new scid on retry packets is now
added in the aad used to encode the token. This way the token
will appear as invalid if the dcid missmatch the scid of
the previous retry packet.
This should be backported until v2.6
(cherry picked from commit 072e77493961a06b89f853f4ab2bbf0e9cf3eff7)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/src/quic_conn.c b/src/quic_conn.c
index 443dcbc..ecb4845 100644
--- a/src/quic_conn.c
+++ b/src/quic_conn.c
@@ -6357,7 +6357,8 @@
*/
static int quic_generate_retry_token_aad(unsigned char *aad,
uint32_t version,
- const struct quic_cid *cid,
+ const struct quic_cid *dcid,
+ const struct quic_cid *scid,
const struct sockaddr_storage *addr)
{
unsigned char *p;
@@ -6365,9 +6366,11 @@
p = aad;
*(uint32_t *)p = htonl(version);
p += sizeof version;
+ memcpy(p, dcid->data, dcid->len);
+ p += dcid->len;
p += quic_saddr_cpy(p, addr);
- memcpy(p, cid->data, cid->len);
- p += cid->len;
+ memcpy(p, scid->data, scid->len);
+ p += scid->len;
return p - aad;
}
@@ -6382,13 +6385,15 @@
static int quic_generate_retry_token(unsigned char *token, size_t len,
const uint32_t version,
const struct quic_cid *odcid,
+ const struct quic_cid *scid,
const struct quic_cid *dcid,
struct sockaddr_storage *addr)
{
int ret = 0;
unsigned char *p;
- unsigned char aad[sizeof(uint32_t) + sizeof(in_port_t) +
- sizeof(struct in6_addr) + QUIC_CID_MAXLEN];
+ unsigned char aad[sizeof(uint32_t) + QUIC_CID_MAXLEN +
+ sizeof(in_port_t) + sizeof(struct in6_addr) +
+ QUIC_CID_MAXLEN];
size_t aadlen;
unsigned char salt[QUIC_RETRY_TOKEN_SALTLEN];
unsigned char key[QUIC_TLS_KEY_LEN];
@@ -6408,7 +6413,7 @@
if (1 + odcid->len + 1 + sizeof(timestamp) + QUIC_TLS_TAG_LEN + QUIC_RETRY_TOKEN_SALTLEN > len)
goto err;
- aadlen = quic_generate_retry_token_aad(aad, version, dcid, addr);
+ aadlen = quic_generate_retry_token_aad(aad, version, scid, dcid, addr);
/* TODO: RAND_bytes() should be replaced */
if (RAND_bytes(salt, sizeof salt) != 1) {
TRACE_ERROR("RAND_bytes()", QUIC_EV_CONN_TXPKT);
@@ -6481,8 +6486,9 @@
unsigned char *token = pkt->token;
const uint64_t tokenlen = pkt->token_len;
unsigned char buf[128];
- unsigned char aad[sizeof(uint32_t) + sizeof(in_port_t) +
- sizeof(struct in6_addr) + QUIC_CID_MAXLEN];
+ unsigned char aad[sizeof(uint32_t) + QUIC_CID_MAXLEN +
+ sizeof(in_port_t) + sizeof(struct in6_addr) +
+ QUIC_CID_MAXLEN];
size_t aadlen;
const unsigned char *salt;
unsigned char key[QUIC_TLS_KEY_LEN];
@@ -6523,7 +6529,7 @@
goto err;
}
- aadlen = quic_generate_retry_token_aad(aad, qv->num, &pkt->scid, &dgram->saddr);
+ aadlen = quic_generate_retry_token_aad(aad, qv->num, &pkt->dcid, &pkt->scid, &dgram->saddr);
salt = token + tokenlen - QUIC_RETRY_TOKEN_SALTLEN;
if (!quic_tls_derive_retry_token_secret(EVP_sha256(), key, sizeof key, iv, sizeof iv,
salt, QUIC_RETRY_TOKEN_SALTLEN, sec, seclen)) {
@@ -6607,7 +6613,7 @@
/* token */
if (!(token_len = quic_generate_retry_token(&buf[i], sizeof(buf) - i, qv->num,
- &pkt->dcid, &pkt->scid, addr))) {
+ &pkt->dcid, &scid, &pkt->scid, addr))) {
TRACE_ERROR("quic_generate_retry_token() failed", QUIC_EV_CONN_TXPKT);
goto out;
}