Compare commits

...

2 Commits

Author SHA1 Message Date
Steven Valdez 98aaf4eda3 Clang formatting.
Change-Id: I31e9fb52fb2f7e800ded73076f3da1b7fac716c5
2019-08-15 15:30:33 -04:00
Steven Valdez b641b6aaab In-Progress ESNI draft 04.
Change-Id: Idaebefde3f23f747d5660b46b0f90b2cbe4e6db9
2019-07-21 11:52:36 -04:00
8 changed files with 549 additions and 15 deletions
+25
View File
@@ -619,6 +619,8 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl);
#define DTLS1_VERSION 0xfeff
#define DTLS1_2_VERSION 0xfefd
#define ESNI_VERSION 0xff03
// SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to
// |version|. If |version| is zero, the default minimum version is used. It
// returns one on success and zero if |version| is invalid.
@@ -3906,6 +3908,29 @@ OPENSSL_EXPORT int SSL_is_tls13_downgrade(const SSL *ssl);
OPENSSL_EXPORT void SSL_set_jdk11_workaround(SSL *ssl, int enable);
// ESNI functions.
// SSL_set_enable_esni configures whether to use ESNI as part of this
// connection.
OPENSSL_EXPORT void SSL_set_enable_esni(SSL *ssl, int enable);
// SSL_set_esni_keys sets the ESNIKeys structure that should be used for
// connections to the server.
OPENSSL_EXPORT int SSL_set_esni_keys(SSL *ssl, const uint8_t *key_struct,
size_t key_len);
// SSL_set_esni_private_key sets the keypair that the server should use to decrypt ESNI.
//
// TODO: Support multiple keypairs.
OPENSSL_EXPORT int SSL_set_esni_private_key(SSL *ssl, const uint8_t *pub,
size_t pub_len, const uint8_t *priv,
size_t priv_len);
// SSL_get_retry_keys returns the ESNIKeys structure that was returned by the
// server if ESNI was rejected or a retry was requested.
OPENSSL_EXPORT void SSL_get_retry_keys(SSL *ssl);
// Deprecated functions.
// SSL_library_init calls |CRYPTO_library_init| and returns one.
+3
View File
@@ -235,6 +235,9 @@ extern "C" {
// extension number.
#define TLSEXT_TYPE_delegated_credential 0xff02
// ExtensionType value from draft-ietf-tls-esni.
#define TLSEXT_TYPE_encrypted_server_name 0xffce
// ExtensionType value from RFC6962
#define TLSEXT_TYPE_certificate_timestamp 18
+34 -9
View File
@@ -526,6 +526,40 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_handoff;
}
hs->client_version = client_hello.version;
if (client_hello.random_len != SSL3_RANDOM_SIZE) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_hs_error;
}
OPENSSL_memcpy(ssl->s3->client_random, client_hello.random,
client_hello.random_len);
CBS encrypted_sni;
if (ssl_client_hello_get_extension(&client_hello, &encrypted_sni,
TLSEXT_TYPE_encrypted_server_name)) {
CBS key_share, kse_bytes;
if (!ssl_client_hello_get_extension(&client_hello, &key_share,
TLSEXT_TYPE_key_share)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
if (!CBS_get_u16_length_prefixed(&key_share, &kse_bytes) ||
!hs->key_share_bytes.CopyFrom(
MakeConstSpan(CBS_data(&kse_bytes), CBS_len(&kse_bytes)))) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!ssl_ext_encrypted_server_name_parse_clienthello(hs, &alert, &encrypted_sni)) {
ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
return ssl_hs_error;
}
}
// Run the early callback.
if (ssl->ctx->select_certificate_cb != NULL) {
switch (ssl->ctx->select_certificate_cb(&client_hello)) {
@@ -559,14 +593,6 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
hs->client_version = client_hello.version;
if (client_hello.random_len != SSL3_RANDOM_SIZE) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_hs_error;
}
OPENSSL_memcpy(ssl->s3->client_random, client_hello.random,
client_hello.random_len);
// Only null compression is supported. TLS 1.3 further requires the peer
// advertise no other compression.
if (OPENSSL_memchr(client_hello.compression_methods, 0,
@@ -577,7 +603,6 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
// TLS extensions.
if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+39
View File
@@ -1315,6 +1315,22 @@ bool tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
const SSLMessage &msg, CBS *binders);
// ESNI
enum ssl_esni_state_t {
ssl_esni_unknown = 0,
ssl_esni_attempted = 1,
ssl_esni_verified = 2,
ssl_esni_retry_required = 3,
};
bool tls13_derive_esni_secrets(SSL_HANDSHAKE *hs, Array<uint8_t> shared_secret);
bool ssl_ext_encrypted_server_name_parse_clienthello(SSL_HANDSHAKE *hs,
uint8_t *out_alert,
CBS *contents);
// Handshake functions.
enum ssl_hs_wait_t {
@@ -1562,6 +1578,18 @@ struct SSL_HANDSHAKE {
// key_block is the record-layer key block for TLS 1.2 and earlier.
Array<uint8_t> key_block;
// esni_state is the state of ESNI for this connection.
enum ssl_esni_state_t esni_state;
// esni_nonce is the nonce used for ESNI in this connection.
uint8_t esni_nonce[16];
uint8_t esni_iv[EVP_AEAD_MAX_NONCE_LENGTH];
size_t esni_iv_len;
// esni_aead_ctx is the AEAD CTX to use with ESNI.
ScopedEVP_AEAD_CTX esni_aead_ctx;
// scts_requested is true if the SCT extension is in the ClientHello.
bool scts_requested : 1;
@@ -2549,6 +2577,14 @@ struct SSL_CONFIG {
// verify_mode is a bitmask of |SSL_VERIFY_*| values.
uint8_t verify_mode = SSL_VERIFY_NONE;
CBS esni_public_name;
uint16_t esni_group = 0;
const SSL_CIPHER *esni_cipher = nullptr;
Array<uint8_t> esni_server_keyshare;
Array<uint8_t> esni_record_digest;
uint16_t esni_padded_length = 0;
Array<uint8_t> esni_private;
// Enable signed certificate time stamps. Currently client only.
bool signed_cert_timestamps_enabled : 1;
@@ -2588,6 +2624,9 @@ struct SSL_CONFIG {
// jdk11_workaround is whether to disable TLS 1.3 for JDK 11 clients, as a
// workaround for https://bugs.openjdk.java.net/browse/JDK-8211806.
bool jdk11_workaround : 1;
// enable_esni is whether the connection should attempt to use ESNI.
bool enable_esni : 1;
};
// From RFC 8446, used in determining PSK modes.
+98 -1
View File
@@ -735,7 +735,8 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg)
handoff(false),
shed_handshake_config(false),
ignore_tls13_downgrade(false),
jdk11_workaround(false) {
jdk11_workaround(false),
enable_esni(false) {
assert(ssl);
}
@@ -2849,6 +2850,102 @@ void SSL_set_jdk11_workaround(SSL *ssl, int enable) {
ssl->config->jdk11_workaround = !!enable;
}
void SSL_set_enable_esni(SSL *ssl, int enable) {
if (!ssl->config) {
return;
}
ssl->config->enable_esni = !!enable;
}
int SSL_set_esni_keys(SSL *ssl, const uint8_t *key_struct, size_t key_len) {
if (!ssl->config->enable_esni) {
return false;
}
CBS esni_keys, public_name, keys, cipher_suites, extensions;
uint16_t version;
CBS_init(&esni_keys, key_struct, key_len);
if (!CBS_get_u16(&esni_keys, &version) ||
version != ESNI_VERSION ||
!CBS_get_u16_length_prefixed(&esni_keys,
&ssl->config->esni_public_name) ||
!CBS_get_u16_length_prefixed(&esni_keys, &keys) ||
!CBS_get_u16_length_prefixed(&esni_keys, &cipher_suites) ||
!CBS_get_u16(&esni_keys, &ssl->config->esni_padded_length) ||
!CBS_get_u16_length_prefixed(&esni_keys, &extensions)) {
return false;
}
// TODO(svaldez): Handle extensions.
static const uint16_t kDefaultGroups[] = {
SSL_CURVE_X25519,
SSL_CURVE_SECP256R1,
SSL_CURVE_SECP384R1,
};
Span<const uint16_t> supp = Span<const uint16_t>(kDefaultGroups);
if (!ssl->config->supported_group_list.empty()) {
supp = ssl->config->supported_group_list;
}
CBS esni_keyshare_bytes;
for (uint16_t supp_group : supp) {
CBS copy = keys;
uint16_t group;
while (CBS_len(&copy) > 0) {
if (!CBS_get_u16(&copy, &group) ||
!CBS_get_u16_length_prefixed(&copy, &esni_keyshare_bytes)) {
return false;
}
if (group == supp_group) {
ssl->config->esni_group = supp_group;
break;
}
}
if (ssl->config->esni_group != 0) {
break;
}
}
if (ssl->config->esni_group == 0) {
return false;
}
ssl->config->esni_server_keyshare.CopyFrom(esni_keyshare_bytes);
ssl->config->esni_cipher = ssl_choose_tls13_cipher(
cipher_suites, TLS1_3_VERSION, ssl->config->esni_group);
if (!ssl->config->esni_cipher) {
return false;
}
const EVP_MD *digest =
ssl_get_handshake_digest(TLS1_3_VERSION, ssl->config->esni_cipher);
uint8_t esni_digest[EVP_MAX_MD_SIZE];
unsigned esni_digest_len;
if (!EVP_Digest(key_struct, key_len, esni_digest, &esni_digest_len, digest,
NULL) ||
!ssl->config->esni_record_digest.CopyFrom(
Span<uint8_t>(esni_digest, esni_digest_len))) {
return false;
}
return true;
}
// TODO(svaldez): Support multiple ESNIKeys structs on the server.
int SSL_set_esni_private_key(SSL *ssl, const uint8_t *pub, size_t pub_len,
const uint8_t *priv, size_t priv_len) {
if (!ssl->config->enable_esni) {
return false;
}
ssl->config->esni_server_keyshare.CopyFrom(Span<const uint8_t>(pub, pub_len));
ssl->config->esni_private.CopyFrom(Span<const uint8_t>(priv, priv_len));
return true;
}
// TODO: Get Retry Keys.
int SSL_clear(SSL *ssl) {
if (!ssl->config) {
return 0; // SSL_clear may not be used after shedding config.
+69
View File
@@ -4080,6 +4080,75 @@ TEST(SSLTest, CertCompression) {
EXPECT_TRUE(SSL_get_app_data(server.get()) == XORCompressFunc);
}
TEST(SSLTest, ESNI) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
ASSERT_TRUE(cert);
ASSERT_TRUE(key);
ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get()));
ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
bssl::UniquePtr<SSL> client(SSL_new(client_ctx.get())),
server(SSL_new(server_ctx.get()));
ASSERT_TRUE(client);
ASSERT_TRUE(server);
SSL_set_connect_state(client.get());
SSL_set_accept_state(server.get());
ASSERT_TRUE(SSL_set_tlsext_host_name(client.get(), "esni-test.com"));
SSL_set_enable_esni(client.get(), true);
SSL_set_enable_esni(server.get(), true);
UniquePtr<SSLKeyShare> keyshare = SSLKeyShare::Create(SSL_CURVE_X25519);
CBB key_struct, public_name, keys, kse_bytes, kse_bytes_c, cipher_suites;
if (!CBB_init(&key_struct, 0) ||
!CBB_add_u16(&key_struct, ESNI_VERSION) ||
!CBB_add_u16_length_prefixed(&key_struct, &public_name) ||
!CBB_add_bytes(&public_name, (const uint8_t *)"pn-test.com",
strlen("pn-test.com")) ||
!CBB_add_u16_length_prefixed(&key_struct, &keys) ||
!CBB_add_u16(&keys, SSL_CURVE_X25519) ||
!CBB_add_u16_length_prefixed(&keys, &kse_bytes)) {
ASSERT_TRUE(false);
}
kse_bytes_c = kse_bytes;
if (!keyshare->Offer(&kse_bytes) ||
!CBB_add_u16_length_prefixed(&key_struct, &cipher_suites) ||
!CBB_add_u16(&cipher_suites, 0x1303) ||
!CBB_add_u16(&key_struct, 32) ||
!CBB_add_u16(&key_struct, 0) ||
!CBB_flush(&key_struct)) {
ASSERT_TRUE(false);
}
ASSERT_TRUE(SSL_set_esni_keys(client.get(), CBB_data(&key_struct),
CBB_len(&key_struct)));
CBB private_key;
ASSERT_TRUE(CBB_init(&private_key, 0));
ASSERT_TRUE(keyshare->Serialize(&private_key));
ASSERT_TRUE(SSL_set_esni_private_key(
server.get(), CBB_data(&kse_bytes_c), CBB_len(&kse_bytes_c) - 8,
CBB_data(&private_key), CBB_len(&private_key)));
BIO *bio1, *bio2;
ASSERT_TRUE(BIO_new_bio_pair(&bio1, 0, &bio2, 0));
// SSL_set_bio takes ownership.
SSL_set_bio(client.get(), bio1, bio1);
SSL_set_bio(server.get(), bio2, bio2);
ASSERT_TRUE(CompleteHandshakes(client.get(), server.get()));
printf("%s\n", SSL_get_servername(server.get(), TLSEXT_NAMETYPE_host_name));
}
void MoveBIOs(SSL *dest, SSL *src) {
BIO *rbio = SSL_get_rbio(src);
BIO_up_ref(rbio);
+221 -5
View File
@@ -614,14 +614,23 @@ static bool ext_sni_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) {
!CBB_add_u16_length_prefixed(out, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &server_name_list) ||
!CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name) ||
!CBB_add_u16_length_prefixed(&server_name_list, &name) ||
!CBB_add_bytes(&name, (const uint8_t *)ssl->hostname.get(),
strlen(ssl->hostname.get())) ||
!CBB_flush(out)) {
!CBB_add_u16_length_prefixed(&server_name_list, &name)) {
return false;
}
return true;
if (hs->config->enable_esni && hs->config->esni_group != 0) {
if (!CBB_add_bytes(&name, CBS_data(&ssl->config->esni_public_name),
CBS_len(&ssl->config->esni_public_name))) {
return false;
}
} else {
if (!CBB_add_bytes(&name, (const uint8_t *)ssl->hostname.get(),
strlen(ssl->hostname.get()))) {
return false;
}
}
return CBB_flush(out);
}
static bool ext_sni_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
@@ -2947,6 +2956,205 @@ static bool ext_pq_experiment_signal_add_serverhello(SSL_HANDSHAKE *hs,
return true;
}
// Encrypted Server Name
//
// https://tools.ietf.org/html/draft-ietf-tls-esni
// TODO: Move this out of the callbacks to do early.
static bool ext_encrypted_server_name_add_clienthello(SSL_HANDSHAKE *hs,
CBB *out) {
SSL *const ssl = hs->ssl;
if (!hs->config->enable_esni || SSL_is_dtls(ssl) ||
hs->config->esni_group == 0) {
return true;
}
hs->esni_state = ssl_esni_attempted;
CBB contents, kse_bytes, key_exchange, record_digest, esni;
if (!CBB_add_u16(out, TLSEXT_TYPE_encrypted_server_name) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
!CBB_add_u16(&contents, ssl_cipher_get_value(ssl->config->esni_cipher)) ||
!CBB_add_u16_length_prefixed(&contents, &kse_bytes) ||
!CBB_add_u16(&kse_bytes, ssl->config->esni_group) ||
!CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange)) {
return false;
}
UniquePtr<SSLKeyShare> esni_client_share =
SSLKeyShare::Create(ssl->config->esni_group);
Array<uint8_t> shared_secret;
uint8_t alert;
if (!esni_client_share ||
!esni_client_share->Accept(&key_exchange, &shared_secret, &alert,
ssl->config->esni_server_keyshare)) {
return false;
}
if (!CBB_add_u16_length_prefixed(&contents, &record_digest) ||
!CBB_add_bytes(&record_digest, ssl->config->esni_record_digest.data(),
ssl->config->esni_record_digest.size()) ||
!CBB_add_u16_length_prefixed(&contents, &esni)) {
return false;
}
if (!RAND_bytes(hs->esni_nonce, sizeof(hs->esni_nonce))) {
return false;
}
if (!tls13_derive_esni_secrets(hs, std::move(shared_secret))) {
return false;
}
size_t padding_len = ssl->config->esni_padded_length - strlen(ssl->hostname.get());
CBB client_esni, dns_name;
uint8_t *padding;
if (!CBB_init(&client_esni, 0) ||
!CBB_add_bytes(&client_esni, hs->esni_nonce, sizeof(hs->esni_nonce)) ||
!CBB_add_u16_length_prefixed(&client_esni, &dns_name) ||
!CBB_add_bytes(&dns_name, (const uint8_t *)ssl->hostname.get(),
strlen(ssl->hostname.get())) ||
!CBB_add_space(&dns_name, &padding, padding_len) ||
!CBB_flush(&client_esni)) {
return false;
}
OPENSSL_memset(padding, padding_len, 0);
size_t esni_max_len =
CBB_len(&client_esni) + EVP_AEAD_max_overhead(hs->esni_aead_ctx->aead);
Array<uint8_t> inner_esni;
size_t inner_esni_len = 0;
if (!inner_esni.Init(esni_max_len) ||
!EVP_AEAD_CTX_seal(hs->esni_aead_ctx.get(), inner_esni.data(),
&inner_esni_len, esni_max_len, hs->esni_iv,
hs->esni_iv_len, CBB_data(&client_esni),
CBB_len(&client_esni), hs->key_share_bytes.data(),
hs->key_share_bytes.size())) {
return false;
}
if (!CBB_add_bytes(&esni, inner_esni.data(), inner_esni_len) ||
!CBB_flush(&esni)) {
return false;
}
return CBB_flush(out);
}
static bool ext_encrypted_server_name_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert,
CBS *contents) {
if (contents == NULL) {
return true;
}
assert(!SSL_is_dtls(hs->ssl));
assert(hs->config->enable_esni);
uint8_t response_type;
if (!CBS_get_u8(contents, &response_type)) {
return false;
}
if (response_type == 0) {
if (CBS_len(contents) != 16 ||
!CBS_mem_equal(contents, hs->esni_nonce, 16)) {
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return false;
}
hs->esni_state = ssl_esni_verified;
} else if (response_type == 1) {
// TODO(svaldez): Handle this.
// esni_retry_request
//ESNIKeys retry_keys<1..2^16-1>;
hs->esni_state = ssl_esni_retry_required;
return false;
} else {
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return false;
}
return true;
}
bool ssl_ext_encrypted_server_name_parse_clienthello(SSL_HANDSHAKE *hs,
uint8_t *out_alert,
CBS *contents) {
SSL *const ssl = hs->ssl;
if (contents == NULL) {
return true;
}
CBS kse_bytes, key_exchange, record_digest, esni;
uint16_t cipher_id;
if (!CBS_get_u16(contents, &cipher_id) ||
!CBS_get_u16_length_prefixed(contents, &kse_bytes) ||
!CBS_get_u16(&kse_bytes, &hs->config->esni_group) ||
!CBS_get_u16_length_prefixed(&kse_bytes, &key_exchange) ||
!CBS_get_u16_length_prefixed(contents, &record_digest) ||
!CBS_get_u16_length_prefixed(contents, &esni) ||
CBS_len(contents) != 0) {
return false;
}
hs->config->esni_cipher = SSL_get_cipher_by_value(cipher_id);
if (!hs->config->esni_record_digest.CopyFrom(
MakeSpan(CBS_data(&record_digest), CBS_len(&record_digest)))) {
return false;
}
CBS server_keyshare;
CBS_init(&server_keyshare, ssl->config->esni_private.data(),
ssl->config->esni_private.size());
UniquePtr<SSLKeyShare> esni_server_share =
SSLKeyShare::Create(&server_keyshare);
Array<uint8_t> shared_secret;
uint8_t alert;
if (!esni_server_share->Finish(&shared_secret, &alert, key_exchange)) {
return false;
}
if (!tls13_derive_esni_secrets(hs, std::move(shared_secret))) {
return false;
}
Array<uint8_t> inner_esni;
size_t inner_esni_len;
size_t esni_max_len = CBS_len(&esni);
if (!inner_esni.Init(esni_max_len) ||
!EVP_AEAD_CTX_open(hs->esni_aead_ctx.get(), inner_esni.data(),
&inner_esni_len, esni_max_len, hs->esni_iv,
hs->esni_iv_len, CBS_data(&esni), CBS_len(&esni),
hs->key_share_bytes.data(),
hs->key_share_bytes.size())) {
return false;
}
inner_esni.Shrink(inner_esni_len);
CBS real_esni, dns_name;
CBS_init(&real_esni, inner_esni.data(), inner_esni.size());
uint8_t nonce[16];
if (!CBS_copy_bytes(&real_esni, nonce, sizeof(nonce)) ||
!CBS_get_u16_length_prefixed(&real_esni, &dns_name)) {
return false;
}
// Copy the hostname as a string.
char *raw = nullptr;
if (!CBS_strdup(&dns_name, &raw)) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return false;
}
ssl->s3->hostname.reset(raw);
return true;
}
static bool ext_encrypted_server_name_add_serverhello(SSL_HANDSHAKE *hs,
CBB *out) {
return true;
}
// kExtensions contains all the supported extensions.
static const struct tls_extension kExtensions[] = {
{
@@ -3143,6 +3351,14 @@ static const struct tls_extension kExtensions[] = {
ext_pq_experiment_signal_parse_clienthello,
ext_pq_experiment_signal_add_serverhello,
},
{
TLSEXT_TYPE_encrypted_server_name,
NULL,
ext_encrypted_server_name_add_clienthello,
ext_encrypted_server_name_parse_serverhello,
ignore_parse_clienthello,
ext_encrypted_server_name_add_serverhello,
},
};
#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension))
+60
View File
@@ -565,4 +565,64 @@ bool tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
return true;
}
//TODO(svaldez): Support HRR case.
bool tls13_derive_esni_secrets(SSL_HANDSHAKE *hs, Array<uint8_t> shared_secret) {
SSL const *ssl = hs->ssl;
const EVP_MD *digest =
ssl_get_handshake_digest(TLS1_3_VERSION, hs->config->esni_cipher);
uint8_t zeroes[EVP_MAX_MD_SIZE] = {0};
uint8_t zx[EVP_MAX_MD_SIZE] = {0};
size_t zx_len;
if (!HKDF_extract(zx, &zx_len, digest, shared_secret.data(),
shared_secret.size(), zeroes, EVP_MD_size(digest))) {
return false;
}
CBB esni_cbb, record_digest, keyshare;
Array<uint8_t> esni_contents;
if (!CBB_init(&esni_cbb, 0) ||
!CBB_add_u16_length_prefixed(&esni_cbb, &record_digest) ||
!CBB_add_bytes(&record_digest, ssl->config->esni_record_digest.data(),
ssl->config->esni_record_digest.size()) ||
!CBB_add_u16(&esni_cbb, ssl->config->esni_group) ||
!CBB_add_u16_length_prefixed(&esni_cbb, &keyshare) ||
!CBB_add_bytes(&keyshare, ssl->config->esni_server_keyshare.data(),
ssl->config->esni_server_keyshare.size()) ||
!CBB_add_bytes(&esni_cbb, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
!CBBFinishArray(&esni_cbb, &esni_contents)) {
return false;
}
uint8_t esni_hash[EVP_MAX_MD_SIZE];
unsigned esni_hash_len;
if (!EVP_Digest(esni_contents.data(), esni_contents.size(), esni_hash,
&esni_hash_len, digest, nullptr)) {
return false;
}
const EVP_AEAD *aead;
size_t discard;
if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, ssl->config->esni_cipher,
TLS1_3_VERSION, false)) {
return false;
}
// Derive the key and iv.
size_t key_len = EVP_AEAD_key_length(aead);
uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
hs->esni_iv_len = EVP_AEAD_nonce_length(aead);
if (!hkdf_expand_label(key, digest, zx, zx_len, "esni key", 8, esni_hash,
esni_hash_len, key_len) ||
!hkdf_expand_label(hs->esni_iv, digest, zx, zx_len, "esni iv", 7,
esni_hash, esni_hash_len, hs->esni_iv_len)) {
return false;
}
return EVP_AEAD_CTX_init(hs->esni_aead_ctx.get(), aead, key, key_len,
hs->esni_iv_len, nullptr);
}
BSSL_NAMESPACE_END