diff --git a/ssl/handshake.cc b/ssl/handshake.cc index 3b446a8cb..cdd1b327c 100644 --- a/ssl/handshake.cc +++ b/ssl/handshake.cc @@ -116,6 +116,8 @@ #include +#include + #include "../crypto/internal.h" #include "internal.h" @@ -143,7 +145,8 @@ SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg) next_proto_neg_seen(false), ticket_expected(false), extended_master_secret(false), - pending_private_key_op(false) { + pending_private_key_op(false), + grease_seeded(false) { } SSL_HANDSHAKE::~SSL_HANDSHAKE() { @@ -351,18 +354,19 @@ enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) { return ret; } -uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) { - // Use the client_random or server_random for entropy. This both avoids - // calling |RAND_bytes| on a single byte repeatedly and ensures the values are - // deterministic. This allows the same ClientHello be sent twice for a - // HelloRetryRequest or the same group be advertised in both supported_groups - // and key_shares. - uint16_t ret = ssl->server ? ssl->s3->server_random[index] - : ssl->s3->client_random[index]; - // The first four bytes of server_random are a timestamp prior to TLS 1.3, but - // servers have no fields to GREASE until TLS 1.3. - assert(!ssl->server || ssl_protocol_version(ssl) >= TLS1_3_VERSION); +uint16_t ssl_get_grease_value(SSL_HANDSHAKE *hs, + enum ssl_grease_index_t index) { + // Draw entropy for all GREASE values at once. This avoids calling + // |RAND_bytes| repeatedly and makes the values consistent within a + // connection. The latter is so the second ClientHello matches after + // HelloRetryRequest and so supported_groups and key_shares are consistent. + if (!hs->grease_seeded) { + RAND_bytes(hs->grease_seed, sizeof(hs->grease_seed)); + hs->grease_seeded = true; + } + // This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. + uint16_t ret = hs->grease_seed[index]; ret = (ret & 0xf0) | 0x0a; ret |= ret << 8; return ret; diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index 4e2158e12..3961ca16d 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc @@ -223,7 +223,7 @@ static int ssl_write_client_cipher_list(SSL_HANDSHAKE *hs, CBB *out) { // Add a fake cipher suite. See draft-davidben-tls-grease-01. if (ssl->ctx->grease_enabled && - !CBB_add_u16(&child, ssl_get_grease_value(ssl, ssl_grease_cipher))) { + !CBB_add_u16(&child, ssl_get_grease_value(hs, ssl_grease_cipher))) { return 0; } diff --git a/ssl/internal.h b/ssl/internal.h index fb9910161..d4f0e3fce 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -1281,6 +1281,16 @@ enum ssl_hs_wait_t { ssl_hs_certificate_verify, }; +enum ssl_grease_index_t { + ssl_grease_cipher = 0, + ssl_grease_group, + ssl_grease_extension1, + ssl_grease_extension2, + ssl_grease_version, + ssl_grease_ticket_extension, + ssl_grease_last_index = ssl_grease_ticket_extension, +}; + struct SSL_HANDSHAKE { explicit SSL_HANDSHAKE(SSL *ssl); ~SSL_HANDSHAKE(); @@ -1493,6 +1503,9 @@ struct SSL_HANDSHAKE { // in progress. bool pending_private_key_op:1; + // grease_seeded is true if |grease_seed| has been initialized. + bool grease_seeded:1; + // client_version is the value sent or received in the ClientHello version. uint16_t client_version = 0; @@ -1508,6 +1521,10 @@ struct SSL_HANDSHAKE { // TLS 1.3 variant. uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH] = {0}; uint8_t session_id_len = 0; + + // grease_seed is the entropy for GREASE values. It is valid if + // |grease_seeded| is true. + uint8_t grease_seed[ssl_grease_last_index + 1] = {0}; }; UniquePtr ssl_handshake_new(SSL *ssl); @@ -1650,20 +1667,11 @@ int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello, // GREASE. -enum ssl_grease_index_t { - ssl_grease_cipher = 0, - ssl_grease_group, - ssl_grease_extension1, - ssl_grease_extension2, - ssl_grease_version, - ssl_grease_ticket_extension, -}; - -// ssl_get_grease_value returns a GREASE value for |ssl|. For a given +// ssl_get_grease_value returns a GREASE value for |hs|. For a given // connection, the values for each index will be deterministic. This allows the // same ClientHello be sent twice for a HelloRetryRequest or the same group be // advertised in both supported_groups and key_shares. -uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index); +uint16_t ssl_get_grease_value(SSL_HANDSHAKE *hs, enum ssl_grease_index_t index); // Signature algorithms. diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc index dafb885d2..de0247684 100644 --- a/ssl/t1_lib.cc +++ b/ssl/t1_lib.cc @@ -2115,7 +2115,7 @@ static bool ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { // Add a fake group. See draft-davidben-tls-grease-01. if (ssl->ctx->grease_enabled && (!CBB_add_u16(&kse_bytes, - ssl_get_grease_value(ssl, ssl_grease_group)) || + 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 */))) { return false; @@ -2287,7 +2287,7 @@ static bool ext_supported_versions_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) // Add a fake version. See draft-davidben-tls-grease-01. if (ssl->ctx->grease_enabled && - !CBB_add_u16(&versions, ssl_get_grease_value(ssl, ssl_grease_version))) { + !CBB_add_u16(&versions, ssl_get_grease_value(hs, ssl_grease_version))) { return false; } @@ -2377,7 +2377,7 @@ static bool ext_supported_groups_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { // Add a fake group. See draft-davidben-tls-grease-01. if (ssl->ctx->grease_enabled && !CBB_add_u16(&groups_bytes, - ssl_get_grease_value(ssl, ssl_grease_group))) { + ssl_get_grease_value(hs, ssl_grease_group))) { return false; } @@ -2813,7 +2813,7 @@ int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len) { uint16_t grease_ext1 = 0; if (ssl->ctx->grease_enabled) { // Add a fake empty extension. See draft-davidben-tls-grease-01. - grease_ext1 = ssl_get_grease_value(ssl, ssl_grease_extension1); + grease_ext1 = ssl_get_grease_value(hs, ssl_grease_extension1); if (!CBB_add_u16(&extensions, grease_ext1) || !CBB_add_u16(&extensions, 0 /* zero length */)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); @@ -2841,7 +2841,7 @@ int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len) { if (ssl->ctx->grease_enabled) { // Add a fake non-empty extension. See draft-davidben-tls-grease-01. - uint16_t grease_ext2 = ssl_get_grease_value(ssl, ssl_grease_extension2); + uint16_t grease_ext2 = ssl_get_grease_value(hs, ssl_grease_extension2); // The two fake extensions must not have the same value. GREASE values are // of the form 0x1a1a, 0x2a2a, 0x3a3a, etc., so XOR to generate a different diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc index 331e0d576..a6a3a0a50 100644 --- a/ssl/tls13_server.cc +++ b/ssl/tls13_server.cc @@ -211,7 +211,7 @@ static int add_new_session_tickets(SSL_HANDSHAKE *hs) { // Add a fake extension. See draft-davidben-tls-grease-01. if (!CBB_add_u16(&extensions, - ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || + ssl_get_grease_value(hs, ssl_grease_ticket_extension)) || !CBB_add_u16(&extensions, 0 /* empty */)) { return 0; }