Skip to content

Commit 6a8ebd5

Browse files
n13lfwh-dc
andcommitted
TLS: Generate the server random before processing ClientHello extensions
The server random was only generated after all of the ClientHello extensions had been processed. In (D)TLSv1.3 the PSK callbacks are invoked while the pre_shared_key extension is being parsed, so a call to SSL_get_server_random() from within them returned all zeros. The TLSv1.2 psk_server_callback runs during ClientKeyExchange processing and so already observed the real value, making the behaviour inconsistent between protocol versions. Move the generation of the server random to immediately after the protocol version has been selected and before any of the remaining ClientHello processing. As a result the server random is also visible from the other callbacks invoked during ClientHello processing, such as the session ticket and servername callbacks. Fixes openssl#26404 Assisted-by: Claude:claude-fable-5-1 Co-authored-by: Frederik Wedel-Heinen <frederik.wedel-heinen@dencrypt.dk>
1 parent 0673930 commit 6a8ebd5

4 files changed

Lines changed: 320 additions & 16 deletions

File tree

‎doc/man3/SSL_get_client_random.pod‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,19 @@ Finally, though the "client_random" and "server_random" values are called
7474
"random", many TLS implementations will generate four bytes of those
7575
values based on their view of the current time.
7676

77+
On the server side the server_random value is generated as soon as the
78+
protocol version has been selected during ClientHello processing. It is
79+
therefore already available to callbacks invoked later during that
80+
processing, such as the servername callback, the session ticket callbacks
81+
and the PSK callbacks (see L<SSL_CTX_set_psk_find_session_callback(3)> and
82+
L<SSL_CTX_set_psk_server_callback(3)>), including in (D)TLSv1.3. Note that if a
83+
HelloRetryRequest is sent a fresh server_random is generated when the second
84+
ClientHello is processed. When Encrypted ClientHello (ECH) is accepted, the
85+
final eight bytes of the server_random are replaced with the ECH acceptance
86+
confirmation while the ServerHello is being constructed, so a value observed
87+
from a callback before that point will differ in those bytes from the value
88+
sent to the client. On the client side the value is available once the
89+
ServerHello has been received.
7790

7891
=head1 RETURN VALUES
7992

‎ssl/statem/statem_srvr.c‎

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2085,6 +2085,7 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
20852085
SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
20862086
SSL *ssl = SSL_CONNECTION_GET_SSL(s);
20872087
SSL *ussl = SSL_CONNECTION_GET_USER_SSL(s);
2088+
unsigned char *snonce = s->s3.server_random;
20882089

20892090
/* Finished parsing the ClientHello, now we can start processing it */
20902091
/* Give the ClientHello callback a crack at things */
@@ -2161,6 +2162,21 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
21612162
}
21622163
}
21632164

2165+
/*
2166+
* Generate the server_random now that the protocol version (and hence any
2167+
* downgrade sentinel) is known, but before any of the remaining ClientHello
2168+
* processing. This ensures that callbacks invoked from here on such as
2169+
* the session ticket callbacks, the servername callback, the (D)TLSv1.3
2170+
* PSK callbacks and tls_session_secret_cb can observe the value via
2171+
* SSL_get_server_random(). Note that in the TLSv1.2 flow
2172+
* tls_session_secret_cb in particular needs it for SessionTicket key
2173+
* derivation.
2174+
*/
2175+
if (ssl_fill_hello_random(s, 1, snonce, SSL3_RANDOM_SIZE, dgrd) <= 0) {
2176+
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
2177+
goto err;
2178+
}
2179+
21642180
s->hit = 0;
21652181

21662182
if (!ssl_cache_cipherlist(s, &clienthello->ciphersuites)
@@ -2330,21 +2346,6 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
23302346
goto err;
23312347
}
23322348

