[ECH] add I/F to obtain kem/cipher being used
diff --git a/include/picotls.h b/include/picotls.h
index 1be5fd2..b9048a4 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -717,8 +717,8 @@
* corresponding private key, invokes `ptls_hpke_setup_base_r` with provided `cipher`, `enc`, and `info_prefix` (which will be
* "tls ech" || 00).
*/
-PTLS_CALLBACK_TYPE(ptls_aead_context_t *, ech_create_opener, ptls_t *tls, uint8_t config_id, ptls_hpke_cipher_suite_t *cipher,
- ptls_iovec_t enc, ptls_iovec_t info_prefix);
+PTLS_CALLBACK_TYPE(ptls_aead_context_t *, ech_create_opener, ptls_hpke_kem_t **kem, ptls_t *tls, uint8_t config_id,
+ ptls_hpke_cipher_suite_t *cipher, ptls_iovec_t enc, ptls_iovec_t info_prefix);
/**
* the configuration
@@ -1448,9 +1448,9 @@
*/
int ptls_is_psk_handshake(ptls_t *tls);
/**
- * return if a ECH handshake was performed
+ * return if a ECH handshake was performed, as well as optionally the kem and cipher-suite being used
*/
-int ptls_is_ech_handshake(ptls_t *tls);
+int ptls_is_ech_handshake(ptls_t *tls, ptls_hpke_kem_t **kem, ptls_hpke_cipher_suite_t **cipher);
/**
* returns a pointer to user data pointer (client is reponsible for freeing the associated data prior to calling ptls_free)
*/
diff --git a/lib/picotls.c b/lib/picotls.c
index 9aff76f..7280d57 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -171,6 +171,7 @@
struct st_ptls_ech_client_t {
uint8_t config_id;
ptls_iovec_t enc;
+ ptls_hpke_kem_t *kem;
ptls_hpke_cipher_suite_t *cipher;
uint8_t max_name_length;
ptls_aead_context_t *aead;
@@ -289,6 +290,7 @@
uint8_t inner_client_random[PTLS_HELLO_RANDOM_SIZE];
ptls_aead_context_t *aead;
uint8_t config_id;
+ ptls_hpke_kem_t *kem;
ptls_hpke_cipher_suite_t *cipher;
unsigned offered_by_client : 1;
} ech;
@@ -1109,7 +1111,7 @@
goto Exit;
}
**ech = (struct st_ptls_ech_client_t){
- .config_id = decoded->id, .cipher = decoded->cipher, .max_name_length = decoded->max_name_length};
+ .config_id = decoded->id, .kem = decoded->kem, .cipher = decoded->cipher, .max_name_length = decoded->max_name_length};
memcpy((*ech)->public_name, decoded->public_name.base, decoded->public_name.len);
(*ech)->public_name[decoded->public_name.len] = '\0';
@@ -2804,7 +2806,7 @@
goto Exit;
}
/* accept retry_configs only if we offered ECH but rejected */
- if (tls->client.first_ech.base == NULL || ptls_is_ech_handshake(tls)) {
+ if (tls->client.first_ech.base == NULL || ptls_is_ech_handshake(tls, NULL, NULL)) {
ret = PTLS_ALERT_UNSUPPORTED_EXTENSION;
goto Exit;
}
@@ -3231,7 +3233,7 @@
ptls__key_schedule_update_hash(tls->key_schedule, message.base, message.len, 0);
/* if ECH was rejected, close the connection with ECH_REQUIRED alert after verifying messages up to Finished */
- if (tls->client.first_ech.base != NULL && !ptls_is_ech_handshake(tls)) {
+ if (tls->client.first_ech.base != NULL && !ptls_is_ech_handshake(tls, NULL, NULL)) {
ret = PTLS_ALERT_ECH_REQUIRED;
goto Exit;
}
@@ -4131,7 +4133,7 @@
if (!is_second_flight && ch->ech.cipher != NULL && ch->ech.payload.len > ch->ech.cipher->aead->tag_size &&
tls->ctx->ech.create_opener != NULL) {
if ((tls->server.ech.aead = tls->ctx->ech.create_opener->cb(
- tls->ctx->ech.create_opener, tls, ch->ech.config_id, ch->ech.cipher, ch->ech.enc,
+ tls->ctx->ech.create_opener, &tls->server.ech.kem, tls, ch->ech.config_id, ch->ech.cipher, ch->ech.enc,
ptls_iovec_init(ech_info_prefix, sizeof(ech_info_prefix)))) != NULL) {
tls->server.ech.config_id = ch->ech.config_id;
tls->server.ech.cipher = ch->ech.cipher;
@@ -4283,7 +4285,8 @@
/* Either send a stateless retry (w. cookies) or a stateful one. When sending the latter, run the state machine. At the
* moment, stateless retry is disabled when ECH is used (do we need to support it?). */
- int retry_uses_cookie = properties != NULL && properties->server.retry_uses_cookie && !ptls_is_ech_handshake(tls);
+ int retry_uses_cookie =
+ properties != NULL && properties->server.retry_uses_cookie && !ptls_is_ech_handshake(tls, NULL, NULL);
if (!retry_uses_cookie) {
key_schedule_transform_post_ch1hash(tls->key_schedule);
key_schedule_extract(tls->key_schedule, ptls_iovec_init(NULL, 0));
@@ -4293,7 +4296,7 @@
tls->key_schedule, key_share.algorithm != NULL ? NULL : negotiated_group,
{
ptls_buffer_t *sendbuf = emitter->buf;
- if (ptls_is_ech_handshake(tls)) {
+ if (ptls_is_ech_handshake(tls, NULL, NULL)) {
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_ENCRYPTED_CLIENT_HELLO, {
if ((ret = ptls_buffer_reserve(sendbuf, 8)) != 0)
goto Exit;
@@ -4432,7 +4435,7 @@
{
tls->ctx->random_bytes(emitter->buf->base + emitter->buf->off, PTLS_HELLO_RANDOM_SIZE);
/* when accepting CHInner, last 8 byte of SH.random is zero for the handshake transcript */
- if (ptls_is_ech_handshake(tls)) {
+ if (ptls_is_ech_handshake(tls, NULL, NULL)) {
ech_confirm_off = emitter->buf->off + PTLS_HELLO_RANDOM_SIZE - 8;
memset(emitter->buf->base + ech_confirm_off, 0, 8);
}
@@ -4505,7 +4508,8 @@
}
if (tls->pending_handshake_secret != NULL)
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_EARLY_DATA, {});
- if (tls->server.ech.offered_by_client && !ptls_is_ech_handshake(tls) && tls->ctx->ech.retry_configs.len != 0)
+ if (tls->server.ech.offered_by_client && !ptls_is_ech_handshake(tls, NULL, NULL) &&
+ tls->ctx->ech.retry_configs.len != 0)
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_ENCRYPTED_CLIENT_HELLO, {
ptls_buffer_pushv(sendbuf, tls->ctx->ech.retry_configs.base, tls->ctx->ech.retry_configs.len);
});
@@ -5131,13 +5135,26 @@
return tls->is_psk_handshake;
}
-int ptls_is_ech_handshake(ptls_t *tls)
+int ptls_is_ech_handshake(ptls_t *tls, ptls_hpke_kem_t **kem, ptls_hpke_cipher_suite_t **cipher)
{
if (tls->is_server) {
- return tls->server.ech.aead != NULL;
+ if (tls->server.ech.aead != NULL) {
+ if (kem != NULL)
+ *kem = tls->server.ech.kem;
+ if (cipher != NULL)
+ *cipher = tls->server.ech.cipher;
+ return 1;
+ }
} else {
- return tls->client.ech != NULL;
+ if (tls->client.ech != NULL) {
+ if (kem != NULL)
+ *kem = tls->client.ech->kem;
+ if (cipher != NULL)
+ *cipher = tls->client.ech->cipher;
+ return 1;
+ }
}
+ return 0;
}
void **ptls_get_data_ptr(ptls_t *tls)
diff --git a/t/cli.c b/t/cli.c
index ca1ab88..9ae3cd9 100644
--- a/t/cli.c
+++ b/t/cli.c
@@ -78,7 +78,7 @@
return NULL;
}
-static ptls_aead_context_t *create_ech_opener(ptls_ech_create_opener_t *self, ptls_t *tls, uint8_t config_id,
+static ptls_aead_context_t *create_ech_opener(ptls_ech_create_opener_t *self, ptls_hpke_kem_t **kem, ptls_t *tls, uint8_t config_id,
ptls_hpke_cipher_suite_t *cipher, ptls_iovec_t enc, ptls_iovec_t info_prefix)
{
const uint8_t *src = ech.config_list.base, *const end = src + ech.config_list.len;
@@ -105,6 +105,7 @@
ptls_hpke_setup_base_r(ech.keyex.list[index].kem, cipher, ech.keyex.list[index].ctx, &aead, enc,
ptls_iovec_init(info, info_prefix.len + end - (src - 4)));
free(info);
+ *kem = ech.keyex.list[index].kem;
return aead;
}
++index;
diff --git a/t/openssl.c b/t/openssl.c
index da3c733..38ca629 100644
--- a/t/openssl.c
+++ b/t/openssl.c
@@ -328,7 +328,7 @@
test_hpke(ptls_openssl_hpke_kems, ptls_openssl_hpke_cipher_suites);
}
-static ptls_aead_context_t *create_ech_opener(ptls_ech_create_opener_t *self, ptls_t *tls, uint8_t config_id,
+static ptls_aead_context_t *create_ech_opener(ptls_ech_create_opener_t *self, ptls_hpke_kem_t **kem, ptls_t *tls, uint8_t config_id,
ptls_hpke_cipher_suite_t *cipher, ptls_iovec_t enc, ptls_iovec_t info_prefix)
{
static ptls_key_exchange_context_t *pem = NULL;
diff --git a/t/picotls.c b/t/picotls.c
index d50c784..6612455 100644
--- a/t/picotls.c
+++ b/t/picotls.c
@@ -909,11 +909,11 @@
}
if (can_ech(ctx_peer, 1) && can_ech(ctx, 0)) {
- ok(ptls_is_ech_handshake(client));
- ok(ptls_is_ech_handshake(server));
+ ok(ptls_is_ech_handshake(client, NULL, NULL));
+ ok(ptls_is_ech_handshake(server, NULL, NULL));
} else {
- ok(!ptls_is_ech_handshake(client));
- ok(!ptls_is_ech_handshake(server));
+ ok(!ptls_is_ech_handshake(client, NULL, NULL));
+ ok(!ptls_is_ech_handshake(server, NULL, NULL));
}
ptls_buffer_dispose(&cbuf);