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
This commit is contained in:
Emeric Brun 2023-07-11 14:57:54 +02:00 committed by Amaury Denoyelle
parent cc0a4fa0cc
commit 072e774939

View File

@ -6313,7 +6313,8 @@ static int send_stateless_reset(struct listener *l, struct sockaddr_storage *dst
*/ */
static int quic_generate_retry_token_aad(unsigned char *aad, static int quic_generate_retry_token_aad(unsigned char *aad,
uint32_t version, uint32_t version,
const struct quic_cid *cid, const struct quic_cid *dcid,
const struct quic_cid *scid,
const struct sockaddr_storage *addr) const struct sockaddr_storage *addr)
{ {
unsigned char *p; unsigned char *p;
@ -6321,9 +6322,11 @@ static int quic_generate_retry_token_aad(unsigned char *aad,
p = aad; p = aad;
*(uint32_t *)p = htonl(version); *(uint32_t *)p = htonl(version);
p += sizeof version; p += sizeof version;
memcpy(p, dcid->data, dcid->len);
p += dcid->len;
p += quic_saddr_cpy(p, addr); p += quic_saddr_cpy(p, addr);
memcpy(p, cid->data, cid->len); memcpy(p, scid->data, scid->len);
p += cid->len; p += scid->len;
return p - aad; return p - aad;
} }
@ -6338,13 +6341,15 @@ static int quic_generate_retry_token_aad(unsigned char *aad,
static int quic_generate_retry_token(unsigned char *token, size_t len, static int quic_generate_retry_token(unsigned char *token, size_t len,
const uint32_t version, const uint32_t version,
const struct quic_cid *odcid, const struct quic_cid *odcid,
const struct quic_cid *scid,
const struct quic_cid *dcid, const struct quic_cid *dcid,
struct sockaddr_storage *addr) struct sockaddr_storage *addr)
{ {
int ret = 0; int ret = 0;
unsigned char *p; unsigned char *p;
unsigned char aad[sizeof(uint32_t) + sizeof(in_port_t) + unsigned char aad[sizeof(uint32_t) + QUIC_CID_MAXLEN +
sizeof(struct in6_addr) + QUIC_CID_MAXLEN]; sizeof(in_port_t) + sizeof(struct in6_addr) +
QUIC_CID_MAXLEN];
size_t aadlen; size_t aadlen;
unsigned char salt[QUIC_RETRY_TOKEN_SALTLEN]; unsigned char salt[QUIC_RETRY_TOKEN_SALTLEN];
unsigned char key[QUIC_TLS_KEY_LEN]; unsigned char key[QUIC_TLS_KEY_LEN];
@ -6364,7 +6369,7 @@ static int quic_generate_retry_token(unsigned char *token, size_t len,
if (1 + odcid->len + 1 + sizeof(timestamp) + QUIC_TLS_TAG_LEN + QUIC_RETRY_TOKEN_SALTLEN > len) if (1 + odcid->len + 1 + sizeof(timestamp) + QUIC_TLS_TAG_LEN + QUIC_RETRY_TOKEN_SALTLEN > len)
goto err; 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 */ /* TODO: RAND_bytes() should be replaced */
if (RAND_bytes(salt, sizeof salt) != 1) { if (RAND_bytes(salt, sizeof salt) != 1) {
TRACE_ERROR("RAND_bytes()", QUIC_EV_CONN_TXPKT); TRACE_ERROR("RAND_bytes()", QUIC_EV_CONN_TXPKT);
@ -6437,8 +6442,9 @@ static int quic_retry_token_check(struct quic_rx_packet *pkt,
unsigned char *token = pkt->token; unsigned char *token = pkt->token;
const uint64_t tokenlen = pkt->token_len; const uint64_t tokenlen = pkt->token_len;
unsigned char buf[128]; unsigned char buf[128];
unsigned char aad[sizeof(uint32_t) + sizeof(in_port_t) + unsigned char aad[sizeof(uint32_t) + QUIC_CID_MAXLEN +
sizeof(struct in6_addr) + QUIC_CID_MAXLEN]; sizeof(in_port_t) + sizeof(struct in6_addr) +
QUIC_CID_MAXLEN];
size_t aadlen; size_t aadlen;
const unsigned char *salt; const unsigned char *salt;
unsigned char key[QUIC_TLS_KEY_LEN]; unsigned char key[QUIC_TLS_KEY_LEN];
@ -6479,7 +6485,7 @@ static int quic_retry_token_check(struct quic_rx_packet *pkt,
goto err; 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; salt = token + tokenlen - QUIC_RETRY_TOKEN_SALTLEN;
if (!quic_tls_derive_retry_token_secret(EVP_sha256(), key, sizeof key, iv, sizeof iv, if (!quic_tls_derive_retry_token_secret(EVP_sha256(), key, sizeof key, iv, sizeof iv,
salt, QUIC_RETRY_TOKEN_SALTLEN, sec, seclen)) { salt, QUIC_RETRY_TOKEN_SALTLEN, sec, seclen)) {
@ -6563,7 +6569,7 @@ static int send_retry(int fd, struct sockaddr_storage *addr,
/* token */ /* token */
if (!(token_len = quic_generate_retry_token(&buf[i], sizeof(buf) - i, qv->num, 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); TRACE_ERROR("quic_generate_retry_token() failed", QUIC_EV_CONN_TXPKT);
goto out; goto out;
} }