summaryrefslogtreecommitdiffstats
path: root/include/haproxy/quic_tls.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/haproxy/quic_tls.h')
-rw-r--r--include/haproxy/quic_tls.h690
1 files changed, 690 insertions, 0 deletions
diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h
new file mode 100644
index 0000000..1429067
--- /dev/null
+++ b/include/haproxy/quic_tls.h
@@ -0,0 +1,690 @@
+/*
+ * include/proto/quic_tls.h
+ * This file provides definitions for QUIC-TLS.
+ *
+ * Copyright 2019 HAProxy Technologies, Frederic Lecaille <flecaille@haproxy.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _PROTO_QUIC_TLS_H
+#define _PROTO_QUIC_TLS_H
+#ifdef USE_QUIC
+#ifndef USE_OPENSSL
+#error "Must define USE_OPENSSL"
+#endif
+
+#define TRACE_SOURCE &trace_quic
+
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/ssl.h>
+
+#include <haproxy/dynbuf.h>
+#include <haproxy/pool.h>
+#include <haproxy/quic_conn-t.h>
+#include <haproxy/quic_tls-t.h>
+#include <haproxy/trace.h>
+
+void quic_tls_keys_hexdump(struct buffer *buf,
+ const 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);
+
+int quic_tls_derive_initial_secrets(const EVP_MD *md,
+ unsigned char *rx, size_t rx_sz,
+ unsigned char *tx, size_t tx_sz,
+ const unsigned char *secret, size_t secret_sz,
+ int server);
+
+int quic_tls_encrypt(unsigned char *buf, size_t len,
+ const unsigned char *aad, size_t aad_len,
+ EVP_CIPHER_CTX *ctx, const EVP_CIPHER *aead,
+ const unsigned char *key, const unsigned char *iv);
+
+int quic_tls_decrypt2(unsigned char *out,
+ unsigned char *in, size_t ilen,
+ unsigned char *aad, size_t aad_len,
+ EVP_CIPHER_CTX *ctx, const EVP_CIPHER *aead,
+ const unsigned char *key, const unsigned char *iv);
+
+int quic_tls_decrypt(unsigned char *buf, size_t len,
+ unsigned char *aad, size_t aad_len,
+ EVP_CIPHER_CTX *tls_ctx, const EVP_CIPHER *aead,
+ const unsigned char *key, const unsigned char *iv);
+
+int quic_tls_generate_retry_integrity_tag(unsigned char *odcid, unsigned char odcid_len,
+ unsigned char *buf, size_t len,
+ const struct quic_version *qv);
+
+int quic_tls_derive_keys(const EVP_CIPHER *aead, const EVP_CIPHER *hp,
+ const EVP_MD *md, const struct quic_version *qv,
+ unsigned char *key, size_t keylen,
+ unsigned char *iv, size_t ivlen,
+ unsigned char *hp_key, size_t hp_keylen,
+ const unsigned char *secret, size_t secretlen);
+
+int quic_tls_derive_retry_token_secret(const EVP_MD *md,
+ unsigned char *key, size_t keylen,
+ unsigned char *iv, size_t ivlen,
+ const unsigned char *salt, size_t saltlen,
+ const unsigned char *secret, size_t secretlen);
+
+int quic_hkdf_extract_and_expand(const EVP_MD *md,
+ unsigned char *buf, size_t buflen,
+ const unsigned char *key, size_t keylen,
+ const unsigned char *salt, size_t saltlen,
+ const unsigned char *label, size_t labellen);
+
+int quic_tls_rx_ctx_init(EVP_CIPHER_CTX **rx_ctx,
+ const EVP_CIPHER *aead, unsigned char *key);
+int quic_tls_tx_ctx_init(EVP_CIPHER_CTX **tx_ctx,
+ const EVP_CIPHER *aead, unsigned char *key);
+
+int quic_tls_sec_update(const EVP_MD *md, const struct quic_version *qv,
+ unsigned char *new_sec, size_t new_seclen,
+ const unsigned char *sec, size_t seclen);
+
+int quic_aead_iv_build(unsigned char *iv, size_t ivlen,
+ unsigned char *aead_iv, size_t aead_ivlen, uint64_t pn);
+
+/* HP protection (AES) */
+int quic_tls_dec_aes_ctx_init(EVP_CIPHER_CTX **aes_ctx,
+ const EVP_CIPHER *aes, unsigned char *key);
+int quic_tls_enc_aes_ctx_init(EVP_CIPHER_CTX **aes_ctx,
+ const EVP_CIPHER *aes, unsigned char *key);
+int quic_tls_aes_decrypt(unsigned char *out,
+ const unsigned char *in, size_t inlen,
+ EVP_CIPHER_CTX *ctx);
+int quic_tls_aes_encrypt(unsigned char *out,
+ const unsigned char *in, size_t inlen,
+ EVP_CIPHER_CTX *ctx);
+
+static inline const EVP_CIPHER *tls_aead(const SSL_CIPHER *cipher)
+{
+ switch (SSL_CIPHER_get_id(cipher)) {
+ case TLS1_3_CK_AES_128_GCM_SHA256:
+ return EVP_aes_128_gcm();
+ case TLS1_3_CK_AES_256_GCM_SHA384:
+ return EVP_aes_256_gcm();
+#if !defined(LIBRESSL_VERSION_NUMBER)
+ case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+ return EVP_chacha20_poly1305();
+#endif
+ case TLS1_3_CK_AES_128_CCM_SHA256:
+ return EVP_aes_128_ccm();
+ default:
+ return NULL;
+ }
+}
+
+static inline const EVP_MD *tls_md(const SSL_CIPHER *cipher)
+{
+ switch (SSL_CIPHER_get_id(cipher)) {
+ case TLS1_3_CK_AES_128_GCM_SHA256:
+ case TLS1_3_CK_AES_128_CCM_SHA256:
+ case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+ return EVP_sha256();
+ case TLS1_3_CK_AES_256_GCM_SHA384:
+ return EVP_sha384();
+ default:
+ return NULL;
+ }
+}
+
+static inline const EVP_CIPHER *tls_hp(const SSL_CIPHER *cipher)
+{
+ switch (SSL_CIPHER_get_id(cipher)) {
+ case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
+ return EVP_chacha20();
+ case TLS1_3_CK_AES_128_CCM_SHA256:
+ case TLS1_3_CK_AES_128_GCM_SHA256:
+ return EVP_aes_128_ctr();
+ case TLS1_3_CK_AES_256_GCM_SHA384:
+ return EVP_aes_256_ctr();
+ default:
+ return NULL;
+ }
+
+}
+
+/* These following functions map TLS implementation encryption level to ours */
+static inline enum quic_tls_enc_level ssl_to_quic_enc_level(enum ssl_encryption_level_t level)
+{
+ switch (level) {
+ case ssl_encryption_initial:
+ return QUIC_TLS_ENC_LEVEL_INITIAL;
+ case ssl_encryption_early_data:
+ return QUIC_TLS_ENC_LEVEL_EARLY_DATA;
+ case ssl_encryption_handshake:
+ return QUIC_TLS_ENC_LEVEL_HANDSHAKE;
+ case ssl_encryption_application:
+ return QUIC_TLS_ENC_LEVEL_APP;
+ default:
+ return -1;
+ }
+}
+
+/* These two following functions map our encryption level to the TLS implementation ones. */
+static inline enum ssl_encryption_level_t quic_to_ssl_enc_level(enum quic_tls_enc_level level)
+{
+ switch (level) {
+ case QUIC_TLS_ENC_LEVEL_INITIAL:
+ return ssl_encryption_initial;
+ case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
+ return ssl_encryption_early_data;
+ case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
+ return ssl_encryption_handshake;
+ case QUIC_TLS_ENC_LEVEL_APP:
+ return ssl_encryption_application;
+ default:
+ return -1;
+ }
+}
+
+/* Return a human readable string from <state> QUIC handshake state of NULL
+ * for unknown state values (for debug purpose).
+ */
+static inline char *quic_hdshk_state_str(const enum quic_handshake_state state)
+{
+ switch (state) {
+ case QUIC_HS_ST_CLIENT_INITIAL:
+ return "CI";
+ case QUIC_HS_ST_CLIENT_HANDSHAKE:
+ return "CH";
+ case QUIC_HS_ST_CLIENT_HANDSHAKE_FAILED:
+ return "CF";
+ case QUIC_HS_ST_SERVER_INITIAL:
+ return "SI";
+ case QUIC_HS_ST_SERVER_HANDSHAKE:
+ return "SH";
+ case QUIC_HS_ST_SERVER_HANDSHAKE_FAILED:
+ return "SF";
+ case QUIC_HS_ST_COMPLETE:
+ return "HCP";
+ case QUIC_HS_ST_CONFIRMED:
+ return "HCF";
+ }
+
+ return NULL;
+}
+
+/* Return a human readable string from <err> SSL error (returned from
+ * SSL_get_error())
+ */
+static inline const char *ssl_error_str(int err)
+{
+ switch (err) {
+ case SSL_ERROR_NONE:
+ return "NONE";
+ case SSL_ERROR_SSL:
+ return "SSL";
+ case SSL_ERROR_WANT_READ:
+ return "WANT_READ";
+ case SSL_ERROR_WANT_WRITE:
+ return "WANT_WRITE";
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return "X509_LOOKUP";
+ case SSL_ERROR_SYSCALL:
+ return "SYSCALL";
+ case SSL_ERROR_ZERO_RETURN:
+ return "ZERO_RETURN";
+ case SSL_ERROR_WANT_CONNECT:
+ return "WANT_CONNECT";
+ case SSL_ERROR_WANT_ACCEPT:
+ return "WANT_ACCEPT";
+#if !defined(LIBRESSL_VERSION_NUMBER)
+ case SSL_ERROR_WANT_ASYNC:
+ return "WANT_ASYNC";
+ case SSL_ERROR_WANT_ASYNC_JOB:
+ return "WANT_ASYNC_JOB";
+ case SSL_ERROR_WANT_CLIENT_HELLO_CB:
+ return "WANT_CLIENT_HELLO_CB";
+#endif
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+/* Return a character identifying the encryption level from <level> QUIC TLS
+ * encryption level (for debug purpose).
+ * Initial -> 'I', Early Data -> 'E', Handshake -> 'H', Application -> 'A' and
+ * '-' if undefined.
+ */
+static inline char quic_enc_level_char(enum quic_tls_enc_level level)
+{
+ switch (level) {
+ case QUIC_TLS_ENC_LEVEL_INITIAL:
+ return 'I';
+ case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
+ return 'E';
+ case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
+ return 'H';
+ case QUIC_TLS_ENC_LEVEL_APP:
+ return 'A';
+ default:
+ return '-';
+ }
+}
+
+/* Return a character identifying <qel> encryption level from <qc> QUIC connection
+ * (for debug purpose).
+ * Initial -> 'I', Early Data -> 'E', Handshake -> 'H', Application -> 'A' and
+ * '-' if undefined.
+ */
+static inline char quic_enc_level_char_from_qel(const struct quic_enc_level *qel,
+ const struct quic_conn *qc)
+{
+ if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_INITIAL])
+ return 'I';
+ else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_EARLY_DATA])
+ return 'E';
+ else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE])
+ return 'H';
+ else if (qel == &qc->els[QUIC_TLS_ENC_LEVEL_APP])
+ return 'A';
+ return '-';
+}
+
+/* Return a character identifying the encryption level of a packet depending on
+ * its <type> type, and its <long_header> header length (for debug purpose).
+ * Initial -> 'I', ORTT -> '0', Handshake -> 'H', Application -> 'A' and
+ * '-' if undefined.
+ */
+static inline char quic_packet_type_enc_level_char(int packet_type)
+{
+ switch (packet_type) {
+ case QUIC_PACKET_TYPE_INITIAL:
+ return 'I';
+ case QUIC_PACKET_TYPE_0RTT:
+ return '0';
+ case QUIC_PACKET_TYPE_HANDSHAKE:
+ return 'H';
+ case QUIC_PACKET_TYPE_SHORT:
+ return 'A';
+ default:
+ return '-';
+ }
+}
+
+/* Return the TLS encryption level to be used for <packet_type>
+ * QUIC packet type.
+ * Returns -1 if there is no TLS encryption level for <packet_type>
+ * packet type.
+ */
+static inline enum quic_tls_enc_level quic_packet_type_enc_level(enum quic_pkt_type packet_type)
+{
+ switch (packet_type) {
+ case QUIC_PACKET_TYPE_INITIAL:
+ return QUIC_TLS_ENC_LEVEL_INITIAL;
+ case QUIC_PACKET_TYPE_0RTT:
+ return QUIC_TLS_ENC_LEVEL_EARLY_DATA;
+ case QUIC_PACKET_TYPE_HANDSHAKE:
+ return QUIC_TLS_ENC_LEVEL_HANDSHAKE;
+ case QUIC_PACKET_TYPE_RETRY:
+ return QUIC_TLS_ENC_LEVEL_NONE;
+ case QUIC_PACKET_TYPE_SHORT:
+ return QUIC_TLS_ENC_LEVEL_APP;
+ default:
+ return QUIC_TLS_ENC_LEVEL_NONE;
+ }
+}
+
+static inline enum quic_tls_pktns quic_tls_pktns(enum quic_tls_enc_level level)
+{
+ switch (level) {
+ case QUIC_TLS_ENC_LEVEL_INITIAL:
+ return QUIC_TLS_PKTNS_INITIAL;
+ case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
+ case QUIC_TLS_ENC_LEVEL_APP:
+ return QUIC_TLS_PKTNS_01RTT;
+ case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
+ return QUIC_TLS_PKTNS_HANDSHAKE;
+ default:
+ return -1;
+ }
+}
+
+/* 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;
+ }
+
+ /* RX HP protection */
+ EVP_CIPHER_CTX_free(ctx->rx.hp_ctx);
+ /* RX AEAD decryption */
+ EVP_CIPHER_CTX_free(ctx->rx.ctx);
+ pool_free(pool_head_quic_tls_iv, ctx->rx.iv);
+ pool_free(pool_head_quic_tls_key, ctx->rx.key);
+
+ /* TX HP protection */
+ EVP_CIPHER_CTX_free(ctx->tx.hp_ctx);
+ /* TX AEAD encryption */
+ EVP_CIPHER_CTX_free(ctx->tx.ctx);
+ 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.key)
+ goto write;
+
+ if (!(ctx->rx.iv = pool_alloc(pool_head_quic_tls_iv)) ||
+ !(ctx->rx.key = pool_alloc(pool_head_quic_tls_key)))
+ goto err;
+
+ write:
+ if (ctx->tx.key)
+ goto out;
+
+ if (!(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;
+out:
+ return 1;
+
+ err:
+ quic_tls_ctx_secs_free(ctx);
+ return 0;
+}
+
+/* Release the memory allocated for <secs> secrets */
+static inline void quic_tls_secrets_keys_free(struct quic_tls_secrets *secs)
+{
+ if (secs->iv) {
+ memset(secs->iv, 0, secs->ivlen);
+ secs->ivlen = 0;
+ }
+
+ if (secs->key) {
+ memset(secs->key, 0, secs->keylen);
+ secs->keylen = 0;
+ }
+
+ /* HP protection */
+ EVP_CIPHER_CTX_free(secs->hp_ctx);
+ /* AEAD decryption */
+ EVP_CIPHER_CTX_free(secs->ctx);
+ pool_free(pool_head_quic_tls_iv, secs->iv);
+ pool_free(pool_head_quic_tls_key, secs->key);
+
+ secs->iv = secs->key = NULL;
+}
+
+/* Allocate the memory for the <secs> secrets.
+ * Return 1 if succeeded, 0 if not.
+ */
+static inline int quic_tls_secrets_keys_alloc(struct quic_tls_secrets *secs)
+{
+ if (!(secs->iv = pool_alloc(pool_head_quic_tls_iv)) ||
+ !(secs->key = pool_alloc(pool_head_quic_tls_key)))
+ goto err;
+
+ secs->ivlen = QUIC_TLS_IV_LEN;
+ secs->keylen = QUIC_TLS_KEY_LEN;
+
+ return 1;
+
+ err:
+ quic_tls_secrets_keys_free(secs);
+ return 0;
+}
+
+/* Initialize a TLS cryptographic context for the Initial encryption level. */
+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)
+{
+ switch (level) {
+ case QUIC_TLS_ENC_LEVEL_INITIAL:
+ return QUIC_PACKET_TYPE_INITIAL;
+ case QUIC_TLS_ENC_LEVEL_EARLY_DATA:
+ return QUIC_PACKET_TYPE_0RTT;
+ case QUIC_TLS_ENC_LEVEL_HANDSHAKE:
+ return QUIC_PACKET_TYPE_HANDSHAKE;
+ case QUIC_TLS_ENC_LEVEL_APP:
+ return QUIC_PACKET_TYPE_SHORT;
+ default:
+ return -1;
+ }
+}
+
+/* Set <*level> and <*next_level> depending on <state> QUIC handshake state. */
+static inline int quic_get_tls_enc_levels(enum quic_tls_enc_level *level,
+ enum quic_tls_enc_level *next_level,
+ struct quic_conn *qc,
+ enum quic_handshake_state state, int zero_rtt)
+{
+ int ret = 0;
+
+ TRACE_ENTER(QUIC_EV_CONN_ELEVELSEL, qc, &state, level, next_level);
+ switch (state) {
+ case QUIC_HS_ST_SERVER_INITIAL:
+ case QUIC_HS_ST_CLIENT_INITIAL:
+ *level = QUIC_TLS_ENC_LEVEL_INITIAL;
+ if (zero_rtt)
+ *next_level = QUIC_TLS_ENC_LEVEL_EARLY_DATA;
+ else
+ *next_level = QUIC_TLS_ENC_LEVEL_HANDSHAKE;
+ break;
+ case QUIC_HS_ST_SERVER_HANDSHAKE:
+ case QUIC_HS_ST_CLIENT_HANDSHAKE:
+ *level = QUIC_TLS_ENC_LEVEL_HANDSHAKE;
+ *next_level = QUIC_TLS_ENC_LEVEL_APP;
+ break;
+ case QUIC_HS_ST_COMPLETE:
+ case QUIC_HS_ST_CONFIRMED:
+ *level = QUIC_TLS_ENC_LEVEL_APP;
+ *next_level = QUIC_TLS_ENC_LEVEL_NONE;
+ break;
+ default:
+ goto leave;
+ }
+
+ ret = 1;
+ leave:
+ TRACE_LEAVE(QUIC_EV_CONN_ELEVELSEL, qc, NULL, level, next_level);
+ return ret;
+}
+
+/* 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.flags |= QUIC_FL_TLS_SECRETS_DCD;
+}
+
+/* Derive the initial secrets with <ctx> as QUIC TLS context which is the
+ * cryptographic context for the first encryption level (Initial) from
+ * <cid> connection ID with <cidlen> as length (in bytes) for a server or not
+ * depending on <server> boolean value.
+ * Return 1 if succeeded or 0 if not.
+ */
+static inline int qc_new_isecs(struct quic_conn *qc,
+ struct quic_tls_ctx *ctx, const struct quic_version *ver,
+ const unsigned char *cid, size_t cidlen, int server)
+{
+ unsigned char initial_secret[32];
+ /* Initial secret to be derived for incoming packets */
+ unsigned char rx_init_sec[32];
+ /* Initial secret to be derived for outgoing packets */
+ unsigned char tx_init_sec[32];
+ struct quic_tls_secrets *rx_ctx, *tx_ctx;
+
+ TRACE_ENTER(QUIC_EV_CONN_ISEC);
+ if (!quic_initial_tls_ctx_init(ctx))
+ goto err;
+
+ if (!quic_derive_initial_secret(ctx->rx.md,
+ ver->initial_salt, ver->initial_salt_len,
+ initial_secret, sizeof initial_secret,
+ cid, cidlen))
+ goto err;
+
+ if (!quic_tls_derive_initial_secrets(ctx->rx.md,
+ rx_init_sec, sizeof rx_init_sec,
+ tx_init_sec, sizeof tx_init_sec,
+ initial_secret, sizeof initial_secret, server))
+ goto err;
+
+ rx_ctx = &ctx->rx;
+ tx_ctx = &ctx->tx;
+ if (!quic_tls_derive_keys(ctx->rx.aead, ctx->rx.hp, ctx->rx.md, ver,
+ 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;
+
+ if (!quic_tls_rx_ctx_init(&rx_ctx->ctx, rx_ctx->aead, rx_ctx->key))
+ goto err;
+
+ if (!quic_tls_enc_aes_ctx_init(&rx_ctx->hp_ctx, rx_ctx->hp, rx_ctx->hp_key))
+ goto err;
+
+ if (!quic_tls_derive_keys(ctx->tx.aead, ctx->tx.hp, ctx->tx.md, ver,
+ 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;
+
+ if (!quic_tls_tx_ctx_init(&tx_ctx->ctx, tx_ctx->aead, tx_ctx->key))
+ goto err;
+
+ if (!quic_tls_enc_aes_ctx_init(&tx_ctx->hp_ctx, tx_ctx->hp, tx_ctx->hp_key))
+ goto err;
+
+ TRACE_LEAVE(QUIC_EV_CONN_ISEC, qc, rx_init_sec, tx_init_sec);
+
+ return 1;
+
+ err:
+ TRACE_DEVEL("leaving in error", QUIC_EV_CONN_ISEC);
+ return 0;
+}
+
+/* Release the memory allocated for all the key update key phase
+ * structures for <qc> QUIC connection.
+ * Always succeeds.
+ */
+static inline void quic_tls_ku_free(struct quic_conn *qc)
+{
+ EVP_CIPHER_CTX_free(qc->ku.prv_rx.ctx);
+ pool_free(pool_head_quic_tls_secret, qc->ku.prv_rx.secret);
+ pool_free(pool_head_quic_tls_iv, qc->ku.prv_rx.iv);
+ pool_free(pool_head_quic_tls_key, qc->ku.prv_rx.key);
+ EVP_CIPHER_CTX_free(qc->ku.nxt_rx.ctx);
+ pool_free(pool_head_quic_tls_secret, qc->ku.nxt_rx.secret);
+ pool_free(pool_head_quic_tls_iv, qc->ku.nxt_rx.iv);
+ pool_free(pool_head_quic_tls_key, qc->ku.nxt_rx.key);
+ EVP_CIPHER_CTX_free(qc->ku.nxt_tx.ctx);
+ pool_free(pool_head_quic_tls_secret, qc->ku.nxt_tx.secret);
+ pool_free(pool_head_quic_tls_iv, qc->ku.nxt_tx.iv);
+ pool_free(pool_head_quic_tls_key, qc->ku.nxt_tx.key);
+}
+
+/* Initialize <kp> key update secrets, allocating the required memory.
+ * Return 1 if all the secrets could be allocated, 0 if not.
+ * This is the responsibility of the caller to release the memory
+ * allocated by this function in case of failure.
+ */
+static inline int quic_tls_kp_init(struct quic_tls_kp *kp)
+{
+ kp->count = 0;
+ kp->pn = 0;
+ kp->flags = 0;
+ kp->secret = pool_alloc(pool_head_quic_tls_secret);
+ kp->secretlen = QUIC_TLS_SECRET_LEN;
+ kp->iv = pool_alloc(pool_head_quic_tls_iv);
+ kp->ivlen = QUIC_TLS_IV_LEN;
+ kp->key = pool_alloc(pool_head_quic_tls_key);
+ kp->keylen = QUIC_TLS_KEY_LEN;
+
+ return kp->secret && kp->iv && kp->key;
+}
+
+/* Initialize all the key update key phase structures for <qc>
+ * QUIC connection, allocating the required memory.
+ *
+ * Returns 1 if succeeded, 0 if not. The caller is responsible to use
+ * quic_tls_ku_free() on error to cleanup partially allocated content.
+ */
+static inline int quic_tls_ku_init(struct quic_conn *qc)
+{
+ struct quic_tls_kp *prv_rx = &qc->ku.prv_rx;
+ struct quic_tls_kp *nxt_rx = &qc->ku.nxt_rx;
+ struct quic_tls_kp *nxt_tx = &qc->ku.nxt_tx;
+
+ if (!quic_tls_kp_init(prv_rx) ||
+ !quic_tls_kp_init(nxt_rx) ||
+ !quic_tls_kp_init(nxt_tx))
+ goto err;
+
+ return 1;
+
+ err:
+ return 0;
+}
+
+/* Return 1 if <qel> has RX secrets, 0 if not. */
+static inline int quic_tls_has_rx_sec(const struct quic_enc_level *qel)
+{
+ return !!qel->tls_ctx.rx.key;
+}
+
+/* Return 1 if <qel> has TX secrets, 0 if not. */
+static inline int quic_tls_has_tx_sec(const struct quic_enc_level *qel)
+{
+ return !!qel->tls_ctx.tx.key;
+}
+
+#endif /* USE_QUIC */
+#endif /* _PROTO_QUIC_TLS_H */
+