]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: Dynamically allocate the secrete keys
authorFrédéric Lécaille <flecaille@haproxy.com>
Tue, 23 Nov 2021 20:02:04 +0000 (21:02 +0100)
committerFrédéric Lécaille <flecaille@haproxy.com>
Tue, 30 Nov 2021 10:51:12 +0000 (11:51 +0100)
This is done for any encryption level. This is to prepare the Key Update feature.

include/haproxy/quic_tls-t.h
include/haproxy/quic_tls.h
src/quic_tls.c
src/xprt_quic.c

index e2f5fb16ab27212c72a91b92ba343929b6b3f1e4..237b8c6113db193bcd0cbf063011b21a4f8e26a3 100644 (file)
 #endif
 #endif
 
+/* AEAD iv and secrete key lengths */
+#define QUIC_TLS_IV_LEN     12 /* bytes */
+#define QUIC_TLS_KEY_LEN    32 /* bytes */
+#define QUIC_TLS_SECRET_LEN 64 /* bytes */
+
 /* The TLS extensions for QUIC transport parameters */
 #define TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS       0x0039
 #define TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS_DRAFT 0xffa5
 
+extern struct pool_head *pool_head_quic_tls_secret;
+extern struct pool_head *pool_head_quic_tls_iv;
+extern struct pool_head *pool_head_quic_tls_key;
+
 /* QUIC handshake states for both clients and servers. */
 enum quic_handshake_state {
        QUIC_HS_ST_CLIENT_HANDSHAKE_FAILED,
@@ -91,20 +100,26 @@ struct quic_tls_secrets {
        const EVP_CIPHER *aead;
        const EVP_MD *md;
        const EVP_CIPHER *hp;
-       unsigned char key[32];
-       unsigned char iv[12];
+       unsigned char *secret;
+       size_t secretlen;
        /* Header protection key.
        * Note: the header protection is applied after packet protection.
        * As the header belong to the data, its protection must be removed before removing
        * the packet protection.
        */
        unsigned char hp_key[32];
+       unsigned char *iv;
+       size_t ivlen;
+       unsigned char *key;
+       size_t keylen;
+       int64_t pn;
        char flags;
 };
 
 struct quic_tls_ctx {
        struct quic_tls_secrets rx;
        struct quic_tls_secrets tx;
+       unsigned char flags;
 };
 
 #endif /* USE_QUIC */
index def95fe443f3d553ddc58af0cd2c7079397dca73..bf23823dd5663a1c2c6432aadcf061322116b2bd 100644 (file)
@@ -340,12 +340,64 @@ static inline enum quic_tls_pktns quic_tls_pktns(enum quic_tls_enc_level level)
        }
 }
 
+/* Erase and free the secrets for a QUIC encryption level with <ctx> as
+ * context.
+ * Always succeeds.
+ */
+static inline void quic_tls_ctx_secs_free(struct quic_tls_ctx *ctx)
+{
+       if (ctx->rx.iv) {
+               memset(ctx->rx.iv, 0, ctx->rx.ivlen);
+               ctx->rx.ivlen = 0;
+       }
+       if (ctx->rx.key) {
+               memset(ctx->rx.key, 0, ctx->rx.keylen);
+               ctx->rx.keylen = 0;
+       }
+       if (ctx->tx.iv) {
+               memset(ctx->tx.iv, 0, ctx->tx.ivlen);
+               ctx->tx.ivlen = 0;
+       }
+       if (ctx->tx.key) {
+               memset(ctx->tx.key, 0, ctx->tx.keylen);
+               ctx->tx.keylen = 0;
+       }
+       pool_free(pool_head_quic_tls_iv,  ctx->rx.iv);
+       pool_free(pool_head_quic_tls_key, ctx->rx.key);
+       pool_free(pool_head_quic_tls_iv,  ctx->tx.iv);
+       pool_free(pool_head_quic_tls_key, ctx->tx.key);
+       ctx->rx.iv = ctx->tx.iv = NULL;
+       ctx->rx.key = ctx->tx.key = NULL;
+}
+
+/* Allocate the secrete keys for a QUIC encryption level with <ctx> as context.
+ * Returns 1 if succeeded, 0 if not.
+ */
+static inline int quic_tls_ctx_keys_alloc(struct quic_tls_ctx *ctx)
+{
+       if (!(ctx->rx.iv = pool_alloc(pool_head_quic_tls_iv)) ||
+           !(ctx->rx.key = pool_alloc(pool_head_quic_tls_key)) ||
+           !(ctx->tx.iv = pool_alloc(pool_head_quic_tls_iv)) ||
+           !(ctx->tx.key = pool_alloc(pool_head_quic_tls_key)))
+               goto err;
+
+       ctx->rx.ivlen = ctx->tx.ivlen = QUIC_TLS_IV_LEN;
+       ctx->rx.keylen = ctx->tx.keylen = QUIC_TLS_KEY_LEN;
+       return 1;
+
+ err:
+       quic_tls_ctx_secs_free(ctx);
+       return 0;
+}
+
 /* Initialize a TLS cryptographic context for the Initial encryption level. */
