MINOR: quic: implement Retry TLS AEAD tag generation
Implement a new QUIC TLS related function
quic_tls_generate_retry_integrity_tag(). This function can be used to
calculate the AEAD tag of a Retry packet.
diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h
index 2c3528d..cc94b02 100644
--- a/include/haproxy/quic_tls.h
+++ b/include/haproxy/quic_tls.h
@@ -69,6 +69,9 @@
const EVP_CIPHER *aead,
const unsigned char *key, const unsigned char *iv);
+int quic_tls_generate_retry_integrity_tag(unsigned char *odcid, size_t odcid_len,
+ unsigned char *buf, size_t len);
+
int quic_tls_derive_keys(const EVP_CIPHER *aead, const EVP_CIPHER *hp,
const EVP_MD *md,
unsigned char *key, size_t keylen,
diff --git a/src/quic_tls.c b/src/quic_tls.c
index 8100d47..d4314d7 100644
--- a/src/quic_tls.c
+++ b/src/quic_tls.c
@@ -396,3 +396,59 @@
EVP_CIPHER_CTX_free(ctx);
return ret;
}
+
+/* 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
+ * be at least 16 bytes longs. <odcid> is the CID of the Initial packet
+ * received which triggers the Retry.
+ *
+ * Returns non-zero on success else zero.
+ */
+int quic_tls_generate_retry_integrity_tag(unsigned char *odcid,
+ unsigned char odcid_len,
+ unsigned char *pkt, size_t pkt_len)
+{
+ const EVP_CIPHER *evp = EVP_aes_128_gcm();
+ EVP_CIPHER_CTX *ctx;
+
+ /* key/nonce from rfc9001 5.8. Retry Packet Integrity */
+ const unsigned char key[] = {
+ 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a,
+ 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e,
+ };
+ const unsigned char nonce[] = {
+ 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb,
+ };
+
+ /* encryption buffer - not used as only AEAD tag generation is proceed */
+ unsigned char *out = NULL;
+ /* address to store the AEAD tag */
+ unsigned char *tag = pkt + pkt_len;
+ int outlen, ret = 0;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return 0;
+
+ /* rfc9001 5.8. Retry Packet Integrity
+ *
+ * AEAD is proceed over a pseudo-Retry packet used as AAD. It contains
+ * the ODCID len + data and the Retry packet itself.
+ */
+ if (!EVP_EncryptInit_ex(ctx, evp, NULL, key, nonce) ||
+ /* specify pseudo-Retry as AAD */
+ !EVP_EncryptUpdate(ctx, NULL, &outlen, &odcid_len, sizeof(odcid_len)) ||
+ !EVP_EncryptUpdate(ctx, NULL, &outlen, odcid, odcid_len) ||
+ !EVP_EncryptUpdate(ctx, NULL, &outlen, pkt, pkt_len) ||
+ /* finalize */
+ !EVP_EncryptFinal_ex(ctx, out, &outlen) ||
+ /* store the tag */
+ !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, QUIC_TLS_TAG_LEN, tag)) {
+ goto out;
+ }
+ ret = 1;
+
+ out:
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+}