mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.17.2
- [BUGFIX] Infinite loop in stream: advance read offset when discarding data. - [OPTIMIZATION] Header protection: only initialize cipher once. - [OPTIMIZATION] Batch header protection application.
This commit is contained in:
parent
e957eb06e3
commit
da99665b1c
9 changed files with 242 additions and 74 deletions
|
@ -123,6 +123,12 @@ struct enc_session_funcs_common
|
|||
void
|
||||
(*esf_set_conn) (enc_session_t *, struct lsquic_conn *);
|
||||
|
||||
/* Optional. This function gets called after packets are encrypted,
|
||||
* batched, and are about to be sent.
|
||||
*/
|
||||
void
|
||||
(*esf_flush_encryption) (enc_session_t *);
|
||||
|
||||
unsigned
|
||||
esf_tag_len;
|
||||
};
|
||||
|
|
|
@ -106,22 +106,26 @@ no_sess_ticket (enum alarm_id alarm_id, void *ctx,
|
|||
lsquic_time_t expiry, lsquic_time_t now);
|
||||
|
||||
|
||||
typedef void (*gen_hp_mask_f)(struct enc_sess_iquic *,
|
||||
const struct header_prot *, unsigned rw,
|
||||
const unsigned char *sample, unsigned char mask[16]);
|
||||
#define SAMPLE_SZ 16
|
||||
|
||||
typedef void (*gen_hp_mask_f)(struct enc_sess_iquic *,
|
||||
struct header_prot *, unsigned rw,
|
||||
const unsigned char *sample, unsigned char *mask, size_t sz);
|
||||
|
||||
#define CHACHA20_KEY_LENGTH 32
|
||||
|
||||
struct header_prot
|
||||
{
|
||||
const EVP_CIPHER *hp_cipher;
|
||||
gen_hp_mask_f hp_gen_mask;
|
||||
enum enc_level hp_enc_level;
|
||||
enum {
|
||||
HP_CAN_READ = 1 << 0,
|
||||
HP_CAN_WRITE = 1 << 1,
|
||||
} hp_flags;
|
||||
unsigned hp_sz;
|
||||
unsigned char hp_buf[2][EVP_MAX_KEY_LENGTH];
|
||||
union {
|
||||
EVP_CIPHER_CTX cipher_ctx[2]; /* AES */
|
||||
unsigned char buf[2][CHACHA20_KEY_LENGTH]; /* ChaCha */
|
||||
} hp_u;
|
||||
};
|
||||
|
||||
#define header_prot_inited(hp_, rw_) ((hp_)->hp_flags & (1 << (rw_)))
|
||||
|
@ -176,20 +180,6 @@ init_crypto_ctx (struct crypto_ctx *crypto_ctx, const EVP_MD *md,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
derive_hp_secrets (struct header_prot *hp, const EVP_MD *md,
|
||||
const EVP_AEAD *aead, size_t secret_sz,
|
||||
const unsigned char *client_secret, const unsigned char *server_secret)
|
||||
{
|
||||
hp->hp_sz = EVP_AEAD_key_length(aead);
|
||||
hp->hp_flags = HP_CAN_READ | HP_CAN_WRITE;
|
||||
lsquic_qhkdf_expand(md, client_secret, secret_sz, PN_LABEL, PN_LABEL_SZ,
|
||||
hp->hp_buf[0], hp->hp_sz);
|
||||
lsquic_qhkdf_expand(md, server_secret, secret_sz, PN_LABEL, PN_LABEL_SZ,
|
||||
hp->hp_buf[1], hp->hp_sz);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cleanup_crypto_ctx (struct crypto_ctx *crypto_ctx)
|
||||
{
|
||||
|
@ -201,6 +191,8 @@ cleanup_crypto_ctx (struct crypto_ctx *crypto_ctx)
|
|||
}
|
||||
|
||||
|
||||
#define HP_BATCH_SIZE 8
|
||||
|
||||
struct enc_sess_iquic
|
||||
{
|
||||
struct lsquic_engine_public
|
||||
|
@ -275,23 +267,24 @@ struct enc_sess_iquic
|
|||
struct lsquic_alarmset
|
||||
*esi_alset;
|
||||
unsigned esi_max_streams_uni;
|
||||
unsigned esi_hp_batch_idx;
|
||||
unsigned esi_hp_batch_packno_len[HP_BATCH_SIZE];
|
||||
unsigned esi_hp_batch_packno_off[HP_BATCH_SIZE];
|
||||
struct lsquic_packet_out *
|
||||
esi_hp_batch_packets[HP_BATCH_SIZE];
|
||||
unsigned char esi_hp_batch_samples[HP_BATCH_SIZE][SAMPLE_SZ];
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
gen_hp_mask_aes (struct enc_sess_iquic *enc_sess,
|
||||
const struct header_prot *hp, unsigned rw,
|
||||
const unsigned char *sample, unsigned char mask[EVP_MAX_BLOCK_LENGTH])
|
||||
struct header_prot *hp, unsigned rw,
|
||||
const unsigned char *sample, unsigned char *mask, size_t sz)
|
||||
{
|
||||
EVP_CIPHER_CTX hp_ctx;
|
||||
int out_len;
|
||||
|
||||
EVP_CIPHER_CTX_init(&hp_ctx);
|
||||
if (EVP_EncryptInit_ex(&hp_ctx, hp->hp_cipher, NULL, hp->hp_buf[rw], 0)
|
||||
&& EVP_EncryptUpdate(&hp_ctx, mask, &out_len, sample, 16))
|
||||
{
|
||||
assert(out_len >= 5);
|
||||
}
|
||||
if (EVP_EncryptUpdate(&hp->hp_u.cipher_ctx[rw], mask, &out_len, sample, sz))
|
||||
assert(out_len >= (int) sz);
|
||||
else
|
||||
{
|
||||
LSQ_WARN("cannot generate hp mask, error code: %"PRIu32,
|
||||
|
@ -299,15 +292,13 @@ gen_hp_mask_aes (struct enc_sess_iquic *enc_sess,
|
|||
enc_sess->esi_conn->cn_if->ci_internal_error(enc_sess->esi_conn,
|
||||
"cannot generate hp mask, error code: %"PRIu32, ERR_get_error());
|
||||
}
|
||||
|
||||
(void) EVP_CIPHER_CTX_cleanup(&hp_ctx);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gen_hp_mask_chacha20 (struct enc_sess_iquic *enc_sess,
|
||||
const struct header_prot *hp, unsigned rw,
|
||||
const unsigned char *sample, unsigned char mask[EVP_MAX_BLOCK_LENGTH])
|
||||
struct header_prot *hp, unsigned rw,
|
||||
const unsigned char *sample, unsigned char *mask, size_t sz)
|
||||
{
|
||||
const uint8_t *nonce;
|
||||
uint32_t counter;
|
||||
|
@ -319,19 +310,17 @@ gen_hp_mask_chacha20 (struct enc_sess_iquic *enc_sess,
|
|||
#endif
|
||||
nonce = sample + sizeof(counter);
|
||||
CRYPTO_chacha_20(mask, (unsigned char [5]) { 0, 0, 0, 0, 0, }, 5,
|
||||
hp->hp_buf[rw], nonce, counter);
|
||||
hp->hp_u.buf[rw], nonce, counter);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
apply_hp (struct enc_sess_iquic *enc_sess,
|
||||
const struct header_prot *hp,
|
||||
unsigned char *dst, unsigned packno_off, unsigned packno_len)
|
||||
apply_hp (struct enc_sess_iquic *enc_sess, struct header_prot *hp,
|
||||
unsigned char *dst, const unsigned char *mask,
|
||||
unsigned packno_off, unsigned packno_len)
|
||||
{
|
||||
unsigned char mask[EVP_MAX_BLOCK_LENGTH];
|
||||
char mask_str[5 * 2 + 1];
|
||||
|
||||
hp->hp_gen_mask(enc_sess, hp, 1, dst + packno_off + 4, mask);
|
||||
LSQ_DEBUG("apply header protection using mask %s",
|
||||
HEXSTR(mask, 5, mask_str));
|
||||
if (enc_sess->esi_flags & ESI_SEND_QL_BITS)
|
||||
|
@ -355,6 +344,64 @@ apply_hp (struct enc_sess_iquic *enc_sess,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
apply_hp_immediately (struct enc_sess_iquic *enc_sess,
|
||||
struct header_prot *hp, struct lsquic_packet_out *packet_out,
|
||||
unsigned packno_off, unsigned packno_len)
|
||||
{
|
||||
unsigned char mask[SAMPLE_SZ];
|
||||
|
||||
hp->hp_gen_mask(enc_sess, hp, 1,
|
||||
packet_out->po_enc_data + packno_off + 4, mask, SAMPLE_SZ);
|
||||
apply_hp(enc_sess, hp, packet_out->po_enc_data, mask, packno_off,
|
||||
packno_len);
|
||||
#ifndef NDEBUG
|
||||
packet_out->po_lflags |= POL_HEADER_PROT;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
flush_hp_batch (struct enc_sess_iquic *enc_sess)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned char mask[HP_BATCH_SIZE][SAMPLE_SZ];
|
||||
|
||||
enc_sess->esi_hp.hp_gen_mask(enc_sess, &enc_sess->esi_hp, 1,
|
||||
(unsigned char *) enc_sess->esi_hp_batch_samples,
|
||||
(unsigned char *) mask,
|
||||
enc_sess->esi_hp_batch_idx * SAMPLE_SZ);
|
||||
for (i = 0; i < enc_sess->esi_hp_batch_idx; ++i)
|
||||
{
|
||||
apply_hp(enc_sess, &enc_sess->esi_hp,
|
||||
enc_sess->esi_hp_batch_packets[i]->po_enc_data,
|
||||
mask[i],
|
||||
enc_sess->esi_hp_batch_packno_off[i],
|
||||
enc_sess->esi_hp_batch_packno_len[i]);
|
||||
#ifndef NDEBUG
|
||||
enc_sess->esi_hp_batch_packets[i]->po_lflags |= POL_HEADER_PROT;
|
||||
#endif
|
||||
}
|
||||
enc_sess->esi_hp_batch_idx = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
apply_hp_batch (struct enc_sess_iquic *enc_sess,
|
||||
struct header_prot *hp, struct lsquic_packet_out *packet_out,
|
||||
unsigned packno_off, unsigned packno_len)
|
||||
{
|
||||
memcpy(enc_sess->esi_hp_batch_samples[enc_sess->esi_hp_batch_idx],
|
||||
packet_out->po_enc_data + packno_off + 4, SAMPLE_SZ);
|
||||
enc_sess->esi_hp_batch_packno_off[enc_sess->esi_hp_batch_idx] = packno_off;
|
||||
enc_sess->esi_hp_batch_packno_len[enc_sess->esi_hp_batch_idx] = packno_len;
|
||||
enc_sess->esi_hp_batch_packets[enc_sess->esi_hp_batch_idx] = packet_out;
|
||||
++enc_sess->esi_hp_batch_idx;
|
||||
if (enc_sess->esi_hp_batch_idx == HP_BATCH_SIZE)
|
||||
flush_hp_batch(enc_sess);
|
||||
}
|
||||
|
||||
|
||||
static lsquic_packno_t
|
||||
decode_packno (lsquic_packno_t max_packno, lsquic_packno_t packno,
|
||||
unsigned shift)
|
||||
|
@ -382,17 +429,17 @@ decode_packno (lsquic_packno_t max_packno, lsquic_packno_t packno,
|
|||
|
||||
static lsquic_packno_t
|
||||
strip_hp (struct enc_sess_iquic *enc_sess,
|
||||
const struct header_prot *hp,
|
||||
struct header_prot *hp,
|
||||
const unsigned char *iv, unsigned char *dst, unsigned packno_off,
|
||||
unsigned *packno_len)
|
||||
{
|
||||
enum packnum_space pns;
|
||||
lsquic_packno_t packno;
|
||||
unsigned shift;
|
||||
unsigned char mask[EVP_MAX_BLOCK_LENGTH];
|
||||
unsigned char mask[SAMPLE_SZ];
|
||||
char mask_str[5 * 2 + 1];
|
||||
|
||||
hp->hp_gen_mask(enc_sess, hp, 0, iv, mask);
|
||||
hp->hp_gen_mask(enc_sess, hp, 0, iv, mask, SAMPLE_SZ);
|
||||
LSQ_DEBUG("strip header protection using mask %s",
|
||||
HEXSTR(mask, 5, mask_str));
|
||||
if (enc_sess->esi_flags & ESI_RECV_QL_BITS)
|
||||
|
@ -892,30 +939,23 @@ log_crypto_pair (const struct enc_sess_iquic *enc_sess,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
log_hp (const struct enc_sess_iquic *enc_sess,
|
||||
const struct header_prot *hp, const char *name)
|
||||
{
|
||||
char hexbuf[EVP_MAX_MD_SIZE * 2 + 1];
|
||||
LSQ_DEBUG("read %s hp: %s", name,
|
||||
HEXSTR(hp->hp_buf[0], hp->hp_sz, hexbuf));
|
||||
LSQ_DEBUG("write %s hp: %s", name,
|
||||
HEXSTR(hp->hp_buf[1], hp->hp_sz, hexbuf));
|
||||
}
|
||||
|
||||
|
||||
/* [draft-ietf-quic-tls-12] Section 5.3.2 */
|
||||
static int
|
||||
setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid)
|
||||
{
|
||||
const EVP_MD *const md = EVP_sha256();
|
||||
const EVP_AEAD *const aead = EVP_aead_aes_128_gcm();
|
||||
/* [draft-ietf-quic-tls-12] Section 5.6.1: AEAD_AES_128_GCM implies
|
||||
* 128-bit AES-CTR.
|
||||
*/
|
||||
const EVP_CIPHER *const cipher = EVP_aes_128_ecb();
|
||||
struct crypto_ctx_pair *pair;
|
||||
struct header_prot *hp;
|
||||
size_t hsk_secret_sz;
|
||||
unsigned cliser;
|
||||
size_t hsk_secret_sz, key_len;
|
||||
unsigned cliser, i;
|
||||
unsigned char hsk_secret[EVP_MAX_MD_SIZE];
|
||||
unsigned char secret[2][SHA256_DIGEST_LENGTH]; /* client, server */
|
||||
unsigned char key[2][EVP_MAX_KEY_LENGTH];
|
||||
char hexbuf[EVP_MAX_MD_SIZE * 2 + 1];
|
||||
|
||||
if (!enc_sess->esi_hsk_pairs)
|
||||
|
@ -965,18 +1005,29 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid)
|
|||
sizeof(secret[1]), rw2dir(cliser)))
|
||||
goto err;
|
||||
|
||||
/* [draft-ietf-quic-tls-12] Section 5.6.1: AEAD_AES_128_GCM implies
|
||||
* 128-bit AES-CTR.
|
||||
*/
|
||||
hp->hp_cipher = EVP_aes_128_ecb();
|
||||
hp->hp_gen_mask = gen_hp_mask_aes;
|
||||
hp->hp_enc_level = ENC_LEV_CLEAR;
|
||||
derive_hp_secrets(hp, md, aead, sizeof(secret[0]), secret[!cliser], secret[cliser]);
|
||||
|
||||
key_len = EVP_AEAD_key_length(aead);
|
||||
lsquic_qhkdf_expand(md, secret[!cliser], sizeof(secret[0]), PN_LABEL,
|
||||
PN_LABEL_SZ, key[0], key_len);
|
||||
lsquic_qhkdf_expand(md, secret[cliser], sizeof(secret[0]), PN_LABEL,
|
||||
PN_LABEL_SZ, key[1], key_len);
|
||||
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
|
||||
{
|
||||
log_crypto_pair(enc_sess, pair, "handshake");
|
||||
log_hp(enc_sess, hp, "handshake");
|
||||
LSQ_DEBUG("read handshake hp: %s", HEXSTR(key[0], key_len, hexbuf));
|
||||
LSQ_DEBUG("write handshake hp: %s", HEXSTR(key[1], key_len, hexbuf));
|
||||
}
|
||||
for (i = 0; i < 2; ++i)
|
||||
{
|
||||
EVP_CIPHER_CTX_init(&hp->hp_u.cipher_ctx[i]);
|
||||
if (EVP_EncryptInit_ex(&hp->hp_u.cipher_ctx[i], cipher, NULL, key[i], 0))
|
||||
hp->hp_flags |= 1 << i;
|
||||
else
|
||||
{
|
||||
LSQ_ERROR("%s: cannot initialize cipher %u", __func__, i);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -988,10 +1039,23 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
cleanup_hp (struct header_prot *hp)
|
||||
{
|
||||
unsigned rw;
|
||||
|
||||
if (hp->hp_gen_mask == gen_hp_mask_aes)
|
||||
for (rw = 0; rw < 2; ++rw)
|
||||
if (hp->hp_flags & (1 << rw))
|
||||
(void) EVP_CIPHER_CTX_cleanup(&hp->hp_u.cipher_ctx[rw]);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_handshake_keys (struct enc_sess_iquic *enc_sess)
|
||||
{
|
||||
struct crypto_ctx_pair *pair;
|
||||
unsigned i;
|
||||
|
||||
if (enc_sess->esi_hsk_pairs)
|
||||
{
|
||||
|
@ -1004,6 +1068,8 @@ free_handshake_keys (struct enc_sess_iquic *enc_sess)
|
|||
}
|
||||
free(enc_sess->esi_hsk_pairs);
|
||||
enc_sess->esi_hsk_pairs = NULL;
|
||||
for (i = 0; i < N_HSK_PAIRS; ++i)
|
||||
cleanup_hp(&enc_sess->esi_hsk_hps[i]);
|
||||
free(enc_sess->esi_hsk_hps);
|
||||
enc_sess->esi_hsk_hps = NULL;
|
||||
}
|
||||
|
@ -1776,6 +1842,7 @@ iquic_esfi_destroy (enc_session_t *enc_session_p)
|
|||
SSL_free(enc_sess->esi_ssl);
|
||||
|
||||
free_handshake_keys(enc_sess);
|
||||
cleanup_hp(&enc_sess->esi_hp);
|
||||
|
||||
free(enc_sess->esi_zero_rtt_buf);
|
||||
free(enc_sess->esi_hostname);
|
||||
|
@ -1813,7 +1880,7 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
unsigned char *dst;
|
||||
const struct crypto_ctx_pair *pair;
|
||||
const struct crypto_ctx *crypto_ctx;
|
||||
const struct header_prot *hp;
|
||||
struct header_prot *hp;
|
||||
enum enc_level enc_level;
|
||||
unsigned char nonce_buf[ sizeof(crypto_ctx->yk_iv_buf) + 8 ];
|
||||
unsigned char *nonce, *begin_xor;
|
||||
|
@ -1896,6 +1963,9 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
#endif
|
||||
*((uint64_t *) begin_xor) ^= packno;
|
||||
|
||||
/* TODO: have this call return packno_off and packno_len to avoid
|
||||
* another function call.
|
||||
*/
|
||||
header_sz = lconn->cn_pf->pf_gen_reg_pkt_header(lconn, packet_out, dst,
|
||||
dst_sz);
|
||||
if (header_sz < 0)
|
||||
|
@ -1927,7 +1997,6 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
const unsigned sample_off = packno_off + 4;
|
||||
assert(sample_off + IQUIC_TAG_LEN <= dst_sz);
|
||||
#endif
|
||||
apply_hp(enc_sess, hp, dst, packno_off, packno_len);
|
||||
|
||||
packet_out->po_enc_data = dst;
|
||||
packet_out->po_enc_data_sz = dst_sz;
|
||||
|
@ -1936,6 +2005,12 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
packet_out->po_flags |= PO_ENCRYPTED|PO_SENT_SZ|(ipv6 << POIPv6_SHIFT);
|
||||
lsquic_packet_out_set_enc_level(packet_out, enc_level);
|
||||
lsquic_packet_out_set_kp(packet_out, enc_sess->esi_key_phase);
|
||||
|
||||
if (enc_level == ENC_LEV_FORW && hp->hp_gen_mask != gen_hp_mask_chacha20)
|
||||
apply_hp_batch(enc_sess, hp, packet_out, packno_off, packno_len);
|
||||
else
|
||||
apply_hp_immediately(enc_sess, hp, packet_out, packno_off, packno_len);
|
||||
|
||||
return ENCPA_OK;
|
||||
|
||||
err:
|
||||
|
@ -1945,6 +2020,20 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
iquic_esf_flush_encryption (enc_session_t *enc_session_p)
|
||||
{
|
||||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||
|
||||
if (enc_sess->esi_hp_batch_idx)
|
||||
{
|
||||
LSQ_DEBUG("flush header protection application, count: %u",
|
||||
enc_sess->esi_hp_batch_idx);
|
||||
flush_hp_batch(enc_sess);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct ku_label
|
||||
{
|
||||
const char *str;
|
||||
|
@ -1966,7 +2055,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
|
|||
struct enc_sess_iquic *const enc_sess = enc_session_p;
|
||||
unsigned char *dst;
|
||||
struct crypto_ctx_pair *pair;
|
||||
const struct header_prot *hp;
|
||||
struct header_prot *hp;
|
||||
struct crypto_ctx *crypto_ctx = NULL;
|
||||
unsigned char nonce_buf[ sizeof(crypto_ctx->yk_iv_buf) + 8 ];
|
||||
unsigned char *nonce, *begin_xor;
|
||||
|
@ -2454,6 +2543,25 @@ const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1 =
|
|||
|
||||
|
||||
const struct enc_session_funcs_common lsquic_enc_session_common_ietf_v1 =
|
||||
{
|
||||
.esf_encrypt_packet = iquic_esf_encrypt_packet,
|
||||
.esf_decrypt_packet = iquic_esf_decrypt_packet,
|
||||
.esf_flush_encryption= iquic_esf_flush_encryption,
|
||||
.esf_global_cleanup = iquic_esf_global_cleanup,
|
||||
.esf_global_init = iquic_esf_global_init,
|
||||
.esf_tag_len = IQUIC_TAG_LEN,
|
||||
.esf_get_server_cert_chain
|
||||
= iquic_esf_get_server_cert_chain,
|
||||
.esf_cipher = iquic_esf_cipher,
|
||||
.esf_keysize = iquic_esf_keysize,
|
||||
.esf_alg_keysize = iquic_esf_alg_keysize,
|
||||
.esf_is_zero_rtt_enabled = iquic_esf_zero_rtt_enabled,
|
||||
.esf_set_conn = iquic_esf_set_conn,
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
const struct enc_session_funcs_common lsquic_enc_session_common_ietf_v1_no_flush =
|
||||
{
|
||||
.esf_encrypt_packet = iquic_esf_encrypt_packet,
|
||||
.esf_decrypt_packet = iquic_esf_decrypt_packet,
|
||||
|
@ -2553,7 +2661,9 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
int have_alpn;
|
||||
const unsigned char *alpn;
|
||||
unsigned alpn_len;
|
||||
size_t key_len;
|
||||
const enum enc_level enc_level = (enum enc_level) level;
|
||||
unsigned char key[EVP_MAX_KEY_LENGTH];
|
||||
char errbuf[ERR_ERROR_STRING_BUF_LEN];
|
||||
#define hexbuf errbuf
|
||||
|
||||
|
@ -2602,6 +2712,13 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
memcpy(enc_sess->esi_traffic_secrets[rw], secret, secret_len);
|
||||
enc_sess->esi_md = crypa.md;
|
||||
enc_sess->esi_aead = crypa.aead;
|
||||
if (!(hp->hp_flags & (HP_CAN_READ|HP_CAN_WRITE))
|
||||
&& crypa.aead == EVP_aead_chacha20_poly1305())
|
||||
{
|
||||
LSQ_DEBUG("turn off header protection batching (chacha not "
|
||||
"supported)");
|
||||
enc_sess->esi_conn->cn_esf_c = &lsquic_enc_session_common_ietf_v1_no_flush;
|
||||
}
|
||||
}
|
||||
pair->ykp_thresh = IQUIC_INVALID_PACKNO;
|
||||
|
||||
|
@ -2620,25 +2737,36 @@ set_secret (SSL *ssl, enum ssl_encryption_level_t level,
|
|||
/* Sanity check that the two sides end up with the same header
|
||||
* protection logic, as they should.
|
||||
*/
|
||||
assert(hp->hp_cipher == crypa.hp);
|
||||
assert(hp->hp_gen_mask == crypa.gen_hp_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
hp->hp_enc_level = enc_level;
|
||||
hp->hp_cipher = crypa.hp;
|
||||
hp->hp_gen_mask = crypa.gen_hp_mask;
|
||||
hp->hp_sz = EVP_AEAD_key_length(crypa.aead);
|
||||
}
|
||||
lsquic_qhkdf_expand(crypa.md, secret, secret_len, PN_LABEL, PN_LABEL_SZ,
|
||||
hp->hp_buf[rw], hp->hp_sz);
|
||||
key_len = EVP_AEAD_key_length(crypa.aead);
|
||||
if (hp->hp_gen_mask == gen_hp_mask_aes)
|
||||
{
|
||||
lsquic_qhkdf_expand(crypa.md, secret, secret_len, PN_LABEL, PN_LABEL_SZ,
|
||||
key, key_len);
|
||||
EVP_CIPHER_CTX_init(&hp->hp_u.cipher_ctx[rw]);
|
||||
if (!EVP_EncryptInit_ex(&hp->hp_u.cipher_ctx[rw], crypa.hp, NULL, key, 0))
|
||||
{
|
||||
LSQ_ERROR("cannot initialize cipher on level %u", enc_level);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else
|
||||
lsquic_qhkdf_expand(crypa.md, secret, secret_len, PN_LABEL, PN_LABEL_SZ,
|
||||
hp->hp_u.buf[rw], key_len);
|
||||
hp->hp_flags |= 1 << rw;
|
||||
|
||||
if (enc_sess->esi_flags & ESI_LOG_SECRETS)
|
||||
{
|
||||
log_crypto_ctx(enc_sess, &pair->ykp_ctx[rw], "new", rw);
|
||||
LSQ_DEBUG("%s hp: %s", rw2str[rw],
|
||||
HEXSTR(hp->hp_buf[rw], hp->hp_sz, hexbuf));
|
||||
HEXSTR(hp->hp_gen_mask == gen_hp_mask_aes ? key : hp->hp_u.buf[rw],
|
||||
key_len, hexbuf));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -2160,6 +2160,20 @@ close_conn_on_send_error (struct lsquic_engine *engine,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
apply_hp (struct conns_out_iter *iter)
|
||||
{
|
||||
struct lsquic_conn *conn;
|
||||
|
||||
TAILQ_FOREACH(conn, &iter->coi_active_list, cn_next_out)
|
||||
if (conn->cn_esf_c->esf_flush_encryption && conn->cn_enc_session)
|
||||
conn->cn_esf_c->esf_flush_encryption(conn->cn_enc_session);
|
||||
TAILQ_FOREACH(conn, &iter->coi_inactive_list, cn_next_out)
|
||||
if (conn->cn_esf_c->esf_flush_encryption && conn->cn_enc_session)
|
||||
conn->cn_esf_c->esf_flush_encryption(conn->cn_enc_session);
|
||||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
send_batch (lsquic_engine_t *engine, const struct send_batch_ctx *sb_ctx,
|
||||
unsigned n_to_send)
|
||||
|
@ -2171,6 +2185,7 @@ send_batch (lsquic_engine_t *engine, const struct send_batch_ctx *sb_ctx,
|
|||
CONST_BATCH struct out_batch *const batch = sb_ctx->batch;
|
||||
struct lsquic_packet_out *CONST_BATCH *packet_out, *CONST_BATCH *end;
|
||||
|
||||
apply_hp(sb_ctx->conns_iter);
|
||||
#if CAN_LOSE_PACKETS
|
||||
if (engine->flags & ENG_LOSE_PACKETS)
|
||||
lose_matching_packets(engine, batch, n_to_send);
|
||||
|
|
|
@ -6608,6 +6608,9 @@ static void
|
|||
ietf_full_conn_ci_packet_not_sent (struct lsquic_conn *lconn,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert(packet_out->po_lflags & POL_HEADER_PROT);
|
||||
#endif
|
||||
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
|
||||
lsquic_send_ctl_delayed_one(&conn->ifc_send_ctl, packet_out);
|
||||
}
|
||||
|
@ -6620,6 +6623,9 @@ static void
|
|||
pre_hsk_packet_sent_or_delayed (struct ietf_full_conn *conn,
|
||||
const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert(packet_out->po_lflags & POL_HEADER_PROT);
|
||||
#endif
|
||||
/* Once IFC_IGNORE_INIT is set, the pre-hsk wrapper is removed: */
|
||||
assert(!(conn->ifc_flags & IFC_IGNORE_INIT));
|
||||
--conn->ifc_u.cli.ifcli_packets_out;
|
||||
|
|
|
@ -146,6 +146,9 @@ typedef struct lsquic_packet_out
|
|||
POL_LOG_QL_BITS = 1 << 6,
|
||||
POL_SQUARE_BIT = 1 << 7,
|
||||
POL_LOSS_BIT = 1 << 8,
|
||||
#ifndef NDEBUG
|
||||
POL_HEADER_PROT = 1 << 9, /* Header protection applied */
|
||||
#endif
|
||||
} po_lflags:16;
|
||||
unsigned char *po_data;
|
||||
|
||||
|
|
|
@ -783,10 +783,13 @@ static int
|
|||
stream_readable_discard (struct lsquic_stream *stream)
|
||||
{
|
||||
struct data_frame *data_frame;
|
||||
uint64_t toread;
|
||||
|
||||
while ((data_frame = stream->data_in->di_if->di_get_frame(
|
||||
stream->data_in, stream->read_offset)))
|
||||
{
|
||||
toread = data_frame->df_size - data_frame->df_read_off;
|
||||
stream->read_offset += toread;
|
||||
data_frame->df_read_off = data_frame->df_size;
|
||||
stream->data_in->di_if->di_frame_done(stream->data_in, data_frame);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue