Move key_share computation out of ClientHello callbacks. Like the early_data CL, this does shift a bit of logic that was previously hidden away in the callbacks. For key_share, this is probably a good move independent of ECH. The logic around HRR, etc., was a little messy. Bug: 275 Change-Id: Iafbcebdf66ce1f7957d798a98ee6b996fff24639 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47986 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index aa015d4..7607d56 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc
@@ -497,7 +497,8 @@ hs->early_data_offered = true; } - if (!ssl_write_client_hello(hs)) { + if (!ssl_setup_key_shares(hs, /*override_group_id=*/0) || + !ssl_write_client_hello(hs)) { return ssl_hs_error; }
diff --git a/ssl/internal.h b/ssl/internal.h index d6801df..1893aa5 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -1742,10 +1742,6 @@ uint32_t received; } extensions; - // retry_group is the group ID selected by the server in HelloRetryRequest in - // TLS 1.3. - uint16_t retry_group = 0; - // error, if |wait| is |ssl_hs_error|, is the error the handshake failed on. UniquePtr<ERR_SAVE_STATE> error; @@ -1768,8 +1764,7 @@ // reconstructed ClientHelloInner message. Array<uint8_t> ech_client_hello_buf; - // key_share_bytes is the value of the previously sent KeyShare extension by - // the client in TLS 1.3. + // key_share_bytes is the key_share extension that the client should send. Array<uint8_t> key_share_bytes; // ecdh_public_key, for servers, is the key share to be sent to the client in @@ -2040,6 +2035,12 @@ bssl::UniquePtr<SSL_SESSION> tls13_create_session_with_ticket(SSL *ssl, CBS *body); +// ssl_setup_key_shares computes client key shares and saves them in |hs|. It +// returns true on success and false on failure. If |override_group_id| is zero, +// it offers the default groups, including GREASE. If it is non-zero, it offers +// a single key share of the specified group. +bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id); + bool ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, Array<uint8_t> *out_secret, uint8_t *out_alert, CBS *contents);
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc index da3400f..f48ed84 100644 --- a/ssl/t1_lib.cc +++ b/ssl/t1_lib.cc
@@ -405,6 +405,11 @@ return false; } + // We internally assume zero is never allocated as a group ID. + if (group_id == 0) { + return false; + } + for (uint16_t supported : tls1_get_grouplist(hs)) { if (supported == group_id) { return true; @@ -2242,42 +2247,33 @@ // // https://tools.ietf.org/html/rfc8446#section-4.2.8 -static bool ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { +bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id) { SSL *const ssl = hs->ssl; + hs->key_shares[0].reset(); + hs->key_shares[1].reset(); + hs->key_share_bytes.Reset(); + if (hs->max_version < TLS1_3_VERSION) { return true; } - CBB contents, kse_bytes; - if (!CBB_add_u16(out, TLSEXT_TYPE_key_share) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &kse_bytes)) { + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 64)) { return false; } - uint16_t group_id = hs->retry_group; - uint16_t second_group_id = 0; - if (ssl->s3 && ssl->s3->used_hello_retry_request) { - // We received a HelloRetryRequest without a new curve, so there is no new - // share to append. Leave |hs->key_share| as-is. - if (group_id == 0 && - !CBB_add_bytes(&kse_bytes, hs->key_share_bytes.data(), - hs->key_share_bytes.size())) { - return false; - } - if (group_id == 0) { - return CBB_flush(out); - } - } else { + if (override_group_id == 0 && ssl->ctx->grease_enabled) { // Add a fake group. See RFC 8701. - if (ssl->ctx->grease_enabled && - (!CBB_add_u16(&kse_bytes, - ssl_get_grease_value(hs, ssl_grease_group)) || - !CBB_add_u16(&kse_bytes, 1 /* length */) || - !CBB_add_u8(&kse_bytes, 0 /* one byte key share */))) { + if (!CBB_add_u16(cbb.get(), ssl_get_grease_value(hs, ssl_grease_group)) || + !CBB_add_u16(cbb.get(), 1 /* length */) || + !CBB_add_u8(cbb.get(), 0 /* one byte key share */)) { return false; } + } + uint16_t group_id = override_group_id; + uint16_t second_group_id = 0; + if (override_group_id == 0) { // Predict the most preferred group. Span<const uint16_t> groups = tls1_get_grouplist(hs); if (groups.empty()) { @@ -2297,34 +2293,43 @@ CBB key_exchange; hs->key_shares[0] = SSLKeyShare::Create(group_id); - if (!hs->key_shares[0] || - !CBB_add_u16(&kse_bytes, group_id) || - !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || - !hs->key_shares[0]->Offer(&key_exchange) || - !CBB_flush(&kse_bytes)) { + if (!hs->key_shares[0] || // + !CBB_add_u16(cbb.get(), group_id) || + !CBB_add_u16_length_prefixed(cbb.get(), &key_exchange) || + !hs->key_shares[0]->Offer(&key_exchange)) { return false; } if (second_group_id != 0) { hs->key_shares[1] = SSLKeyShare::Create(second_group_id); - if (!hs->key_shares[1] || - !CBB_add_u16(&kse_bytes, second_group_id) || - !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || - !hs->key_shares[1]->Offer(&key_exchange) || - !CBB_flush(&kse_bytes)) { + if (!hs->key_shares[1] || // + !CBB_add_u16(cbb.get(), second_group_id) || + !CBB_add_u16_length_prefixed(cbb.get(), &key_exchange) || + !hs->key_shares[1]->Offer(&key_exchange)) { return false; } } - // Save the contents of the extension to repeat it in the second - // ClientHello. - if (ssl->s3 && !ssl->s3->used_hello_retry_request && - !hs->key_share_bytes.CopyFrom( - MakeConstSpan(CBB_data(&kse_bytes), CBB_len(&kse_bytes)))) { + return CBBFinishArray(cbb.get(), &hs->key_share_bytes); +} + +static bool ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + if (hs->max_version < TLS1_3_VERSION) { + return true; + } + + assert(!hs->key_share_bytes.empty()); + CBB contents, kse_bytes; + if (!CBB_add_u16(out, TLSEXT_TYPE_key_share) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u16_length_prefixed(&contents, &kse_bytes) || + !CBB_add_bytes(&kse_bytes, hs->key_share_bytes.data(), + hs->key_share_bytes.size()) || + !CBB_flush(out)) { return false; } - return CBB_flush(out); + return true; } bool ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs,
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc index c7f45f6..92ccf62 100644 --- a/ssl/tls13_client.cc +++ b/ssl/tls13_client.cc
@@ -222,9 +222,9 @@ return ssl_hs_error; } - hs->key_shares[0].reset(); - hs->key_shares[1].reset(); - hs->retry_group = group_id; + if (!ssl_setup_key_shares(hs, group_id)) { + return ssl_hs_error; + } } if (!ssl_hash_message(hs, msg)) {