Skip to content

Commit 0defef0

Browse files
committed
DTLS 1.3: don't echo legacy_session_id in ServerHello
1 parent 8169780 commit 0defef0

3 files changed

Lines changed: 147 additions & 17 deletions

File tree

src/tls13.c

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5581,6 +5581,18 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
55815581

55825582
case TLS_ASYNC_FINALIZE:
55835583
{
5584+
#ifdef WOLFSSL_DTLS13
5585+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
5586+
* legacy_session_id_echo. */
5587+
if (ssl->options.dtls) {
5588+
if (args->sessIdSz != 0) {
5589+
WOLFSSL_MSG("DTLS 1.3 ServerHello must have empty session ID");
5590+
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
5591+
return INVALID_PARAMETER;
5592+
}
5593+
}
5594+
else
5595+
#endif
55845596
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
55855597
if (ssl->options.tls13MiddleBoxCompat) {
55865598
if (args->sessIdSz == 0) {
@@ -6607,8 +6619,11 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
66076619
return ret;
66086620

66096621
/* Reconstruct the HelloRetryMessage for handshake hash. */
6610-
length = HRR_BODY_SZ - ID_LEN + ssl->session->sessionIDSz +
6611-
HRR_COOKIE_HDR_SZ + cookie->len;
6622+
length = HRR_BODY_SZ - ID_LEN + HRR_COOKIE_HDR_SZ + cookie->len;
6623+
#ifdef WOLFSSL_DTLS13
6624+
if (!ssl->options.dtls)
6625+
#endif
6626+
length += ssl->session->sessionIDSz;
66126627
length += HRR_VERSIONS_SZ;
66136628
/* HashSz (1 byte) + Hash (HashSz bytes) + CipherSuite (2 bytes) */
66146629
if (cookieDataSz > OPAQUE8_LEN + hashSz + OPAQUE16_LEN) {
@@ -6634,10 +6649,17 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
66346649
XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN);
66356650
hrrIdx += RAN_LEN;
66366651

6637-
hrr[hrrIdx++] = ssl->session->sessionIDSz;
6638-
if (ssl->session->sessionIDSz > 0) {
6639-
XMEMCPY(hrr + hrrIdx, ssl->session->sessionID, ssl->session->sessionIDSz);
6640-
hrrIdx += ssl->session->sessionIDSz;
6652+
#ifdef WOLFSSL_DTLS13
6653+
if (ssl->options.dtls)
6654+
hrr[hrrIdx++] = 0;
6655+
else
6656+
#endif
6657+
{
6658+
hrr[hrrIdx++] = ssl->session->sessionIDSz;
6659+
if (ssl->session->sessionIDSz > 0) {
6660+
XMEMCPY(hrr + hrrIdx, ssl->session->sessionID, ssl->session->sessionIDSz);
6661+
hrrIdx += ssl->session->sessionIDSz;
6662+
}
66416663
}
66426664

66436665
/* Cipher Suite */
@@ -6648,7 +6670,11 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
66486670
hrr[hrrIdx++] = 0;
66496671

66506672
/* Extensions' length */
6651-
length -= HRR_BODY_SZ - ID_LEN + ssl->session->sessionIDSz;
6673+
length -= HRR_BODY_SZ - ID_LEN;
6674+
#ifdef WOLFSSL_DTLS13
6675+
if (!ssl->options.dtls)
6676+
#endif
6677+
length -= ssl->session->sessionIDSz;
66526678
c16toa(length, hrr + hrrIdx);
66536679
hrrIdx += 2;
66546680

@@ -7073,9 +7099,17 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
70737099
if (sessIdSz + args->idx > helloSz)
70747100
ERROR_OUT(BUFFER_ERROR, exit_dch);
70757101

7076-
ssl->session->sessionIDSz = sessIdSz;
7077-
if (sessIdSz > 0)
7078-
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
7102+
#ifdef WOLFSSL_DTLS13
7103+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
7104+
* legacy_session_id_echo. Don't store the client's value so it
7105+
* won't be echoed in SendTls13ServerHello. */
7106+
if (!ssl->options.dtls)
7107+
#endif
7108+
{
7109+
ssl->session->sessionIDSz = sessIdSz;
7110+
if (sessIdSz > 0)
7111+
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
7112+
}
70797113
args->idx += sessIdSz;
70807114

70817115
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
@@ -7579,8 +7613,13 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
75797613
/* Protocol version, server random, session id, cipher suite, compression
75807614
* and extensions.
75817615
*/
7582-
length = VERSION_SZ + RAN_LEN + ENUM_LEN + ssl->session->sessionIDSz +
7583-
SUITE_LEN + COMP_LEN;
7616+
length = VERSION_SZ + RAN_LEN + ENUM_LEN + SUITE_LEN + COMP_LEN;
7617+
#ifdef WOLFSSL_DTLS13
7618+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
7619+
* legacy_session_id_echo. */
7620+
if (!ssl->options.dtls)
7621+
#endif
7622+
length += ssl->session->sessionIDSz;
75847623
ret = TLSX_GetResponseSize(ssl, extMsgType, &length);
75857624
if (ret != 0)
75867625
return ret;
@@ -7624,10 +7663,21 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
76247663
WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN);
76257664
#endif
76267665

7627-
output[idx++] = ssl->session->sessionIDSz;
7628-
if (ssl->session->sessionIDSz > 0) {
7629-
XMEMCPY(output + idx, ssl->session->sessionID, ssl->session->sessionIDSz);
7630-
idx += ssl->session->sessionIDSz;
7666+
#ifdef WOLFSSL_DTLS13
7667+
if (ssl->options.dtls) {
7668+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
7669+
* legacy_session_id_echo. */
7670+
output[idx++] = 0;
7671+
}
7672+
else
7673+
#endif
7674+
{
7675+
output[idx++] = ssl->session->sessionIDSz;
7676+
if (ssl->session->sessionIDSz > 0) {
7677+
XMEMCPY(output + idx, ssl->session->sessionID,
7678+
ssl->session->sessionIDSz);
7679+
idx += ssl->session->sessionIDSz;
7680+
}
76317681
}
76327682

76337683
/* Chosen cipher suite */

tests/api/test_dtls.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,3 +2567,81 @@ int test_dtls13_min_rtx_interval(void)
25672567
#endif
25682568
return EXPECT_RESULT();
25692569
}
2570+
2571+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
2572+
* legacy_session_id_echo, even if the ClientHello had a non-empty
2573+
* legacy_session_id. */
2574+
int test_dtls13_no_session_id_echo(void)
2575+
{
2576+
EXPECT_DECLS;
2577+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
2578+
struct test_memio_ctx test_ctx;
2579+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
2580+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
2581+
WOLFSSL_SESSION *sess = NULL;
2582+
char readBuf[1];
2583+
2584+
/* First connection: complete a DTLS 1.3 handshake to get a session */
2585+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2586+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
2587+
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
2588+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
2589+
2590+
/* Read to process any NewSessionTicket */
2591+
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
2592+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
2593+
2594+
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
2595+
2596+
/* Ensure the session has a non-empty session ID so the ClientHello
2597+
* will have a populated legacy_session_id field (which is legal per
2598+
* RFC 9147). */
2599+
if (sess->sessionIDSz == 0) {
2600+
sess->sessionIDSz = ID_LEN;
2601+
XMEMSET(sess->sessionID, 0x42, ID_LEN);
2602+
}
2603+
2604+
wolfSSL_free(ssl_c); ssl_c = NULL;
2605+
wolfSSL_free(ssl_s); ssl_s = NULL;
2606+
wolfSSL_CTX_free(ctx_c); ctx_c = NULL;
2607+
wolfSSL_CTX_free(ctx_s); ctx_s = NULL;
2608+
2609+
/* Second connection: set the session on the client so the ClientHello
2610+
* contains a non-empty legacy_session_id. Verify the server does NOT
2611+
* echo it in the ServerHello. */
2612+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2613+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
2614+
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
2615+
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
2616+
/* Disable HRR cookie so the server directly sends a ServerHello */
2617+
ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS);
2618+
2619+
/* Client sends ClientHello (with non-empty legacy_session_id) */
2620+
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
2621+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
2622+
2623+
/* Server processes ClientHello and sends ServerHello + flight */
2624+
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
2625+
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
2626+
2627+
/* Verify the ServerHello on the wire.
2628+
* Layout: DTLS Record Header (13) + DTLS Handshake Header (12) +
2629+
* ProtocolVersion (2) + Random (32) = offset 59 for
2630+
* legacy_session_id_echo length byte. */
2631+
ExpectIntGE(test_ctx.c_len, 60);
2632+
ExpectIntEQ(test_ctx.c_buff[0], handshake);
2633+
ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello);
2634+
ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ +
2635+
DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], 0);
2636+
2637+
/* Complete the handshake */
2638+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
2639+
2640+
wolfSSL_SESSION_free(sess);
2641+
wolfSSL_free(ssl_c);
2642+
wolfSSL_free(ssl_s);
2643+
wolfSSL_CTX_free(ctx_c);
2644+
wolfSSL_CTX_free(ctx_s);
2645+
#endif
2646+
return EXPECT_RESULT();
2647+
}

tests/api/test_dtls.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ int test_dtls_memio_wolfio_stateless(void);
5050
int test_dtls_mtu_fragment_headroom(void);
5151
int test_dtls_mtu_split_messages(void);
5252
int test_dtls13_min_rtx_interval(void);
53+
int test_dtls13_no_session_id_echo(void);
5354

5455
#define TEST_DTLS_DECLS \
5556
TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \
@@ -79,5 +80,6 @@ int test_dtls13_min_rtx_interval(void);
7980
TEST_DECL_GROUP("dtls", test_dtls_mtu_fragment_headroom), \
8081
TEST_DECL_GROUP("dtls", test_dtls_mtu_split_messages), \
8182
TEST_DECL_GROUP("dtls", test_dtls_memio_wolfio_stateless), \
82-
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval)
83+
TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \
84+
TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo)
8385
#endif /* TESTS_API_DTLS_H */

0 commit comments

Comments
 (0)