retain innerCH.random separately
diff --git a/lib/picotls.c b/lib/picotls.c
index ebb8b0b..9aff76f 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -172,8 +172,9 @@
uint8_t config_id;
ptls_iovec_t enc;
ptls_hpke_cipher_suite_t *cipher;
- ptls_aead_context_t *aead;
uint8_t max_name_length;
+ ptls_aead_context_t *aead;
+ uint8_t inner_client_random[PTLS_HELLO_RANDOM_SIZE];
char public_name[0];
};
@@ -240,13 +241,9 @@
*/
ptls_cipher_suite_t *cipher_suite;
/**
- * clienthello.random. `outer` is the value that can be observed. `inner` is different from `outer` if ECH is used. Otherwise,
- * the two are identical.
+ * ClientHello.random that appears on the wire. When ECH is used, that of inner CH is retained separately.
*/
- struct {
- uint8_t outer[PTLS_HELLO_RANDOM_SIZE];
- uint8_t inner[PTLS_HELLO_RANDOM_SIZE];
- } client_random;
+ uint8_t client_random[PTLS_HELLO_RANDOM_SIZE];
/**
* exporter master secret (either 0rtt or 1rtt)
*/
@@ -289,6 +286,7 @@
* ECH: if used, `aead` is non-NULL
*/
struct {
+ uint8_t inner_client_random[PTLS_HELLO_RANDOM_SIZE];
ptls_aead_context_t *aead;
uint8_t config_id;
ptls_hpke_cipher_suite_t *cipher;
@@ -979,6 +977,7 @@
free(ech->enc.base);
if (ech->aead != NULL)
ptls_aead_free(ech->aead);
+ ptls_clear_memory(ech->inner_client_random, PTLS_HELLO_RANDOM_SIZE);
free(ech);
}
@@ -1094,7 +1093,8 @@
return ret;
}
-static int client_instantiate_ech(struct st_ptls_ech_client_t **ech, struct st_decoded_ech_config_t *decoded)
+static int client_instantiate_ech(struct st_ptls_ech_client_t **ech, struct st_decoded_ech_config_t *decoded,
+ void (*random_bytes)(void *, size_t))
{
ptls_buffer_t infobuf;
uint8_t infobuf_smallbuf[256];
@@ -1119,6 +1119,7 @@
if ((ret = ptls_hpke_setup_base_s(decoded->kem, decoded->cipher, &(*ech)->enc, &(*ech)->aead, decoded->public_key,
ptls_iovec_init(infobuf.base, infobuf.off))) != 0)
goto Exit;
+ random_bytes((*ech)->inner_client_random, PTLS_HELLO_RANDOM_SIZE);
Exit:
if (ret != 0 && *ech != NULL) {
@@ -1595,8 +1596,8 @@
static void log_client_random(ptls_t *tls)
{
PTLS_PROBE(CLIENT_RANDOM, tls,
- ptls_hexdump(alloca(sizeof(tls->client_random) * 2 + 1), tls->client_random.outer, PTLS_HELLO_RANDOM_SIZE));
- PTLS_LOG_CONN(client_random, tls, { PTLS_LOG_ELEMENT_HEXDUMP(bytes, tls->client_random.outer, PTLS_HELLO_RANDOM_SIZE); });
+ ptls_hexdump(alloca(sizeof(tls->client_random) * 2 + 1), tls->client_random, sizeof(tls->client_random)));
+ PTLS_LOG_CONN(client_random, tls, { PTLS_LOG_ELEMENT_HEXDUMP(bytes, tls->client_random, sizeof(tls->client_random)); });
}
#define SESSION_IDENTIFIER_MAGIC "ptls0001" /* the number should be changed upon incompatible format change */
@@ -2236,9 +2237,8 @@
struct st_decoded_ech_config_t decoded;
decode_ech_config_list(tls->ctx, &decoded, properties->client.ech.configs);
if (decoded.kem != NULL && decoded.cipher != NULL) {
- if ((ret = client_instantiate_ech(&tls->client.ech, &decoded)) != 0)
+ if ((ret = client_instantiate_ech(&tls->client.ech, &decoded, tls->ctx->random_bytes)) != 0)
goto Exit;
- tls->ctx->random_bytes(tls->client_random.inner, PTLS_HELLO_RANDOM_SIZE);
}
}
/* setup resumption-related data. If successful, resumption_secret becomes a non-zero value. */
@@ -2296,10 +2296,10 @@
/* generate true (inner) CH */
if ((ret = encode_client_hello(tls->ctx, emitter->buf, ENCODE_CH_MODE_INNER, is_second_flight, properties,
- tls->client_random.inner, tls->client.key_share_ctx, sni_name, tls->client.legacy_session_id,
- tls->client.ech, NULL, tls->client.first_ech, resumption_secret, resumption_ticket,
- obfuscated_ticket_age, tls->key_schedule->hashes[0].algo->digest_size, cookie,
- tls->client.using_early_data)) != 0)
+ tls->client.ech != NULL ? tls->client.ech->inner_client_random : tls->client_random,
+ tls->client.key_share_ctx, sni_name, tls->client.legacy_session_id, tls->client.ech, NULL,
+ tls->client.first_ech, resumption_secret, resumption_ticket, obfuscated_ticket_age,
+ tls->key_schedule->hashes[0].algo->digest_size, cookie, tls->client.using_early_data)) != 0)
goto Exit;
/* update the message hash, filling in the PSK binder HMAC if necessary */
@@ -2318,10 +2318,10 @@
if (tls->client.ech != NULL) {
/* build EncodedCHInner */
if ((ret = encode_client_hello(tls->ctx, &encoded_ch_inner, ENCODE_CH_MODE_ENCODED_INNER, is_second_flight, properties,
- tls->client_random.inner, tls->client.key_share_ctx, sni_name, tls->client.legacy_session_id,
- tls->client.ech, NULL, ptls_iovec_init(NULL, 0), resumption_secret, resumption_ticket,
- obfuscated_ticket_age, tls->key_schedule->hashes[0].algo->digest_size, cookie,
- tls->client.using_early_data)) != 0)
+ tls->client.ech->inner_client_random, tls->client.key_share_ctx, sni_name,
+ tls->client.legacy_session_id, tls->client.ech, NULL, ptls_iovec_init(NULL, 0),
+ resumption_secret, resumption_ticket, obfuscated_ticket_age,
+ tls->key_schedule->hashes[0].algo->digest_size, cookie, tls->client.using_early_data)) != 0)
goto Exit;
if (resumption_secret.base != NULL)
memcpy(encoded_ch_inner.base + encoded_ch_inner.off - tls->key_schedule->hashes[0].algo->digest_size,
@@ -2351,7 +2351,7 @@
size_t ech_payload_size = encoded_ch_inner.off - PTLS_HANDSHAKE_HEADER_SIZE + tls->client.ech->aead->algo->tag_size,
ech_size_offset = ech_payload_size;
if ((ret = encode_client_hello(tls->ctx, emitter->buf, ENCODE_CH_MODE_OUTER, is_second_flight, properties,
- tls->client_random.outer, tls->client.key_share_ctx, tls->client.ech->public_name,
+ tls->client_random, tls->client.key_share_ctx, tls->client.ech->public_name,
tls->client.legacy_session_id, tls->client.ech, &ech_size_offset, ptls_iovec_init(NULL, 0),
resumption_secret, resumption_ticket, obfuscated_ticket_age,
tls->key_schedule->hashes[0].algo->digest_size, cookie, tls->client.using_early_data)) != 0)
@@ -2610,7 +2610,8 @@
if (confirm_hash_off != 0) {
memcpy(confirm_hash_delivered, message.base + confirm_hash_off, sizeof(confirm_hash_delivered));
memset(message.base + confirm_hash_off, 0, sizeof(confirm_hash_delivered));
- if ((ret = ech_calc_confirmation(tls->key_schedule, confirm_hash_expected, tls->client_random.inner, label, message)) != 0)
+ if ((ret = ech_calc_confirmation(tls->key_schedule, confirm_hash_expected, tls->client.ech->inner_client_random, label,
+ message)) != 0)
goto Exit;
int ech_accepted = ptls_mem_equal(confirm_hash_delivered, confirm_hash_expected, sizeof(confirm_hash_delivered));
memcpy(message.base + confirm_hash_off, confirm_hash_delivered, sizeof(confirm_hash_delivered));
@@ -2621,7 +2622,6 @@
/* dispose ECH state, adopting outer CH for the rest of the handshake */
client_free_ech(tls->client.ech);
tls->client.ech = NULL;
- memcpy(tls->client_random.inner, tls->client_random.outer, PTLS_HELLO_RANDOM_SIZE);
key_schedule_select_outer(tls->key_schedule);
Exit:
@@ -3998,7 +3998,7 @@
hctx->update(hctx, b, 2); \
} while (0)
- UPDATE_BLOCK(tls->client_random.inner, PTLS_HELLO_RANDOM_SIZE);
+ UPDATE_BLOCK(tls->client_random, sizeof(tls->client_random));
UPDATE_BLOCK(tls->server_name, tls->server_name != NULL ? strlen(tls->server_name) : 0);
UPDATE16(tls->cipher_suite->id);
UPDATE16(negotiated_group->id);
@@ -4099,12 +4099,10 @@
if ((ret = decode_client_hello(tls->ctx, ch, message.base + PTLS_HANDSHAKE_HEADER_SIZE, message.base + message.len, properties,
tls)) != 0)
goto Exit;
- if ((ret = check_client_hello_constraints(tls->ctx, ch, is_second_flight ? tls->client_random.outer : NULL, 0, message, tls)) !=
- 0)
+ if ((ret = check_client_hello_constraints(tls->ctx, ch, is_second_flight ? tls->client_random : NULL, 0, message, tls)) != 0)
goto Exit;
if (!is_second_flight) {
- memcpy(tls->client_random.outer, ch->random_bytes, PTLS_HELLO_RANDOM_SIZE);
- memcpy(tls->client_random.inner, ch->random_bytes, PTLS_HELLO_RANDOM_SIZE);
+ memcpy(tls->client_random, ch->random_bytes, PTLS_HELLO_RANDOM_SIZE);
log_client_random(tls);
} else {
/* consistency check for ECH extension in response to HRR */
@@ -4162,11 +4160,11 @@
if ((ret = decode_client_hello(tls->ctx, ch, ech.ch_inner.base + PTLS_HANDSHAKE_HEADER_SIZE,
ech.ch_inner.base + ech.ch_inner.off, properties, tls)) != 0)
goto Exit;
- if ((ret = check_client_hello_constraints(tls->ctx, ch, is_second_flight ? tls->client_random.inner : NULL, 1,
- message, tls)) != 0)
+ if ((ret = check_client_hello_constraints(
+ tls->ctx, ch, is_second_flight ? tls->server.ech.inner_client_random : NULL, 1, message, tls)) != 0)
goto Exit;
if (!is_second_flight)
- memcpy(tls->client_random.inner, ch->random_bytes, PTLS_HELLO_RANDOM_SIZE);
+ memcpy(tls->server.ech.inner_client_random, ch->random_bytes, PTLS_HELLO_RANDOM_SIZE);
} else {
/* decryption failure indicates key mismatch; dispose of AEAD context to indicate that outerCH is adopted */
ptls_aead_free(tls->server.ech.aead);
@@ -4341,7 +4339,7 @@
{
if (ech_confirm_off != 0 &&
(ret = ech_calc_confirmation(
- tls->key_schedule, emitter->buf->base + ech_confirm_off, tls->client_random.inner,
+ tls->key_schedule, emitter->buf->base + ech_confirm_off, tls->server.ech.inner_client_random,
ECH_CONFIRMATION_HRR,
ptls_iovec_init(emitter->buf->base + sh_start_off, emitter->buf->off - sh_start_off))) != 0)
goto Exit;
@@ -4453,10 +4451,11 @@
}
},
{
- if (ech_confirm_off != 0 && (ret = ech_calc_confirmation(tls->key_schedule, emitter->buf->base + ech_confirm_off,
- tls->client_random.inner, ECH_CONFIRMATION_SERVER_HELLO,
- ptls_iovec_init(emitter->buf->base + sh_start_off,
- emitter->buf->off - sh_start_off))) != 0)
+ if (ech_confirm_off != 0 &&
+ (ret = ech_calc_confirmation(
+ tls->key_schedule, emitter->buf->base + ech_confirm_off, tls->server.ech.inner_client_random,
+ ECH_CONFIRMATION_SERVER_HELLO,
+ ptls_iovec_init(emitter->buf->base + sh_start_off, emitter->buf->off - sh_start_off))) != 0)
goto Exit;
});
}
@@ -4766,8 +4765,7 @@
{
ptls_t *tls = new_instance(ctx, 0);
tls->state = PTLS_STATE_CLIENT_HANDSHAKE_START;
- tls->ctx->random_bytes(tls->client_random.outer, PTLS_HELLO_RANDOM_SIZE);
- memcpy(tls->client_random.inner, tls->client_random.outer, PTLS_HELLO_RANDOM_SIZE);
+ tls->ctx->random_bytes(tls->client_random, sizeof(tls->client_random));
log_client_random(tls);
if (tls->send_change_cipher_spec) {
tls->client.legacy_session_id =
@@ -4874,7 +4872,7 @@
ptls_iovec_t negotiated_protocol =
ptls_iovec_init(tls->negotiated_protocol, tls->negotiated_protocol != NULL ? strlen(tls->negotiated_protocol) : 0);
- return export_tls12_params(output, tls->is_server, tls->is_psk_handshake, tls->cipher_suite, tls->client_random.outer,
+ return export_tls12_params(output, tls->is_server, tls->is_psk_handshake, tls->cipher_suite, tls->client_random,
tls->server_name, negotiated_protocol, tls->traffic_protection.enc.secret,
tls->traffic_protection.enc.secret + PTLS_MAX_SECRET_SIZE, tls->traffic_protection.enc.seq,
tls->traffic_protection.enc.tls12_enc_record_iv, tls->traffic_protection.dec.secret,
@@ -4943,8 +4941,7 @@
ret = PTLS_ALERT_DECODE_ERROR;
goto Exit;
}
- memcpy((*tls)->client_random.outer, src, PTLS_HELLO_RANDOM_SIZE);
- memcpy((*tls)->client_random.inner, src, PTLS_HELLO_RANDOM_SIZE);
+ memcpy((*tls)->client_random, src, PTLS_HELLO_RANDOM_SIZE);
src += PTLS_HELLO_RANDOM_SIZE;
ptls_decode_open_block(src, end, 2, {
if (src != end) {
@@ -5048,7 +5045,7 @@
ptls_iovec_t ptls_get_client_random(ptls_t *tls)
{
- return ptls_iovec_init(tls->client_random.outer, PTLS_HELLO_RANDOM_SIZE);
+ return ptls_iovec_init(tls->client_random, PTLS_HELLO_RANDOM_SIZE);
}
ptls_cipher_suite_t *ptls_get_cipher(ptls_t *tls)