summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2022-10-31 16:15:26 +0100
committerHugo Landau <hlandau@openssl.org>2023-01-13 14:20:10 +0100
commit70d45893d0decc1ac2431a20db6750bc70cbaea5 (patch)
tree686f50f6f6860f5dc86808ed1f2af17e83532817
parentQUIC RX: Do not handle auto-discard of Initial EL inside the QRX (diff)
downloadopenssl-70d45893d0decc1ac2431a20db6750bc70cbaea5.tar.xz
openssl-70d45893d0decc1ac2431a20db6750bc70cbaea5.zip
QUIC Wire Encoding: Support Retry Integrity Tag Calculation
This adds support for calculating and verifying retry integrity tags. In order to support this, an 'unused' field is added to the QUIC packet header structure so we can ensure that the serialization of the header is bit-for-bit identical to what was decoded. Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19703)
-rw-r--r--include/internal/quic_wire_pkt.h55
-rw-r--r--ssl/quic/quic_wire_pkt.c132
-rw-r--r--test/quic_record_test.c44
-rw-r--r--test/quic_record_test_util.h1
-rw-r--r--test/quic_wire_test.c56
5 files changed, 283 insertions, 5 deletions
diff --git a/include/internal/quic_wire_pkt.h b/include/internal/quic_wire_pkt.h
index 34e95ba7b6..daf1785591 100644
--- a/include/internal/quic_wire_pkt.h
+++ b/include/internal/quic_wire_pkt.h
@@ -322,6 +322,14 @@ typedef struct quic_pkt_hdr_st {
*/
unsigned int fixed :1;
+ /*
+ * The unused bits in the low 4 bits of a Retry packet header's first byte.
+ * This is used to ensure that Retry packets have the same bit-for-bit
+ * representation in their header when decoding and encoding them again.
+ * This is necessary to validate Retry packet headers.
+ */
+ unsigned int unused :4;
+
/* [L] Version field. Valid if (type != 1RTT). */
uint32_t version;
@@ -537,4 +545,51 @@ int ossl_quic_wire_determine_pn_len(QUIC_PN pn, QUIC_PN largest_acked);
int ossl_quic_wire_encode_pkt_hdr_pn(QUIC_PN pn,
unsigned char *enc_pn,
size_t enc_pn_len);
+
+/*
+ * Retry Integrity Tags
+ * ====================
+ */
+
+#define QUIC_RETRY_INTEGRITY_TAG_LEN 16
+
+/*
+ * Validate a retry integrity tag. Returns 1 if the tag is valid.
+ *
+ * Must be called on a hdr with a type of QUIC_PKT_TYPE_RETRY with a valid data
+ * pointer.
+ *
+ * client_initial_dcid must be the original DCID used by the client in its first
+ * Initial packet, as this is used to calculate the Retry Integrity Tag.
+ *
+ * Returns 0 if the tag is invalid, if called on any other type of packet or if
+ * the body is too short.
+ */
+int ossl_quic_validate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
+ const char *propq,
+ const QUIC_PKT_HDR *hdr,
+ const QUIC_CONN_ID *client_initial_dcid);
+
+/*
+ * Calculates a retry integrity tag. Returns 0 on error, for example if hdr does
+ * not have a type of QUIC_PKT_TYPE_RETRY.
+ *
+ * client_initial_dcid must be the original DCID used by the client in its first
+ * Initial packet, as this is used to calculate the Retry Integrity Tag.
+ *
+ * tag must point to a buffer of QUIC_RETRY_INTEGRITY_TAG_LEN bytes in size.
+ *
+ * Note that hdr->data must point to the Retry packet body, and hdr->len must
+ * include the space for the Retry Integrity Tag. (This means that you can
+ * easily fill in a tag in a Retry packet you are generating by calling this
+ * function and passing (hdr->data + hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN) as
+ * the tag argument.) This function fails if hdr->len is too short to contain a
+ * Retry Integrity Tag.
+ */
+int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
+ const char *propq,
+ const QUIC_PKT_HDR *hdr,
+ const QUIC_CONN_ID *client_initial_dcid,
+ unsigned char *tag);
+
#endif
diff --git a/ssl/quic/quic_wire_pkt.c b/ssl/quic/quic_wire_pkt.c
index a4fdc7bf53..de3466daa2 100644
--- a/ssl/quic/quic_wire_pkt.c
+++ b/ssl/quic/quic_wire_pkt.c
@@ -181,6 +181,7 @@ int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt,
return 0;
hdr->partial = partial;
+ hdr->unused = 0;
if ((b0 & 0x80) == 0) {
/* Short header. */
@@ -353,6 +354,9 @@ int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt,
/* Retry packets are always fully decoded. */
hdr->partial = 0;
+ /* Unused bits in Retry header. */
+ hdr->unused = b0 & 0x0f;
+
/* Fields not used in Retry packets. */
memset(hdr->pn, 0, sizeof(hdr->pn));
@@ -490,6 +494,8 @@ int ossl_quic_wire_encode_pkt_hdr(WPACKET *pkt,
b0 |= 0x40; /* fixed */
if (ossl_quic_pkt_type_has_pn(hdr->type))
b0 |= hdr->pn_len - 1;
+ if (hdr->type == QUIC_PKT_TYPE_RETRY)
+ b0 |= hdr->unused;
if (!WPACKET_put_bytes_u8(pkt, b0)
|| !WPACKET_put_bytes_u32(pkt, hdr->version)
@@ -503,7 +509,7 @@ int ossl_quic_wire_encode_pkt_hdr(WPACKET *pkt,
if (hdr->type == QUIC_PKT_TYPE_VERSION_NEG
|| hdr->type == QUIC_PKT_TYPE_RETRY) {
- if (!WPACKET_reserve_bytes(pkt, hdr->len, NULL))
+ if (hdr->len > 0 && !WPACKET_reserve_bytes(pkt, hdr->len, NULL))
return 0;
return 1;
@@ -521,7 +527,7 @@ int ossl_quic_wire_encode_pkt_hdr(WPACKET *pkt,
return 0;
}
- if (!WPACKET_reserve_bytes(pkt, hdr->len, NULL))
+ if (hdr->len > 0 && !WPACKET_reserve_bytes(pkt, hdr->len, NULL))
return 0;
off_sample = off_pn + 4;
@@ -745,3 +751,125 @@ int ossl_quic_wire_encode_pkt_hdr_pn(QUIC_PN pn,
return 1;
}
+
+int ossl_quic_validate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
+ const char *propq,
+ const QUIC_PKT_HDR *hdr,
+ const QUIC_CONN_ID *client_initial_dcid)
+{
+ unsigned char expected_tag[QUIC_RETRY_INTEGRITY_TAG_LEN];
+ const unsigned char *actual_tag;
+
+ if (hdr == NULL || hdr->len < QUIC_RETRY_INTEGRITY_TAG_LEN)
+ return 0;
+
+ if (!ossl_quic_calculate_retry_integrity_tag(libctx, propq,
+ hdr, client_initial_dcid,
+ expected_tag))
+ return 0;
+
+ actual_tag = hdr->data + hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN;
+
+ return !CRYPTO_memcmp(expected_tag, actual_tag,
+ QUIC_RETRY_INTEGRITY_TAG_LEN);
+}
+
+/* RFC 9001 s. 5.8 */
+static const unsigned char retry_integrity_key[] = {
+ 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a,
+ 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e
+};
+
+static const unsigned char retry_integrity_nonce[] = {
+ 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2,
+ 0x23, 0x98, 0x25, 0xbb
+};
+
+int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
+ const char *propq,
+ const QUIC_PKT_HDR *hdr,
+ const QUIC_CONN_ID *client_initial_dcid,
+ unsigned char *tag)
+{
+ EVP_CIPHER *cipher = NULL;
+ EVP_CIPHER_CTX *cctx = NULL;
+ int ok = 0, l = 0, l2 = 0, wpkt_valid = 0;
+ WPACKET wpkt;
+ /* Worst case length of the Retry Psuedo-Packet header is 68 bytes. */
+ unsigned char buf[128];
+ QUIC_PKT_HDR hdr2;
+ size_t hdr_enc_len = 0;
+
+ if (hdr->type != QUIC_PKT_TYPE_RETRY || hdr->version == 0
+ || hdr->len < QUIC_RETRY_INTEGRITY_TAG_LEN
+ || hdr->data == NULL
+ || client_initial_dcid == NULL || tag == NULL
+ || client_initial_dcid->id_len > QUIC_MAX_CONN_ID_LEN)
+ goto err;
+
+ /*
+ * Do not reserve packet body in WPACKET. Retry packet header
+ * does not contain a Length field so this does not affect
+ * the serialized packet header.
+ */
+ hdr2 = *hdr;
+ hdr2.len = 0;
+
+ /* Assemble retry psuedo-packet. */
+ if (!WPACKET_init_static_len(&wpkt, buf, sizeof(buf), 0))
+ goto err;
+
+ wpkt_valid = 1;
+
+ /* Prepend original DCID to the packet. */
+ if (!WPACKET_put_bytes_u8(&wpkt, client_initial_dcid->id_len)
+ || !WPACKET_memcpy(&wpkt, client_initial_dcid->id,
+ client_initial_dcid->id_len))
+ goto err;
+
+ /* Encode main retry header. */
+ if (!ossl_quic_wire_encode_pkt_hdr(&wpkt, hdr2.dst_conn_id.id_len,
+ &hdr2, NULL))
+ goto err;
+
+ if (!WPACKET_get_total_written(&wpkt, &hdr_enc_len))
+ return 0;
+
+ /* Create and initialise cipher context. */
+ if ((cipher = EVP_CIPHER_fetch(libctx, "AES-128-GCM", propq)) == NULL)
+ goto err;
+
+ if ((cctx = EVP_CIPHER_CTX_new()) == NULL)
+ goto err;
+
+ if (!EVP_CipherInit_ex(cctx, cipher, NULL,
+ retry_integrity_key, retry_integrity_nonce, /*enc=*/1))
+ goto err;
+
+ /* Feed packet header as AAD data. */
+ if (EVP_CipherUpdate(cctx, NULL, &l, buf, hdr_enc_len) != 1)
+ return 0;
+
+ /* Feed packet body as AAD data. */
+ if (EVP_CipherUpdate(cctx, NULL, &l, hdr->data,
+ hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN) != 1)
+ return 0;
+
+ /* Finalise and get tag. */
+ if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1)
+ return 0;
+
+ if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG,
+ QUIC_RETRY_INTEGRITY_TAG_LEN,
+ tag) != 1)
+ return 0;
+
+ ok = 1;
+err:
+ EVP_CIPHER_free(cipher);
+ EVP_CIPHER_CTX_free(cctx);
+ if (wpkt_valid)
+ WPACKET_finish(&wpkt);
+
+ return ok;
+}
diff --git a/test/quic_record_test.c b/test/quic_record_test.c
index f02abb25b8..1664cd2afc 100644
--- a/test/quic_record_test.c
+++ b/test/quic_record_test.c
@@ -150,7 +150,7 @@ static const QUIC_CONN_ID rx_script_1_dcid = {
static const QUIC_PKT_HDR rx_script_1_expect_hdr = {
QUIC_PKT_TYPE_INITIAL,
- 0, 0, 2, 0, 1, 1, { 0, {0} },
+ 0, 0, 2, 0, 1, 0, 1, { 0, {0} },
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } },
{ 0, 1, 0, 0 },
NULL, 0,
@@ -186,7 +186,7 @@ static const unsigned char rx_script_2_body[] = {
static const QUIC_PKT_HDR rx_script_2_expect_hdr = {
QUIC_PKT_TYPE_1RTT,
- 0, 0, 3, 0, 1, 0, {0, {0}}, {0, {0}},
+ 0, 0, 3, 0, 1, 0, 0, {0, {0}}, {0, {0}},
{0x00, 0xbf, 0xf4, 0x00},
NULL, 0,
1, NULL
@@ -222,6 +222,7 @@ static const QUIC_PKT_HDR rx_script_3_expect_hdr = {
0, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{12, {0x35, 0x3c, 0x1b, 0x97, 0xca, 0xf8, /* SCID */
@@ -274,6 +275,7 @@ static const QUIC_PKT_HDR rx_script_4_expect_hdr = {
0, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
1, /* Version */
{0, {0}}, /* DCID */
{4, {0xad, 0x15, 0x3f, 0xae}}, /* SCID */
@@ -455,6 +457,7 @@ static const QUIC_PKT_HDR rx_script_5a_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
1, /* Version */
{0, {0}}, /* DCID */
{4, {0x83, 0xd0, 0x0a, 0x27}}, /* SCID */
@@ -511,6 +514,7 @@ static const QUIC_PKT_HDR rx_script_5b_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
1, /* Version */
{0, {0}}, /* DCID */
{4, {0x83, 0xd0, 0x0a, 0x27}}, /* SCID */
@@ -584,6 +588,7 @@ static const QUIC_PKT_HDR rx_script_5c_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -818,6 +823,7 @@ static const QUIC_PKT_HDR rx_script_6a_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
1, /* Version */
{0, {0}}, /* DCID */
{4, {0x36, 0xf4, 0x75, 0x2d}}, /* SCID */
@@ -872,6 +878,7 @@ static const QUIC_PKT_HDR rx_script_6b_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
1, /* Version */
{0, {0}}, /* DCID */
{4, {0x36, 0xf4, 0x75, 0x2d}}, /* SCID */
@@ -946,6 +953,7 @@ static const QUIC_PKT_HDR rx_script_6c_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1174,6 +1182,7 @@ static const QUIC_PKT_HDR rx_script_7a_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
1, /* Version */
{0, {0}}, /* DCID */
{4, {0x03, 0x45, 0x0c, 0x7a}}, /* SCID */
@@ -1229,6 +1238,7 @@ static const QUIC_PKT_HDR rx_script_7b_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
1, /* Version */
{0, {0}}, /* DCID */
{4, {0x03, 0x45, 0x0c, 0x7a}}, /* SCID */
@@ -1302,6 +1312,7 @@ static const QUIC_PKT_HDR rx_script_7c_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1402,6 +1413,7 @@ static const QUIC_PKT_HDR rx_script_8a_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1433,6 +1445,7 @@ static const QUIC_PKT_HDR rx_script_8b_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1463,6 +1476,7 @@ static const QUIC_PKT_HDR rx_script_8c_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1494,6 +1508,7 @@ static const QUIC_PKT_HDR rx_script_8d_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1525,6 +1540,7 @@ static const QUIC_PKT_HDR rx_script_8e_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1553,6 +1569,7 @@ static const QUIC_PKT_HDR rx_script_8f_expect_hdr = {
2, /* PN Length */
0, /* Partial */
1, /* Fixed */
+ 0, /* Unused */
0, /* Version */
{0, {0}}, /* DCID */
{0, {0}}, /* SCID */
@@ -1969,6 +1986,7 @@ static const struct pkt_hdr_test pkt_hdr_test_1 = {
2, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
1, /* version */
{ 0, {0} }, /* DCID */
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } }, /* SCID */
@@ -2015,6 +2033,7 @@ static const struct pkt_hdr_test pkt_hdr_test_2 = {
2, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
1, /* version */
{ 0, {0} }, /* DCID */
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } }, /* SCID */
@@ -2062,6 +2081,7 @@ static const struct pkt_hdr_test pkt_hdr_test_3 = {
2, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
1, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } }, /* SCID */
@@ -2103,6 +2123,7 @@ static const struct pkt_hdr_test pkt_hdr_test_4 = {
1, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
1, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } }, /* SCID */
@@ -2143,7 +2164,8 @@ static const struct pkt_hdr_test pkt_hdr_test_5 = {
0, /* key phase */
1, /* PN length */
0, /* partial */
- 1, /* fixed */
+ 1, /* fixed */
+ 0, /* unused */
1, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } }, /* SCID */
@@ -2183,6 +2205,7 @@ static const struct pkt_hdr_test pkt_hdr_test_6 = {
0, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
1, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } }, /* SCID */
@@ -2218,6 +2241,7 @@ static const struct pkt_hdr_test pkt_hdr_test_7 = {
3, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
0, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -2253,6 +2277,7 @@ static const struct pkt_hdr_test pkt_hdr_test_8 = {
3, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
0, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -2288,6 +2313,7 @@ static const struct pkt_hdr_test pkt_hdr_test_9 = {
3, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
0, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -2329,6 +2355,7 @@ static const struct pkt_hdr_test pkt_hdr_test_10 = {
4, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
1, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5 } }, /* SCID */
@@ -2364,6 +2391,7 @@ static const struct pkt_hdr_test pkt_hdr_test_11 = {
4, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
0, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -2398,6 +2426,7 @@ static const struct pkt_hdr_test pkt_hdr_test_12 = {
0, /* PN length */
0, /* partial */
1, /* fixed */
+ 0, /* unused */
0, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 2, {0x81, 0x82} }, /* SCID */
@@ -2432,6 +2461,7 @@ static const struct pkt_hdr_test pkt_hdr_test_13 = {
0, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
0, /* version */
{ 3, {0x70, 0x71, 0x72} }, /* DCID */
{ 2, {0x81, 0x82} }, /* SCID */
@@ -2964,6 +2994,7 @@ static QUIC_PKT_HDR tx_script_1_hdr = {
4, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
1, /* version */
{8, {0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08}}, /* DCID */
{ 0, {0} }, /* SCID */
@@ -3027,6 +3058,7 @@ static QUIC_PKT_HDR tx_script_2_hdr = {
2, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
1, /* version */
{ 0, {0} }, /* DCID */
{8, {0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5}}, /* SCID */
@@ -3077,6 +3109,7 @@ static QUIC_PKT_HDR tx_script_3_hdr = {
3, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
0, /* version */
{ 0, {0} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -3133,6 +3166,7 @@ static QUIC_PKT_HDR tx_script_4a_hdr = {
2, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
0, /* version */
{ 4, {0x6e, 0x4e, 0xbd, 0x49} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -3175,6 +3209,7 @@ static QUIC_PKT_HDR tx_script_4b_hdr = {
2, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
0, /* version */
{ 4, {0x6e, 0x4e, 0xbd, 0x49} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -3217,6 +3252,7 @@ static QUIC_PKT_HDR tx_script_4c_hdr = {
2, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
0, /* version */
{ 4, {0x6e, 0x4e, 0xbd, 0x49} }, /* DCID */
{ 0, {0} }, /* SCID */
@@ -3286,6 +3322,7 @@ static QUIC_PKT_HDR tx_script_5_hdr = {
0, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
1, /* version */
{ 0, {0} }, /* DCID */
{ 4, {0xa9, 0x20, 0xcc, 0xc2} }, /* SCID */
@@ -3336,6 +3373,7 @@ static QUIC_PKT_HDR tx_script_6_hdr = {
0, /* PN length */
0, /* partial */
0, /* fixed */
+ 0, /* unused */
0, /* version */
{ 0, {0} }, /* DCID */
{ 12, {0x35, 0x3c, 0x1b, 0x97, 0xca, 0xf8, 0x99,
diff --git a/test/quic_record_test_util.h b/test/quic_record_test_util.h
index 51d5db8a6e..2dc0951f2e 100644
--- a/test/quic_record_test_util.h
+++ b/test/quic_record_test_util.h
@@ -27,6 +27,7 @@ static int cmp_pkt_hdr(const QUIC_PKT_HDR *a, const QUIC_PKT_HDR *b,
|| !TEST_int_eq(a->pn_len, b->pn_len)
|| !TEST_int_eq(a->partial, b->partial)
|| !TEST_int_eq(a->fixed, b->fixed)
+ || !TEST_int_eq(a->unused, b->unused)
|| !TEST_uint_eq(a->version, b->version)
|| !TEST_true(ossl_quic_conn_id_eq(&a->dst_conn_id, &b->dst_conn_id))
|| !TEST_true(ossl_quic_conn_id_eq(&a->src_conn_id, &b->src_conn_id))
diff --git a/test/quic_wire_test.c b/test/quic_wire_test.c
index 325e322694..ceb273e7b6 100644
--- a/test/quic_wire_test.c
+++ b/test/quic_wire_test.c
@@ -1437,10 +1437,66 @@ err:
return testresult;
}
+/* RFC 9001 s. A.4 */
+static const QUIC_CONN_ID retry_orig_dcid = {
+ 8, { 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08 }
+};
+
+static const unsigned char retry_encoded[] = {
+ 0xff, /* Long Header, Retry */
+ 0x00, 0x00, 0x00, 0x01, /* Version 1 */
+ 0x00, /* DCID */
+ 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, 0xb5, /* SCID */
+
+ /* Retry Token */
+ 0x74, 0x6f, 0x6b, 0x65, 0x6e,
+
+ /* Retry Integrity Tag */
+ 0x04, 0xa2, 0x65, 0xba, 0x2e, 0xff, 0x4d, 0x82, 0x90, 0x58, 0xfb, 0x3f, 0x0f,
+ 0x24, 0x96, 0xba
+};
+
+static int test_wire_retry_integrity_tag(void)
+{
+ int testresult = 0;
+ PACKET pkt = {0};
+ QUIC_PKT_HDR hdr = {0};
+ unsigned char got_tag[QUIC_RETRY_INTEGRITY_TAG_LEN] = {0};
+
+ if (!TEST_true(PACKET_buf_init(&pkt, retry_encoded, sizeof(retry_encoded))))
+ goto err;
+
+ if (!TEST_true(ossl_quic_wire_decode_pkt_hdr(&pkt, 0, 0, &hdr, NULL)))
+ goto err;
+
+ if (!TEST_int_eq(hdr.type, QUIC_PKT_TYPE_RETRY))
+ goto err;
+
+ if (!TEST_true(ossl_quic_calculate_retry_integrity_tag(NULL, NULL, &hdr,
+ &retry_orig_dcid,
+ got_tag)))
+ goto err;
+
+ if (!TEST_mem_eq(got_tag, sizeof(got_tag),
+ retry_encoded + sizeof(retry_encoded)
+ - QUIC_RETRY_INTEGRITY_TAG_LEN,
+ QUIC_RETRY_INTEGRITY_TAG_LEN))
+ goto err;
+
+ if (!TEST_true(ossl_quic_validate_retry_integrity_tag(NULL, NULL, &hdr,
+ &retry_orig_dcid)))
+ goto err;
+
+ testresult = 1;
+err:
+ return testresult;
+}
+
int setup_tests(void)
{
ADD_ALL_TESTS(test_wire_encode, OSSL_NELEM(encode_cases));
ADD_ALL_TESTS(test_wire_ack, OSSL_NELEM(ack_cases));
ADD_ALL_TESTS(test_wire_pkt_hdr_pn, OSSL_NELEM(pn_tests));
+ ADD_TEST(test_wire_retry_integrity_tag);
return 1;
}