}
}
+/* 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)
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
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,
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;
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
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);
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);
{
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)) {
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);