-static inline void quic_initial_tls_ctx_init(struct quic_tls_ctx *ctx)
+static inline int quic_initial_tls_ctx_init(struct quic_tls_ctx *ctx)
 {
        ctx->rx.aead = ctx->tx.aead = EVP_aes_128_gcm();
        ctx->rx.md   = ctx->tx.md   = EVP_sha256();
        ctx->rx.hp   = ctx->tx.hp   = EVP_aes_128_ctr();
+
+       return quic_tls_ctx_keys_alloc(ctx);
 }
 
 static inline int quic_tls_level_pkt_type(enum quic_tls_enc_level level)
@@ -392,11 +444,14 @@ static inline int quic_get_tls_enc_levels(enum quic_tls_enc_level *level,
        return 1;
 }
 
-/* Flag the keys at <qel> encryption level as discarded. */
+/* Flag the keys at <qel> encryption level as discarded.
+ * Note that this function is called only for Initial or Handshake encryption levels.
+ */
 static inline void quic_tls_discard_keys(struct quic_enc_level *qel)
 {
        qel->tls_ctx.rx.flags |= QUIC_FL_TLS_SECRETS_DCD;
        qel->tls_ctx.tx.flags |= QUIC_FL_TLS_SECRETS_DCD;
+       quic_tls_ctx_secs_free(&qel->tls_ctx);
 }
 
 /* Derive the initial secrets with <ctx> as QUIC TLS context which is the
@@ -419,7 +474,9 @@ static inline int qc_new_isecs(struct quic_conn *qc,
 
        TRACE_ENTER(QUIC_EV_CONN_ISEC);
        ctx = &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL].tls_ctx;
-       quic_initial_tls_ctx_init(ctx);
+       if (!quic_initial_tls_ctx_init(ctx))
+               goto err;
+
        if (!quic_derive_initial_secret(ctx->rx.md,
                                        salt, salt_len,
                                        initial_secret, sizeof initial_secret,
@@ -435,16 +492,16 @@ static inline int qc_new_isecs(struct quic_conn *qc,
        rx_ctx = &ctx->rx;
        tx_ctx = &ctx->tx;
        if (!quic_tls_derive_keys(ctx->rx.aead, ctx->rx.hp, ctx->rx.md,
-                                 rx_ctx->key, sizeof rx_ctx->key,
-                                 rx_ctx->iv, sizeof rx_ctx->iv,
+                                 rx_ctx->key, rx_ctx->keylen,
+                                 rx_ctx->iv, rx_ctx->ivlen,
                                  rx_ctx->hp_key, sizeof rx_ctx->hp_key,
                                  rx_init_sec, sizeof rx_init_sec))
                goto err;
 
        rx_ctx->flags |= QUIC_FL_TLS_SECRETS_SET;
        if (!quic_tls_derive_keys(ctx->tx.aead, ctx->tx.hp, ctx->tx.md,
-                                 tx_ctx->key, sizeof tx_ctx->key,
-                                 tx_ctx->iv, sizeof tx_ctx->iv,
+                                 tx_ctx->key, tx_ctx->keylen,
+                                 tx_ctx->iv, tx_ctx->ivlen,
                                  tx_ctx->hp_key, sizeof tx_ctx->hp_key,
                                  tx_init_sec, sizeof tx_init_sec))
                goto err;
index bd45fcee98486b1f368e413e1c43c70bf9740b20..491a1bcd7915f3c129157b756ab2f2a275375cd1 100644 (file)
 #include <haproxy/xprt_quic.h>
 
 
+DECLARE_POOL(pool_head_quic_tls_secret, "quic_tls_secret", QUIC_TLS_SECRET_LEN);
+DECLARE_POOL(pool_head_quic_tls_iv,     "quic_tls_iv",     QUIC_TLS_IV_LEN);
+DECLARE_POOL(pool_head_quic_tls_key,    "quic_tls_key",    QUIC_TLS_KEY_LEN);
+
 __attribute__((format (printf, 3, 4)))
 void hexdump(const void *buf, size_t buflen, const char *title_fmt, ...);
 
index b09db069491a542a1c7e26b2cce168e4e1a00ad6..2f23eae4d4f536e28b909715cfd557f9d1bb695f 100644 (file)
@@ -684,51 +684,61 @@ int ha_quic_set_encryption_secrets(SSL *ssl, enum ssl_encryption_level_t level,
        struct quic_tls_ctx *tls_ctx =
                &conn->qc->els[ssl_to_quic_enc_level(level)].tls_ctx;
        const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
+       struct quic_tls_secrets *rx, *tx;
 
        TRACE_ENTER(QUIC_EV_CONN_RWSEC, conn);
+       BUG_ON(secret_len > QUIC_TLS_SECRET_LEN);
        if (HA_ATOMIC_LOAD(&conn->qc->flags) & QUIC_FL_CONN_IMMEDIATE_CLOSE) {
                TRACE_PROTO("CC required", QUIC_EV_CONN_RWSEC, conn);
                goto out;
        }
-       tls_ctx->rx.aead = tls_ctx->tx.aead = tls_aead(cipher);
-       tls_ctx->rx.md   = tls_ctx->tx.md   = tls_md(cipher);
-       tls_ctx->rx.hp   = tls_ctx->tx.hp   = tls_hp(cipher);
 
-       if (!quic_tls_derive_keys(tls_ctx->rx.aead, tls_ctx->rx.hp, tls_ctx->rx.md,
-                                 tls_ctx->rx.key, sizeof tls_ctx->rx.key,
-                                 tls_ctx->rx.iv, sizeof tls_ctx->rx.iv,
-                                 tls_ctx->rx.hp_key, sizeof tls_ctx->rx.hp_key,
+       if (!quic_tls_ctx_keys_alloc(tls_ctx)) {
+               TRACE_DEVEL("keys allocation failed", QUIC_EV_CONN_RWSEC, conn);
+               goto err;
+       }
+
+       rx = &tls_ctx->rx;
+       tx = &tls_ctx->tx;
+
+       rx->aead = tx->aead = tls_aead(cipher);
+       rx->md   = tx->md   = tls_md(cipher);
+       rx->hp   = tx->hp   = tls_hp(cipher);
+
+       if (!quic_tls_derive_keys(rx->aead, rx->hp, rx->md, rx->key, rx->keylen,
+                                 rx->iv, rx->ivlen, rx->hp_key, sizeof rx->hp_key,
                                  read_secret, secret_len)) {
                TRACE_DEVEL("RX key derivation failed", QUIC_EV_CONN_RWSEC, conn);
-               return 0;
+               goto err;
        }
 
-       tls_ctx->rx.flags |= QUIC_FL_TLS_SECRETS_SET;
-       if (!quic_tls_derive_keys(tls_ctx->tx.aead, tls_ctx->tx.hp, tls_ctx->tx.md,
-                                 tls_ctx->tx.key, sizeof tls_ctx->tx.key,
-                                 tls_ctx->tx.iv, sizeof tls_ctx->tx.iv,
-                                 tls_ctx->tx.hp_key, sizeof tls_ctx->tx.hp_key,
+       rx->flags |= QUIC_FL_TLS_SECRETS_SET;
+       if (!quic_tls_derive_keys(tx->aead, tx->hp, tx->md, tx->key, tx->keylen,
+                                 tx->iv, tx->ivlen, tx->hp_key, sizeof tx->hp_key,
                                  write_secret, secret_len)) {
                TRACE_DEVEL("TX key derivation failed", QUIC_EV_CONN_RWSEC, conn);
-               return 0;
+               goto err;
        }
 
-       tls_ctx->tx.flags |= QUIC_FL_TLS_SECRETS_SET;
+       tx->flags |= QUIC_FL_TLS_SECRETS_SET;
        if (objt_server(conn->target) && level == ssl_encryption_application) {
                const unsigned char *buf;
                size_t buflen;
 
                SSL_get_peer_quic_transport_params(ssl, &buf, &buflen);
                if (!buflen)
-                       return 0;
+                       goto err;
 
                if (!quic_transport_params_store(conn->qc, 1, buf, buf + buflen))
-                       return 0;
+                       goto err;
        }
  out:
        TRACE_LEAVE(QUIC_EV_CONN_RWSEC, conn, &level);
-
        return 1;
+
+ err:
+       TRACE_DEVEL("leaving in error", QUIC_EV_CONN_RWSEC, conn);
+       return 0;
 }
 #else
 /* ->set_read_secret callback to derive the RX secrets at <level> encryption
@@ -753,9 +763,12 @@ int ha_set_rsec(SSL *ssl, enum ssl_encryption_level_t level,
        tls_ctx->rx.md = tls_md(cipher);
        tls_ctx->rx.hp = tls_hp(cipher);
 
+       if (!(ctx->rx.key = pool_alloc(pool_head_quic_tls_key)))
+               goto err;
+
        if (!quic_tls_derive_keys(tls_ctx->rx.aead, tls_ctx->rx.hp, tls_ctx->rx.md,
-                                 tls_ctx->rx.key, sizeof tls_ctx->rx.key,
-                                 tls_ctx->rx.iv, sizeof tls_ctx->rx.iv,
+                                 tls_ctx->rx.key, tls_ctx->rx.keylen,
+                                 tls_ctx->rx.iv, tls_ctx->rx.ivlen,
                                  tls_ctx->rx.hp_key, sizeof tls_ctx->rx.hp_key,
                                  secret, secret_len)) {
                TRACE_DEVEL("RX key derivation failed", QUIC_EV_CONN_RSEC, conn);
@@ -803,13 +816,16 @@ int ha_set_wsec(SSL *ssl, enum ssl_encryption_level_t level,
                goto out;
        }
 
+       if (!(ctx->tx.key = pool_alloc(pool_head_quic_tls_key)))
+               goto err;
+
        tls_ctx->tx.aead = tls_aead(cipher);
        tls_ctx->tx.md = tls_md(cipher);
        tls_ctx->tx.hp = tls_hp(cipher);
 
        if (!quic_tls_derive_keys(tls_ctx->tx.aead, tls_ctx->tx.hp, tls_ctx->tx.md,
-                                 tls_ctx->tx.key, sizeof tls_ctx->tx.key,
-                                 tls_ctx->tx.iv, sizeof tls_ctx->tx.iv,
+                                 tls_ctx->tx.key, tls_ctx->tx.keylen,
+                                 tls_ctx->tx.iv, tls_ctx->tx.ivlen,
                                  tls_ctx->tx.hp_key, sizeof tls_ctx->tx.hp_key,
                                  secret, secret_len)) {
                TRACE_DEVEL("TX key derivation failed", QUIC_EV_CONN_WSEC, conn);
@@ -1162,7 +1178,7 @@ static int quic_packet_encrypt(unsigned char *payload, size_t payload_len,
 {
        unsigned char iv[12];
        unsigned char *tx_iv = tls_ctx->tx.iv;
-       size_t tx_iv_sz = sizeof tls_ctx->tx.iv;
+       size_t tx_iv_sz = tls_ctx->tx.ivlen;
        struct enc_debug_info edi;
 
        if (!quic_aead_iv_build(iv, sizeof iv, tx_iv, tx_iv_sz, pn)) {
@@ -2974,6 +2990,7 @@ static int quic_conn_enc_level_init(struct quic_conn *qc,
        qel->tls_ctx.rx.hp   = qel->tls_ctx.tx.hp = NULL;
        qel->tls_ctx.rx.flags = 0;
        qel->tls_ctx.tx.flags = 0;
+       qel->tls_ctx.flags = 0;
 
        qel->rx.pkts = EB_ROOT;
        HA_RWLOCK_INIT(&qel->rx.pkts_rwlock);