2333-
/*
2334-
* Check if we want to use external pre-shared secret for this handshake
2335-
* for not reused session only. We need to generate server_random before
2336-
* calling tls_session_secret_cb in order to allow SessionTicket
2337-
* processing to use it in key derivation.
2338-
*/
2339-
{
2340-
unsigned char *pos;
2341-
pos = s->s3.server_random;
2342-
if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE, dgrd) <= 0) {
2343-
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
2344-
goto err;
2345-
}
2346-
}
2347-
23482349
if (!s->hit && !tls1_set_server_sigalgs(s)) {
23492350
/* SSLfatal() already called */
23502351
goto err;
@@ -2809,7 +2810,7 @@ CON_FUNC_RETURN tls_construct_server_hello(SSL_CONNECTION *s, WPACKET *pkt)
28092810
if (!WPACKET_put_bytes_u16(pkt, version)
28102811
/*
28112812
* Random stuff. Filling of the server_random takes place in
2812-
* tls_process_client_hello()
2813+
* tls_early_post_process_client_hello()
28132814
*/
28142815
|| !WPACKET_memcpy(pkt,
28152816
s->hello_retry_request == SSL_HRR_PENDING

‎test/quicapitest.c‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,11 +1336,24 @@ static int use_session_cb(SSL *ssl, const EVP_MD *md, const unsigned char **id,
13361336
return 1;
13371337
}
13381338

1339+
/*
1340+
* The server random as observed from within find_session_cb(). Prior to the
1341+
* fix for issue #26404 the server random was generated only after the
1342+
* ClientHello extensions had been processed, so a PSK callback observed an
1343+
* all-zero value.
1344+
*/
1345+
static unsigned char cb_server_random[SSL3_RANDOM_SIZE];
1346+
static size_t cb_server_random_len;
1347+
13391348
static int find_session_cb(SSL *ssl, const unsigned char *identity,
13401349
size_t identity_len, SSL_SESSION **sess)
13411350
{
13421351
find_session_cb_cnt++;
13431352

1353+
memset(cb_server_random, 0, sizeof(cb_server_random));
1354+
cb_server_random_len = SSL_get_server_random(ssl, cb_server_random,
1355+
sizeof(cb_server_random));
1356+
13441357
if (serverpsk == NULL || !SSL_SESSION_up_ref(serverpsk))
13451358
return 0;
13461359

@@ -1361,6 +1374,10 @@ static int test_quic_psk(void)
13611374
SSL_CTX *cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method());
13621375
SSL *clientquic = NULL;
13631376
QUIC_TSERVER *qtserv = NULL;
1377+
SSL *stream = NULL;
1378+
unsigned char zeros[SSL3_RANDOM_SIZE] = { 0 };
1379+
unsigned char server_random[SSL3_RANDOM_SIZE];
1380+
unsigned char client_random[SSL3_RANDOM_SIZE];
13641381
int testresult = 0;
13651382

13661383
if (!TEST_ptr(cctx)
@@ -1387,9 +1404,39 @@ static int test_quic_psk(void)
13871404
|| !TEST_true(SSL_session_reused(clientquic)))
13881405
goto end;
13891406

1407+
/*
1408+
* The server PSK callback must have observed the server random actually
1409+
* used in the handshake. The client side SSL object is a QUIC connection
1410+
* object, on which SSL_get_server_random() and SSL_get_client_random()
1411+
* report the values from the underlying TLS handshake.
1412+
*/
1413+
if (!TEST_size_t_eq(cb_server_random_len, SSL3_RANDOM_SIZE)
1414+
|| !TEST_mem_ne(cb_server_random, sizeof(cb_server_random),
1415+
zeros, sizeof(zeros))
1416+
|| !TEST_size_t_eq(SSL_get_server_random(clientquic, server_random,
1417+
sizeof(server_random)),
1418+
SSL3_RANDOM_SIZE)
1419+
|| !TEST_mem_eq(cb_server_random, sizeof(cb_server_random),
1420+
server_random, sizeof(server_random))
1421+
|| !TEST_size_t_eq(SSL_get_client_random(clientquic, client_random,
1422+
sizeof(client_random)),
1423+
SSL3_RANDOM_SIZE))
1424+
goto end;
1425+
1426+
/* On a QUIC stream object the getters are not applicable and return 0 */
1427+
if (!TEST_ptr(stream = SSL_new_stream(clientquic, 0))
1428+
|| !TEST_size_t_eq(SSL_get_server_random(stream, server_random,
1429+
sizeof(server_random)),
1430+
0)
1431+
|| !TEST_size_t_eq(SSL_get_client_random(stream, client_random,
1432+
sizeof(client_random)),
1433+
0))
1434+
goto end;
1435+
13901436
testresult = 1;
13911437

13921438
end:
1439+
SSL_free(stream);
13931440
SSL_free(clientquic);
13941441
ossl_quic_tserver_free(qtserv);
13951442
SSL_CTX_free(cctx);

0 commit comments

Comments
 (0)