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.
This commit is contained in:
Frédéric Lécaille 2021-08-31 19:10:40 +02:00 committed by Amaury Denoyelle
parent 2766e78f3b
commit 2fc76cffaf
4 changed files with 34 additions and 20 deletions

View File

@ -27,12 +27,28 @@
#include <haproxy/trace.h>
#include <haproxy/xprt_quic.h>
/* 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;

View File

@ -42,6 +42,8 @@
#include <import/ebmbtree.h>
#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

View File

@ -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 <secs> 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;

View File

@ -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,