From 2fc76cffaf0d7f97b8bc45d13b05243950f27af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= Date: Tue, 31 Aug 2021 19:10:40 +0200 Subject: [PATCH] MINOR: quic: Make QUIC-TLS support at least two initial salts These salts are used to derive initial secrets to decrypt the first Initial packet. We support draft-29 and v1 QUIC version initial salts. Add parameters to our QUIC-TLS API functions used to derive these secret for these salts. Make our xprt_quic use the correct initial salt upon QUIC version field found in the first paquet. Useful to support connections with curl which use draft-29 QUIC version. --- include/haproxy/quic_tls.h | 18 ++++++++++++++++++ include/haproxy/xprt_quic-t.h | 2 ++ src/quic_tls.c | 22 ++++------------------ src/xprt_quic.c | 12 ++++++++++-- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h index 288cc16c0..def95fe44 100644 --- a/include/haproxy/quic_tls.h +++ b/include/haproxy/quic_tls.h @@ -27,12 +27,28 @@ #include #include +/* Initial salt depending on QUIC version to derive client/server initial secrets. + * This one is for draft-29 QUIC version. + */ +unsigned char initial_salt_draft_29[20] = { + 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, + 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, + 0x43, 0x90, 0xa8, 0x99 +}; + +unsigned char initial_salt_v1[20] = { + 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, + 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, + 0xcc, 0xbb, 0x7f, 0x0a +}; + void quic_tls_keys_hexdump(struct buffer *buf, struct quic_tls_secrets *secs); void quic_tls_secret_hexdump(struct buffer *buf, const unsigned char *secret, size_t secret_len); int quic_derive_initial_secret(const EVP_MD *md, + const unsigned char *initial_salt, size_t initial_salt_sz, unsigned char *initial_secret, size_t initial_secret_sz, const unsigned char *secret, size_t secret_sz); @@ -390,6 +406,7 @@ static inline void quic_tls_discard_keys(struct quic_enc_level *qel) * Return 1 if succeeded or 0 if not. */ static inline int qc_new_isecs(struct quic_conn *qc, + const unsigned char *salt, size_t salt_len, const unsigned char *cid, size_t cidlen, int server) { unsigned char initial_secret[32]; @@ -404,6 +421,7 @@ static inline int qc_new_isecs(struct quic_conn *qc, ctx = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].tls_ctx; quic_initial_tls_ctx_init(ctx); if (!quic_derive_initial_secret(ctx->rx.md, + salt, salt_len, initial_secret, sizeof initial_secret, cid, cidlen)) goto err; diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h index b64da75eb..b06245554 100644 --- a/include/haproxy/xprt_quic-t.h +++ b/include/haproxy/xprt_quic-t.h @@ -42,6 +42,8 @@ #include #define QUIC_PROTOCOL_VERSION_DRAFT_28 0xff00001c /* draft-28 */ +#define QUIC_PROTOCOL_VERSION_DRAFT_29 0xff00001d /* draft-29 */ +#define QUIC_PROTOCOL_VERSION_1 0x00000001 /* V1 */ #define QUIC_INITIAL_IPV4_MTU 1252 /* (bytes) */ #define QUIC_INITIAL_IPV6_MTU 1232 diff --git a/src/quic_tls.c b/src/quic_tls.c index 11d5875da..bd45fcee9 100644 --- a/src/quic_tls.c +++ b/src/quic_tls.c @@ -18,21 +18,6 @@ __attribute__((format (printf, 3, 4))) void hexdump(const void *buf, size_t buflen, const char *title_fmt, ...); -/* Initial salt depending on QUIC version to derive client/server initial secrets. - * This one is for draft-29 QUIC version. - */ -unsigned char initial_salt[20] = { - 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, - 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, - 0x43, 0x90, 0xa8, 0x99 -}; - -unsigned char initial_salt_v1[20] = { - 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, - 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, - 0xcc, 0xbb, 0x7f, 0x0a -}; - /* Dump the RX/TX secrets of QUIC TLS secrets. */ void quic_tls_keys_hexdump(struct buffer *buf, struct quic_tls_secrets *secs) { @@ -67,7 +52,7 @@ void quic_tls_secret_hexdump(struct buffer *buf, int quic_hkdf_extract(const EVP_MD *md, unsigned char *buf, size_t *buflen, const unsigned char *key, size_t keylen, - unsigned char *salt, size_t saltlen) + const unsigned char *salt, size_t saltlen) { return HKDF_extract(buf, buflen, md, key, keylen, salt, saltlen); } @@ -83,7 +68,7 @@ int quic_hkdf_expand(const EVP_MD *md, int quic_hkdf_extract(const EVP_MD *md, unsigned char *buf, size_t *buflen, const unsigned char *key, size_t keylen, - unsigned char *salt, size_t saltlen) + const unsigned char *salt, size_t saltlen) { EVP_PKEY_CTX *ctx; @@ -224,11 +209,12 @@ int quic_tls_derive_keys(const EVP_CIPHER *aead, const EVP_CIPHER *hp, * Returns the size of the derived secret if succeeded, 0 if not. */ int quic_derive_initial_secret(const EVP_MD *md, + const unsigned char *initial_salt, size_t initial_salt_sz, unsigned char *initial_secret, size_t initial_secret_sz, const unsigned char *secret, size_t secret_sz) { if (!quic_hkdf_extract(md, initial_secret, &initial_secret_sz, secret, secret_sz, - initial_salt_v1, sizeof initial_salt_v1)) + initial_salt, initial_salt_sz)) return 0; return 1; diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 765494080..ee7004bf4 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -3371,6 +3371,8 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end, int ipv4; struct quic_cid *odcid; struct ebmb_node *n = NULL; + const unsigned char *salt = initial_salt_v1; + size_t salt_len = sizeof initial_salt_v1; if (pkt->type != QUIC_PACKET_TYPE_INITIAL) { TRACE_PROTO("Non Initiial packet", QUIC_EV_CONN_LPKT); @@ -3406,7 +3408,12 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end, /* NOTE: the socket address has been concatenated to the destination ID * chosen by the client for Initial packets. */ - if (!qc_new_isecs(qc, pkt->dcid.data, pkt->odcid_len, 1)) { + if (pkt->version == QUIC_PROTOCOL_VERSION_DRAFT_29) { + salt = initial_salt_draft_29; + salt_len = sizeof initial_salt_draft_29; + } + if (!qc_new_isecs(qc, salt, salt_len, + pkt->dcid.data, pkt->odcid_len, 1)) { TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc->conn); goto err; } @@ -4360,7 +4367,8 @@ static int qc_conn_init(struct connection *conn, void **xprt_ctx) conn->qc = qc; qc->conn = conn; - if (!qc_new_isecs(qc, dcid, sizeof dcid, 0)) + if (!qc_new_isecs(qc, initial_salt_v1, sizeof initial_salt_v1, + dcid, sizeof dcid, 0)) goto err; if (ssl_bio_and_sess_init(conn, srv->ssl_ctx.ctx,