From f913a2972bc94e161ffd389039fcf34a2fce66cf Mon Sep 17 00:00:00 2001 From: Dmitri Tikhonov Date: Fri, 12 Jun 2020 08:04:42 -0400 Subject: [PATCH] Release 2.16.2 - [BUGFIX] ID-28: do not use TLS middlebox compatibility mode in ClientHello. This change requires using a newer version of BoringSSL. - [BUGFIX] Free connections in Advisory Tick Time Queue in engine dtor. - [BUGFIX] IETF QUIC client: narrow migration check to a single path. - [BUGFIX] NULL dereference: set function pointers for alarm for path challenges 2 and 3. - [BUGFIX] HTTP/3 headers may be followed immediately by trailers. - [BUGFIX] Log messages when SCID changes. --- .cirrus.yml | 2 +- .travis.yml | 2 +- CHANGELOG | 11 ++ README.md | 2 +- appveyor.yml | 2 +- docs/conf.py | 2 +- include/lsquic.h | 2 +- src/liblsquic/lsquic_enc_sess_ietf.c | 215 +++++++++++++++----------- src/liblsquic/lsquic_engine.c | 3 + src/liblsquic/lsquic_full_conn_ietf.c | 39 ++--- src/liblsquic/lsquic_stream.c | 1 + 11 files changed, 155 insertions(+), 126 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 93c7b83..e50d797 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -8,7 +8,7 @@ task: - cd boringssl # This is so that both GQUIC and IETF branches build. Just picking # a known good revision: - - git checkout bfe527fa35735e8e045cbfb42b012e13ca68f9cf + - git checkout 251b5169fd44345f455438312ec4e18ae07fd58c - cmake . - make - cd - diff --git a/.travis.yml b/.travis.yml index 6e4d5e7..b87cd55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ before_script: - cd boringssl # This is so that both GQUIC and IETF branches build. Just picking # a known good revision: - - git checkout bfe527fa35735e8e045cbfb42b012e13ca68f9cf + - git checkout 251b5169fd44345f455438312ec4e18ae07fd58c - cmake . - make - cd - diff --git a/CHANGELOG b/CHANGELOG index 14006e9..9f44d7e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,14 @@ +2020-06-12 + - 2.16.2 + - [BUGFIX] ID-28: do not use TLS middlebox compatibility mode in + ClientHello. This change requires using a newer version of BoringSSL. + - [BUGFIX] Free connections in Advisory Tick Time Queue in engine dtor. + - [BUGFIX] IETF QUIC client: narrow migration check to a single path. + - [BUGFIX] NULL dereference: set function pointers for alarm for path + challenges 2 and 3. + - [BUGFIX] HTTP/3 headers may be followed immediately by trailers. + - [BUGFIX] Log messages when SCID changes. + 2020-06-09 - 2.16.1 - [FEATURE] Use "no-progress timeout" after which connection is closed. diff --git a/README.md b/README.md index 821e439..837c4b5 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ You may need to install pre-requisites like zlib and libevent. 2. Use specific BoringSSL version ``` -git checkout bfe527fa35735e8e045cbfb42b012e13ca68f9cf +git checkout 251b5169fd44345f455438312ec4e18ae07fd58c ``` 3. Compile the library diff --git a/appveyor.yml b/appveyor.yml index 65d9d03..283efb3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,7 +30,7 @@ build_script: cd boringssl - git checkout bfe527fa35735e8e045cbfb42b012e13ca68f9cf + git checkout 251b5169fd44345f455438312ec4e18ae07fd58c cmake -DCMAKE_GENERATOR_PLATFORM=x64 --config Debug -DBUILD_SHARED_LIBS=OFF -DOPENSSL_NO_ASM=1 . diff --git a/docs/conf.py b/docs/conf.py index df59515..9a8741f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ author = u'LiteSpeed Technologies' # The short X.Y version version = u'2.16' # The full version, including alpha/beta/rc tags -release = u'2.16.1' +release = u'2.16.2' # -- General configuration --------------------------------------------------- diff --git a/include/lsquic.h b/include/lsquic.h index ae8af12..c1af68c 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -25,7 +25,7 @@ extern "C" { #define LSQUIC_MAJOR_VERSION 2 #define LSQUIC_MINOR_VERSION 16 -#define LSQUIC_PATCH_VERSION 1 +#define LSQUIC_PATCH_VERSION 2 /** * Engine flags: diff --git a/src/liblsquic/lsquic_enc_sess_ietf.c b/src/liblsquic/lsquic_enc_sess_ietf.c index d57b80a..a201737 100644 --- a/src/liblsquic/lsquic_enc_sess_ietf.c +++ b/src/liblsquic/lsquic_enc_sess_ietf.c @@ -106,7 +106,7 @@ no_sess_ticket (enum alarm_id alarm_id, void *ctx, typedef void (*gen_hp_mask_f)(struct enc_sess_iquic *, - const struct header_prot *, unsigned cliser, + const struct header_prot *, unsigned rw, const unsigned char *sample, unsigned char mask[16]); @@ -243,8 +243,6 @@ struct enc_sess_iquic ESI_ISCID = 1 << 15, ESI_RETRY = 1 << 16, /* Connection was retried */ } esi_flags; - enum evp_aead_direction_t - esi_dir[2]; /* client, server */ enum enc_level esi_last_w; unsigned esi_trasec_sz; char *esi_hostname; @@ -278,14 +276,14 @@ struct enc_sess_iquic static void gen_hp_mask_aes (struct enc_sess_iquic *enc_sess, - const struct header_prot *hp, unsigned cliser, + const struct header_prot *hp, unsigned rw, const unsigned char *sample, unsigned char mask[EVP_MAX_BLOCK_LENGTH]) { 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[cliser], 0) + 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); @@ -304,7 +302,7 @@ gen_hp_mask_aes (struct enc_sess_iquic *enc_sess, static void gen_hp_mask_chacha20 (struct enc_sess_iquic *enc_sess, - const struct header_prot *hp, unsigned cliser, + const struct header_prot *hp, unsigned rw, const unsigned char *sample, unsigned char mask[EVP_MAX_BLOCK_LENGTH]) { const uint8_t *nonce; @@ -317,19 +315,19 @@ 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[cliser], nonce, counter); + hp->hp_buf[rw], nonce, counter); } static void apply_hp (struct enc_sess_iquic *enc_sess, - const struct header_prot *hp, unsigned cliser, + const struct header_prot *hp, unsigned char *dst, 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, cliser, dst + packno_off + 4, mask); + 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) @@ -380,7 +378,7 @@ 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, unsigned cliser, + const struct header_prot *hp, const unsigned char *iv, unsigned char *dst, unsigned packno_off, unsigned *packno_len) { @@ -390,7 +388,7 @@ strip_hp (struct enc_sess_iquic *enc_sess, unsigned char mask[EVP_MAX_BLOCK_LENGTH]; char mask_str[5 * 2 + 1]; - hp->hp_gen_mask(enc_sess, hp, cliser, iv, mask); + hp->hp_gen_mask(enc_sess, hp, 0, iv, mask); LSQ_DEBUG("strip header protection using mask %s", HEXSTR(mask, 5, mask_str)); if (enc_sess->esi_flags & ESI_RECV_QL_BITS) @@ -739,9 +737,6 @@ iquic_esfi_create_client (const char *hostname, enc_sess->esi_conn = lconn; enc_sess->esi_ver_neg = ver_neg; - enc_sess->esi_dir[0] = evp_aead_seal; - enc_sess->esi_dir[1] = evp_aead_open; - enc_sess->esi_odcid = *dcid; enc_sess->esi_flags |= ESI_ODCID; @@ -831,9 +826,6 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub, enc_sess->esi_enpub = enpub; enc_sess->esi_conn = lconn; - enc_sess->esi_dir[0] = evp_aead_open; - enc_sess->esi_dir[1] = evp_aead_seal; - if (odcid) { enc_sess->esi_odcid = *odcid; @@ -868,23 +860,31 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub, } +static const char *const rw2str[] = { "read", "write", }; + +typedef char evp_aead_enum_has_expected_values[ + (int) evp_aead_open == 0 && (int) evp_aead_seal == 1 ? 1 : -1]; +#define rw2dir(rw_) ((enum evp_aead_direction_t) (rw_)) + + +static void +log_crypto_ctx (const struct enc_sess_iquic *enc_sess, + const struct crypto_ctx *ctx, const char *name, int rw) +{ + char hexbuf[EVP_MAX_MD_SIZE * 2 + 1]; + LSQ_DEBUG("%s %s key: %s", name, rw2str[rw], + HEXSTR(ctx->yk_key_buf, ctx->yk_key_sz, hexbuf)); + LSQ_DEBUG("%s %s iv: %s", name, rw2str[rw], + HEXSTR(ctx->yk_iv_buf, ctx->yk_iv_sz, hexbuf)); +} + + static void log_crypto_pair (const struct enc_sess_iquic *enc_sess, const struct crypto_ctx_pair *pair, const char *name) { - char hexbuf[EVP_MAX_MD_SIZE * 2 + 1]; - LSQ_DEBUG("client %s key: %s", name, - HEXSTR(pair->ykp_ctx[0].yk_key_buf, pair->ykp_ctx[0].yk_key_sz, - hexbuf)); - LSQ_DEBUG("client %s iv: %s", name, - HEXSTR(pair->ykp_ctx[0].yk_iv_buf, pair->ykp_ctx[0].yk_iv_sz, - hexbuf)); - LSQ_DEBUG("server %s key: %s", name, - HEXSTR(pair->ykp_ctx[1].yk_key_buf, pair->ykp_ctx[1].yk_key_sz, - hexbuf)); - LSQ_DEBUG("server %s iv: %s", name, - HEXSTR(pair->ykp_ctx[1].yk_iv_buf, pair->ykp_ctx[1].yk_iv_sz, - hexbuf)); + log_crypto_ctx(enc_sess, &pair->ykp_ctx[0], name, 0); + log_crypto_ctx(enc_sess, &pair->ykp_ctx[1], name, 1); } @@ -893,9 +893,9 @@ 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("client %s hp: %s", name, + LSQ_DEBUG("read %s hp: %s", name, HEXSTR(hp->hp_buf[0], hp->hp_sz, hexbuf)); - LSQ_DEBUG("server %s hp: %s", name, + LSQ_DEBUG("write %s hp: %s", name, HEXSTR(hp->hp_buf[1], hp->hp_sz, hexbuf)); } @@ -909,6 +909,7 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid) struct crypto_ctx_pair *pair; struct header_prot *hp; size_t hsk_secret_sz; + unsigned cliser; unsigned char hsk_secret[EVP_MAX_MD_SIZE]; unsigned char secret[2][SHA256_DIGEST_LENGTH]; /* client, server */ char hexbuf[EVP_MAX_MD_SIZE * 2 + 1]; @@ -941,17 +942,22 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid) lsquic_qhkdf_expand(md, hsk_secret, hsk_secret_sz, CLIENT_LABEL, CLIENT_LABEL_SZ, secret[0], sizeof(secret[0])); - LSQ_DEBUG("client handshake secret: %s", - HEXSTR(secret[0], sizeof(secret[0]), hexbuf)); - if (0 != init_crypto_ctx(&pair->ykp_ctx[0], md, aead, secret[0], - sizeof(secret[0]), enc_sess->esi_dir[0])) - goto err; lsquic_qhkdf_expand(md, hsk_secret, hsk_secret_sz, SERVER_LABEL, SERVER_LABEL_SZ, secret[1], sizeof(secret[1])); - LSQ_DEBUG("server handshake secret: %s", - HEXSTR(secret[1], sizeof(secret[1]), hexbuf)); - if (0 != init_crypto_ctx(&pair->ykp_ctx[1], md, aead, secret[1], - sizeof(secret[1]), enc_sess->esi_dir[1])) + if (enc_sess->esi_flags & ESI_LOG_SECRETS) + { + LSQ_DEBUG("client handshake secret: %s", + HEXSTR(secret[0], sizeof(secret[0]), hexbuf)); + LSQ_DEBUG("server handshake secret: %s", + HEXSTR(secret[1], sizeof(secret[1]), hexbuf)); + } + + cliser = !!(enc_sess->esi_flags & ESI_SERVER); + if (0 != init_crypto_ctx(&pair->ykp_ctx[!cliser], md, aead, secret[0], + sizeof(secret[0]), rw2dir(!cliser))) + goto err; + if (0 != init_crypto_ctx(&pair->ykp_ctx[cliser], md, aead, secret[1], + sizeof(secret[1]), rw2dir(cliser))) goto err; /* [draft-ietf-quic-tls-12] Section 5.6.1: AEAD_AES_128_GCM implies @@ -960,7 +966,7 @@ setup_handshake_keys (struct enc_sess_iquic *enc_sess, const lsquic_cid_t *cid) 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[0], secret[1]); + derive_hp_secrets(hp, md, aead, sizeof(secret[0]), secret[!cliser], secret[cliser]); if (enc_sess->esi_flags & ESI_LOG_SECRETS) { @@ -1419,13 +1425,11 @@ struct crypto_params static int get_crypto_params (const struct enc_sess_iquic *enc_sess, - struct crypto_params *params) + const SSL_CIPHER *cipher, struct crypto_params *params) { - const SSL_CIPHER *cipher; unsigned key_sz, iv_sz; uint32_t id; - cipher = SSL_get_current_cipher(enc_sess->esi_ssl); id = SSL_CIPHER_get_id(cipher); LSQ_DEBUG("Negotiated cipher ID is 0x%"PRIX32, id); @@ -1475,6 +1479,9 @@ get_crypto_params (const struct enc_sess_iquic *enc_sess, return -1; } + /* FIXME: figure out why this duplicate check is here and either fix it + * or get rid of it. + */ if (key_sz > EVP_MAX_KEY_LENGTH) { LSQ_DEBUG("PN size %u is too large", key_sz); @@ -1802,7 +1809,7 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p, size_t out_sz, dst_sz; int header_sz; int ipv6; - unsigned packno_off, packno_len, cliser; + unsigned packno_off, packno_len; enum packnum_space pns; char errbuf[ERR_ERROR_STRING_BUF_LEN]; @@ -1810,17 +1817,16 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p, /* TODO Obviously, will need more logic for 0-RTT */ enc_level = pns2enc_level[ pns ]; - cliser = !!(enc_sess->esi_flags & ESI_SERVER); if (enc_level == ENC_LEV_FORW) { pair = &enc_sess->esi_pairs[ enc_sess->esi_key_phase ]; - crypto_ctx = &pair->ykp_ctx[ cliser ]; + crypto_ctx = &pair->ykp_ctx[ 1 ]; hp = &enc_sess->esi_hp; } else if (enc_sess->esi_hsk_pairs) { pair = &enc_sess->esi_hsk_pairs[ enc_level ]; - crypto_ctx = &pair->ykp_ctx[ cliser ]; + crypto_ctx = &pair->ykp_ctx[ 1 ]; hp = &enc_sess->esi_hsk_hps[ enc_level ]; } else @@ -1909,7 +1915,7 @@ 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, cliser, dst, packno_off, packno_len); + apply_hp(enc_sess, hp, dst, packno_off, packno_len); packet_out->po_enc_data = dst; packet_out->po_enc_data_sz = dst_sz; @@ -1952,7 +1958,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p, struct crypto_ctx *crypto_ctx = NULL; unsigned char nonce_buf[ sizeof(crypto_ctx->yk_iv_buf) + 8 ]; unsigned char *nonce, *begin_xor; - unsigned sample_off, packno_len, cliser, key_phase; + unsigned sample_off, packno_len, key_phase; enum enc_level enc_level; enum packnum_space pns; lsquic_packno_t packno; @@ -2000,10 +2006,9 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p, dec_packin = DECPI_TOO_SHORT; goto err; } - cliser = !(enc_sess->esi_flags & ESI_SERVER); memcpy(dst, packet_in->pi_data, sample_off); packet_in->pi_packno = - packno = strip_hp(enc_sess, hp, cliser, + packno = strip_hp(enc_sess, hp, packet_in->pi_data + sample_off, dst, packet_in->pi_header_sz, &packno_len); @@ -2012,7 +2017,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p, key_phase = (dst[0] & 0x04) > 0; pair = &enc_sess->esi_pairs[ key_phase ]; if (key_phase == enc_sess->esi_key_phase) - crypto_ctx = &pair->ykp_ctx[ cliser ]; + crypto_ctx = &pair->ykp_ctx[ 0 ]; else if (!is_valid_packno( enc_sess->esi_pairs[enc_sess->esi_key_phase].ykp_thresh) || packet_in->pi_packno @@ -2020,7 +2025,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p, { const struct ku_label kl = select_ku_label(enc_sess); lsquic_qhkdf_expand(enc_sess->esi_md, - enc_sess->esi_traffic_secrets[cliser], enc_sess->esi_trasec_sz, + enc_sess->esi_traffic_secrets[0], enc_sess->esi_trasec_sz, kl.str, kl.len, new_secret, enc_sess->esi_trasec_sz); if (enc_sess->esi_flags & ESI_LOG_SECRETS) LSQ_DEBUG("key phase changed to %u, will try decrypting using " @@ -2043,7 +2048,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p, } else { - crypto_ctx = &pair->ykp_ctx[ cliser ]; + crypto_ctx = &pair->ykp_ctx[ 0 ]; if (UNLIKELY(0 == (crypto_ctx->yk_flags & YK_INITED))) { LSQ_DEBUG("supposedly older context is not initialized (key " @@ -2058,7 +2063,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p, key_phase = 0; assert(enc_sess->esi_hsk_pairs); pair = &enc_sess->esi_hsk_pairs[ enc_level ]; - crypto_ctx = &pair->ykp_ctx[ cliser ]; + crypto_ctx = &pair->ykp_ctx[ 0 ]; if (UNLIKELY(0 == (crypto_ctx->yk_flags & YK_INITED))) { LSQ_WARN("decrypt crypto context at level %s not initialized", @@ -2128,21 +2133,21 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p, "keys", key_phase); const struct ku_label kl = select_ku_label(enc_sess); pair->ykp_thresh = packet_in->pi_packno; - pair->ykp_ctx[ cliser ] = crypto_ctx_buf; - memcpy(enc_sess->esi_traffic_secrets[ cliser ], new_secret, + pair->ykp_ctx[ 0 ] = crypto_ctx_buf; + memcpy(enc_sess->esi_traffic_secrets[ 0 ], new_secret, enc_sess->esi_trasec_sz); lsquic_qhkdf_expand(enc_sess->esi_md, - enc_sess->esi_traffic_secrets[!cliser], enc_sess->esi_trasec_sz, + enc_sess->esi_traffic_secrets[1], enc_sess->esi_trasec_sz, kl.str, kl.len, new_secret, enc_sess->esi_trasec_sz); - memcpy(enc_sess->esi_traffic_secrets[ !cliser ], new_secret, + memcpy(enc_sess->esi_traffic_secrets[1], new_secret, enc_sess->esi_trasec_sz); - s = init_crypto_ctx(&pair->ykp_ctx[ !cliser ], enc_sess->esi_md, + s = init_crypto_ctx(&pair->ykp_ctx[1], enc_sess->esi_md, enc_sess->esi_aead, new_secret, enc_sess->esi_trasec_sz, evp_aead_seal); if (s != 0) { LSQ_ERROR("could not init seal crypto ctx (key phase)"); - cleanup_crypto_ctx(&pair->ykp_ctx[ !cliser ]); + cleanup_crypto_ctx(&pair->ykp_ctx[1]); /* This is a severe error, abort connection */ enc_sess->esi_conn->cn_if->ci_internal_error(enc_sess->esi_conn, "crypto ctx failure during key phase shift"); @@ -2522,20 +2527,17 @@ typedef char enums_have_the_same_value[ (int) ssl_encryption_application == (int) ENC_LEV_FORW ? 1 : -1]; static int -cry_sm_set_encryption_secret (SSL *ssl, enum ssl_encryption_level_t level, - const uint8_t *read_secret, const uint8_t *write_secret, - size_t secret_len) +set_secret (SSL *ssl, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len, int rw) { struct enc_sess_iquic *enc_sess; struct crypto_ctx_pair *pair; struct header_prot *hp; struct crypto_params crypa; - int i; int have_alpn; const unsigned char *alpn; unsigned alpn_len; const enum enc_level enc_level = (enum enc_level) level; - const uint8_t *secrets[2]; char errbuf[ERR_ERROR_STRING_BUF_LEN]; #define hexbuf errbuf @@ -2560,13 +2562,15 @@ cry_sm_set_encryption_secret (SSL *ssl, enum ssl_encryption_level_t level, } } - if (0 != get_crypto_params(enc_sess, &crypa)) + if (0 != get_crypto_params(enc_sess, cipher, &crypa)) return 0; +/* if (enc_sess->esi_flags & ESI_SERVER) secrets[0] = read_secret, secrets[1] = write_secret; else secrets[0] = write_secret, secrets[1] = read_secret; + */ if (enc_level < ENC_LEV_FORW) { @@ -2579,39 +2583,45 @@ cry_sm_set_encryption_secret (SSL *ssl, enum ssl_encryption_level_t level, pair = &enc_sess->esi_pairs[0]; hp = &enc_sess->esi_hp; enc_sess->esi_trasec_sz = secret_len; - memcpy(enc_sess->esi_traffic_secrets[0], secrets[0], secret_len); - memcpy(enc_sess->esi_traffic_secrets[1], secrets[1], secret_len); + memcpy(enc_sess->esi_traffic_secrets[rw], secret, secret_len); enc_sess->esi_md = crypa.md; enc_sess->esi_aead = crypa.aead; } pair->ykp_thresh = IQUIC_INVALID_PACKNO; - LSQ_DEBUG("set encryption for level %u", enc_level); - for (i = 1; i >= 0; --i) - { - if (secrets[i]) - { - if (enc_sess->esi_flags & ESI_LOG_SECRETS) - LSQ_DEBUG("new %s secret: %s", i ? "server" : "client", - HEXSTR(secrets[i], secret_len, hexbuf)); - if (0 != init_crypto_ctx(&pair->ykp_ctx[i], crypa.md, - crypa.aead, secrets[i], secret_len, enc_sess->esi_dir[i])) - goto err; - } - else - assert(level == ssl_encryption_early_data); - } + if (enc_sess->esi_flags & ESI_LOG_SECRETS) + LSQ_DEBUG("set %s secret for level %u: %s", rw2str[rw], enc_level, + HEXSTR(secret, secret_len, hexbuf)); + else + LSQ_DEBUG("set %s for level %u", rw2str[rw], enc_level); - hp->hp_enc_level = enc_level; - hp->hp_cipher = crypa.hp; - hp->hp_gen_mask = crypa.gen_hp_mask; - derive_hp_secrets(hp, crypa.md, crypa.aead, secret_len, secrets[0], - secrets[1]); + if (0 != init_crypto_ctx(&pair->ykp_ctx[rw], crypa.md, + crypa.aead, secret, secret_len, rw2dir(rw))) + goto err; + + if (pair->ykp_ctx[!rw].yk_flags & YK_INITED) + { + /* 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); if (enc_sess->esi_flags & ESI_LOG_SECRETS) { - log_crypto_pair(enc_sess, pair, "new"); - log_hp(enc_sess, hp, "new"); + 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)); } return 1; @@ -2624,6 +2634,22 @@ cry_sm_set_encryption_secret (SSL *ssl, enum ssl_encryption_level_t level, } +static int +cry_sm_set_read_secret (SSL *ssl, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len) +{ + return set_secret(ssl, level, cipher, secret, secret_len, 0); +} + + +static int +cry_sm_set_write_secret (SSL *ssl, enum ssl_encryption_level_t level, + const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len) +{ + return set_secret(ssl, level, cipher, secret, secret_len, 1); +} + + static int cry_sm_write_message (SSL *ssl, enum ssl_encryption_level_t level, const uint8_t *data, size_t len) @@ -2721,7 +2747,8 @@ cry_sm_send_alert (SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) static const SSL_QUIC_METHOD cry_quic_method = { - .set_encryption_secrets = cry_sm_set_encryption_secret, + .set_read_secret = cry_sm_set_read_secret, + .set_write_secret = cry_sm_set_write_secret, .add_handshake_data = cry_sm_write_message, .flush_flight = cry_sm_flush_flight, .send_alert = cry_sm_send_alert, diff --git a/src/liblsquic/lsquic_engine.c b/src/liblsquic/lsquic_engine.c index 724715c..3045cef 100644 --- a/src/liblsquic/lsquic_engine.c +++ b/src/liblsquic/lsquic_engine.c @@ -1447,6 +1447,9 @@ lsquic_engine_destroy (lsquic_engine_t *engine) } lsquic_hash_destroy(engine->conns_hash); + while ((conn = lsquic_attq_pop(engine->attq, UINT64_MAX))) + (void) engine_decref_conn(engine, conn, LSCONN_ATTQ); + assert(0 == engine->n_conns); assert(0 == engine->mini_conns_count); if (engine->pr_queue) diff --git a/src/liblsquic/lsquic_full_conn_ietf.c b/src/liblsquic/lsquic_full_conn_ietf.c index ff0a220..9bbd305 100644 --- a/src/liblsquic/lsquic_full_conn_ietf.c +++ b/src/liblsquic/lsquic_full_conn_ietf.c @@ -591,9 +591,10 @@ wipe_path (struct ietf_full_conn *conn, unsigned path_id) static void path_chal_alarm_expired (enum alarm_id al_id, void *ctx, - lsquic_time_t expiry, lsquic_time_t now, unsigned path_id) + lsquic_time_t expiry, lsquic_time_t now) { struct ietf_full_conn *const conn = (struct ietf_full_conn *) ctx; + const unsigned path_id = al_id - AL_PATH_CHAL; struct conn_path *const copath = &conn->ifc_paths[path_id]; if (copath->cop_n_chals < sizeof(copath->cop_path_chals) @@ -614,22 +615,6 @@ path_chal_alarm_expired (enum alarm_id al_id, void *ctx, } -static void -path_chal_0_alarm_expired (enum alarm_id al_id, void *ctx, - lsquic_time_t expiry, lsquic_time_t now) -{ - path_chal_alarm_expired(al_id, ctx, expiry, now, 0); -} - - -static void -path_chal_1_alarm_expired (enum alarm_id al_id, void *ctx, - lsquic_time_t expiry, lsquic_time_t now) -{ - path_chal_alarm_expired(al_id, ctx, expiry, now, 1); -} - - /* Sending DATA_BLOCKED and STREAM_DATA_BLOCKED frames is a way to elicit * incoming packets from peer when it is too slow to read data. This is * recommended by [draft-ietf-quic-transport-25] Section 4.1. @@ -670,10 +655,10 @@ blocked_ka_alarm_expired (enum alarm_id al_id, void *ctx, static int -migra_is_on (const struct ietf_full_conn *conn) +migra_is_on (const struct ietf_full_conn *conn, unsigned path_id) { - return (conn->ifc_send_flags & SF_SEND_PATH_CHAL_ALL) - || lsquic_alarmset_are_set(&conn->ifc_alset, ALBIT_PATH_CHAL_0|ALBIT_PATH_CHAL_1); + return (conn->ifc_send_flags & (SF_SEND_PATH_CHAL << path_id)) + || lsquic_alarmset_is_set(&conn->ifc_alset, AL_PATH_CHAL + path_id); } @@ -682,7 +667,7 @@ migra_begin (struct ietf_full_conn *conn, struct conn_path *copath, struct dcid_elem *dce, const struct sockaddr *dest_sa, const struct transport_params *params) { - assert(!(migra_is_on(conn))); + assert(!(migra_is_on(conn, copath - conn->ifc_paths))); dce->de_flags |= DE_ASSIGNED; copath->cop_flags |= COP_INITIALIZED; @@ -1126,8 +1111,10 @@ ietf_full_conn_init (struct ietf_full_conn *conn, lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_PING, ping_alarm_expired, conn); lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_HANDSHAKE, handshake_alarm_expired, conn); lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_CID_THROT, cid_throt_alarm_expired, conn); - lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_PATH_CHAL_0, path_chal_0_alarm_expired, conn); - lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_PATH_CHAL_1, path_chal_1_alarm_expired, conn); + lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_PATH_CHAL_0, path_chal_alarm_expired, conn); + lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_PATH_CHAL_1, path_chal_alarm_expired, conn); + lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_PATH_CHAL_2, path_chal_alarm_expired, conn); + lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_PATH_CHAL_3, path_chal_alarm_expired, conn); lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_BLOCKED_KA, blocked_ka_alarm_expired, conn); lsquic_rechist_init(&conn->ifc_rechist[PNS_INIT], &conn->ifc_conn, 1); lsquic_rechist_init(&conn->ifc_rechist[PNS_HSK], &conn->ifc_conn, 1); @@ -5461,11 +5448,11 @@ process_retire_connection_id_frame (struct ietf_full_conn *conn, cce = find_cce_by_cid(conn, &packet_in->pi_dcid); if (cce) { + cce->cce_flags |= CCE_USED; + lconn->cn_cur_cce_idx = cce - lconn->cn_cces; LSQ_DEBUGC("current SCID was retired; set current SCID to " "%"CID_FMT" based on DCID in incoming packet", CID_BITS(&packet_in->pi_dcid)); - cce->cce_flags |= CCE_USED; - lconn->cn_cur_cce_idx = cce - lconn->cn_cces; } else LSQ_WARN("current SCID was retired; no new SCID candidate"); @@ -6310,7 +6297,7 @@ process_regular_packet (struct ietf_full_conn *conn, if (packet_in->pi_path_id != conn->ifc_cur_path_id && 0 == (conn->ifc_flags & IFC_SERVER) && !(packet_in->pi_path_id == conn->ifc_mig_path_id - && migra_is_on(conn))) + && migra_is_on(conn, conn->ifc_mig_path_id))) { /* The "known server address" is recorded in the current path. */ switch ((NP_IS_IPv6(CUR_NPATH(conn)) << 1) | diff --git a/src/liblsquic/lsquic_stream.c b/src/liblsquic/lsquic_stream.c index f4c4733..5e8776a 100644 --- a/src/liblsquic/lsquic_stream.c +++ b/src/liblsquic/lsquic_stream.c @@ -4140,6 +4140,7 @@ update_type_hist_and_check (const struct lsquic_stream *stream, 0123, /* HD+ */ 012, /* HD */ 01, /* H */ + 013, /* H+ */ /* Really HH, but we don't record it like this */ 01231, /* HD+H */ 0121, /* HDH */ };