Skip to content

Commit 27aac0a

Browse files
authored
Merge pull request #10007 from julek-wolfssl/zd/21376
DTLS 1.3: don't echo legacy_session_id in ServerHello
2 parents 68eaf67 + 9cbdf04 commit 27aac0a

10 files changed

Lines changed: 316 additions & 135 deletions

File tree

src/dtls.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -857,9 +857,9 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch)
857857
nonConstSSL->options.tls1_1 = 1;
858858
nonConstSSL->options.tls1_3 = 1;
859859

860-
XMEMCPY(nonConstSSL->session->sessionID, ch->sessionId.elements,
861-
ch->sessionId.size);
862-
nonConstSSL->session->sessionIDSz = (byte)ch->sessionId.size;
860+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
861+
* legacy_session_id_echo. Don't copy the client's session ID. */
862+
nonConstSSL->session->sessionIDSz = 0;
863863
nonConstSSL->options.cipherSuite0 = cs.cipherSuite0;
864864
nonConstSSL->options.cipherSuite = cs.cipherSuite;
865865
nonConstSSL->extensions = parsedExts;

src/ssl_sess.c

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,10 +1142,8 @@ static int CheckSessionMatch(const WOLFSSL* ssl, const WOLFSSL_SESSION* sess)
11421142
XMEMCMP(ssl->sessionCtx, sess->sessionCtx, sess->sessionCtxSz) != 0))
11431143
return 0;
11441144
#endif
1145-
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
11461145
if (IsAtLeastTLSv1_3(ssl->version) != IsAtLeastTLSv1_3(sess->version))
11471146
return 0;
1148-
#endif
11491147
return 1;
11501148
}
11511149

@@ -1553,12 +1551,11 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session)
15531551
ssl->options.resuming = 1;
15541552
ssl->options.haveEMS = (ssl->session->haveEMS) ? 1 : 0;
15551553

1556-
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
1557-
defined(HAVE_SESSION_TICKET))
1558-
ssl->version = ssl->session->version;
1559-
if (IsAtLeastTLSv1_3(ssl->version))
1560-
ssl->options.tls1_3 = 1;
1561-
#endif
1554+
if (ssl->session->version.major != 0) {
1555+
ssl->version = ssl->session->version;
1556+
if (IsAtLeastTLSv1_3(ssl->version))
1557+
ssl->options.tls1_3 = 1;
1558+
}
15621559
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
15631560
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
15641561
ssl->options.cipherSuite0 = ssl->session->cipherSuite0;
@@ -2601,11 +2598,8 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
26012598
for (i = 0; i < sess->chain.count; i++)
26022599
size += OPAQUE16_LEN + sess->chain.certs[i].length;
26032600
#endif
2604-
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
2605-
defined(HAVE_SESSION_TICKET))
26062601
/* Protocol version */
26072602
size += OPAQUE16_LEN;
2608-
#endif
26092603
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
26102604
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
26112605
/* cipher suite */
@@ -2681,11 +2675,8 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
26812675
idx += sess->chain.certs[i].length;
26822676
}
26832677
#endif
2684-
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
2685-
defined(HAVE_SESSION_TICKET))
26862678
data[idx++] = sess->version.major;
26872679
data[idx++] = sess->version.minor;
2688-
#endif
26892680
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
26902681
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
26912682
data[idx++] = sess->cipherSuite0;
@@ -2854,16 +2845,13 @@ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess,
28542845
idx += length;
28552846
}
28562847
#endif
2857-
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
2858-
defined(HAVE_SESSION_TICKET))
28592848
/* Protocol Version */
28602849
if (i - idx < OPAQUE16_LEN) {
28612850
ret = BUFFER_ERROR;
28622851
goto end;
28632852
}
28642853
s->version.major = data[idx++];
28652854
s->version.minor = data[idx++];
2866-
#endif
28672855
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
28682856
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
28692857
/* Cipher suite */
@@ -3176,10 +3164,8 @@ static void SESSION_ex_data_cache_update(WOLFSSL_SESSION* session, int idx,
31763164
if (cacheSession && cacheSession->sessionIDSz == ID_LEN &&
31773165
XMEMCMP(id, cacheSession->sessionID, ID_LEN) == 0
31783166
&& session->side == cacheSession->side
3179-
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
31803167
&& (IsAtLeastTLSv1_3(session->version) ==
31813168
IsAtLeastTLSv1_3(cacheSession->version))
3182-
#endif
31833169
) {
31843170
if (get) {
31853171
if (getRet) {
@@ -3604,10 +3590,7 @@ void SetupSession(WOLFSSL* ssl)
36043590
#ifndef NO_ASN_TIME
36053591
session->bornOn = LowResTimer();
36063592
#endif
3607-
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
3608-
defined(HAVE_SESSION_TICKET))
36093593
session->version = ssl->version;
3610-
#endif
36113594
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
36123595
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
36133596
session->cipherSuite0 = ssl->options.cipherSuite0;

src/tls.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12198,7 +12198,6 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, const byte* input,
1219812198
}
1219912199
list->chosen = 1;
1220012200

12201-
#ifdef HAVE_SESSION_TICKET
1220212201
if (list->resumption) {
1220312202
/* Check that the session's details are the same as the server's. */
1220412203
if (ssl->options.cipherSuite0 != ssl->session->cipherSuite0 ||
@@ -12209,7 +12208,6 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, const byte* input,
1220912208
return PSK_KEY_ERROR;
1221012209
}
1221112210
}
12212-
#endif
1221312211

1221412212
return 0;
1221512213
}

src/tls13.c

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4574,8 +4574,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
45744574
}
45754575
#endif /* WOLFSSL_DTLS */
45764576

4577-
#ifdef HAVE_SESSION_TICKET
45784577
if (ssl->options.resuming &&
4578+
ssl->session->version.major != 0 &&
45794579
(ssl->session->version.major != ssl->version.major ||
45804580
ssl->session->version.minor != ssl->version.minor)) {
45814581
#ifndef WOLFSSL_NO_TLS12
@@ -4594,7 +4594,6 @@ int SendTls13ClientHello(WOLFSSL* ssl)
45944594
return VERSION_ERROR;
45954595
}
45964596
}
4597-
#endif
45984597

45994598
suites = WOLFSSL_SUITES(ssl);
46004599
if (suites == NULL) {
@@ -4648,6 +4647,13 @@ int SendTls13ClientHello(WOLFSSL* ssl)
46484647
ssl->session->sessionIDSz = 0;
46494648
ssl->options.tls13MiddleBoxCompat = 0;
46504649
}
4650+
#endif
4651+
#ifdef WOLFSSL_DTLS13
4652+
if (ssl->options.dtls) {
4653+
/* RFC 9147 Section 5: DTLS implementations do not use the
4654+
* TLS 1.3 "compatibility mode" */
4655+
ssl->options.tls13MiddleBoxCompat = 0;
4656+
}
46514657
#endif
46524658
GetTls13SessionId(ssl, NULL, &sessIdSz);
46534659
args->length += (word16)sessIdSz;
@@ -5591,16 +5597,25 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
55915597
}
55925598
else
55935599
#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
5600+
#if defined(WOLFSSL_QUIC) || defined(WOLFSSL_DTLS13)
5601+
if (0
55945602
#ifdef WOLFSSL_QUIC
5595-
if (WOLFSSL_IS_QUIC(ssl)) {
5603+
|| WOLFSSL_IS_QUIC(ssl)
5604+
#endif
5605+
#ifdef WOLFSSL_DTLS13
5606+
|| ssl->options.dtls
5607+
#endif
5608+
) {
5609+
/* RFC 9147 Section 5.3 / RFC 9001 Section 8.4: DTLS 1.3 and QUIC
5610+
* ServerHello must have empty legacy_session_id_echo. */
55965611
if (args->sessIdSz != 0) {
55975612
WOLFSSL_MSG("args->sessIdSz != 0");
55985613
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
55995614
return INVALID_PARAMETER;
56005615
}
56015616
}
56025617
else
5603-
#endif /* WOLFSSL_QUIC */
5618+
#endif /* WOLFSSL_QUIC || WOLFSSL_DTLS13 */
56045619
if (args->sessIdSz != ssl->session->sessionIDSz || (args->sessIdSz > 0 &&
56055620
XMEMCMP(ssl->session->sessionID, args->sessId, args->sessIdSz) != 0))
56065621
{
@@ -6563,6 +6578,7 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
65636578
word16 length;
65646579
int keyShareExt = 0;
65656580
int ret;
6581+
byte sessIdSz;
65666582

65676583
ret = TlsCheckCookie(ssl, cookie->data, (byte)cookie->len);
65686584
if (ret < 0)
@@ -6587,7 +6603,13 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
65876603
return ret;
65886604

65896605
/* Reconstruct the HelloRetryMessage for handshake hash. */
6590-
length = HRR_BODY_SZ - ID_LEN + ssl->session->sessionIDSz +
6606+
sessIdSz = ssl->session->sessionIDSz;
6607+
#ifdef WOLFSSL_DTLS13
6608+
/* RFC 9147 Section 5.3: DTLS 1.3 must use empty legacy_session_id. */
6609+
if (ssl->options.dtls)
6610+
sessIdSz = 0;
6611+
#endif
6612+
length = HRR_BODY_SZ - ID_LEN + sessIdSz +
65916613
HRR_COOKIE_HDR_SZ + cookie->len;
65926614
length += HRR_VERSIONS_SZ;
65936615
/* HashSz (1 byte) + Hash (HashSz bytes) + CipherSuite (2 bytes) */
@@ -6614,10 +6636,10 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
66146636
XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN);
66156637
hrrIdx += RAN_LEN;
66166638

6617-
hrr[hrrIdx++] = ssl->session->sessionIDSz;
6618-
if (ssl->session->sessionIDSz > 0) {
6619-
XMEMCPY(hrr + hrrIdx, ssl->session->sessionID, ssl->session->sessionIDSz);
6620-
hrrIdx += ssl->session->sessionIDSz;
6639+
hrr[hrrIdx++] = sessIdSz;
6640+
if (sessIdSz > 0) {
6641+
XMEMCPY(hrr + hrrIdx, ssl->session->sessionID, sessIdSz);
6642+
hrrIdx += sessIdSz;
66216643
}
66226644

66236645
/* Restore the cipher suite from the cookie. */
@@ -6630,7 +6652,7 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
66306652
hrr[hrrIdx++] = 0;
66316653

66326654
/* Extensions' length */
6633-
length -= HRR_BODY_SZ - ID_LEN + ssl->session->sessionIDSz;
6655+
length -= HRR_BODY_SZ - ID_LEN + sessIdSz;
66346656
c16toa(length, hrr + hrrIdx);
66356657
hrrIdx += 2;
66366658

@@ -7055,9 +7077,20 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
70557077
if (sessIdSz + args->idx > helloSz)
70567078
ERROR_OUT(BUFFER_ERROR, exit_dch);
70577079

7058-
ssl->session->sessionIDSz = sessIdSz;
7059-
if (sessIdSz > 0)
7060-
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
7080+
#ifdef WOLFSSL_DTLS13
7081+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
7082+
* legacy_session_id_echo. Don't store the client's value so it
7083+
* won't be echoed in SendTls13ServerHello. */
7084+
if (ssl->options.dtls) {
7085+
ssl->session->sessionIDSz = 0;
7086+
}
7087+
else
7088+
#endif
7089+
{
7090+
ssl->session->sessionIDSz = sessIdSz;
7091+
if (sessIdSz > 0)
7092+
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
7093+
}
70617094
args->idx += sessIdSz;
70627095

70637096
#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
@@ -7630,10 +7663,21 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
76307663
WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN);
76317664
#endif
76327665

7633-
output[idx++] = ssl->session->sessionIDSz;
7634-
if (ssl->session->sessionIDSz > 0) {
7635-
XMEMCPY(output + idx, ssl->session->sessionID, ssl->session->sessionIDSz);
7636-
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+
}
76377681
}
76387682

76397683
/* Chosen cipher suite */

tests/api.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4559,12 +4559,12 @@ static WC_INLINE int test_ssl_memio_write_cb(WOLFSSL *ssl, char *data, int sz,
45594559
* "Import from Hex Dump..." option ion and selecting the TCP
45604560
* encapsulation option. */
45614561
char dump_file_name[64];
4562-
WOLFSSL_BIO *dump_file;
4562+
XFILE dump_file;
45634563
sprintf(dump_file_name, "%s/%s.dump", tmpDirName, currentTestName);
4564-
dump_file = wolfSSL_BIO_new_file(dump_file_name, "a");
4565-
if (dump_file != NULL) {
4566-
(void)wolfSSL_BIO_write(dump_file, data, sz);
4567-
wolfSSL_BIO_free(dump_file);
4564+
dump_file = XFOPEN(dump_file_name, "ab");
4565+
if (dump_file != XBADFILE) {
4566+
(void)XFWRITE(data, 1, (size_t)sz, dump_file);
4567+
XFCLOSE(dump_file);
45684568
}
45694569
}
45704570
#endif
@@ -30950,10 +30950,7 @@ static int test_short_session_id_ssl_ready(WOLFSSL* ssl)
3095030950
/* Setup the session to avoid errors */
3095130951
ssl->session->timeout = (word32)-1;
3095230952
ssl->session->side = WOLFSSL_CLIENT_END;
30953-
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
30954-
defined(HAVE_SESSION_TICKET))
3095530953
ssl->session->version = ssl->version;
30956-
#endif
3095730954
/* Force a short session ID to be sent */
3095830955
ssl->session->sessionIDSz = 4;
3095930956
#ifndef NO_SESSION_CACHE_REF

tests/api/test_dtls.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,3 +2727,90 @@ int test_dtls13_min_rtx_interval(void)
27272727
#endif
27282728
return EXPECT_RESULT();
27292729
}
2730+
2731+
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
2732+
* legacy_session_id_echo, even if the ClientHello had a non-empty
2733+
* legacy_session_id. */
2734+
int test_dtls13_no_session_id_echo(void)
2735+
{
2736+
EXPECT_DECLS;
2737+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) && \
2738+
defined(HAVE_SESSION_TICKET)
2739+
struct test_memio_ctx test_ctx;
2740+
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
2741+
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
2742+
WOLFSSL_SESSION *sess = NULL;
2743+
char readBuf[1];
2744+
/* Use traditional groups to avoid HRR from PQ key share mismatch */
2745+
int groups[] = {
2746+
WOLFSSL_ECC_SECP256R1,
2747+
WOLFSSL_ECC_SECP384R1,
2748+
};
2749+
2750+
/* First connection: complete a DTLS 1.3 handshake to get a session */
2751+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2752+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
2753+
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
2754+
ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);
2755+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
2756+
2757+
/* Read to process any NewSessionTicket */
2758+
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
2759+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
2760+
2761+
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
2762+
2763+
/* Ensure the session has a non-empty session ID so the ClientHello
2764+
* will have a populated legacy_session_id field (which is legal per
2765+
* RFC 9147). */
2766+
if (sess != NULL && sess->sessionIDSz == 0) {
2767+
sess->sessionIDSz = ID_LEN;
2768+
XMEMSET(sess->sessionID, 0x42, ID_LEN);
2769+
}
2770+
2771+
wolfSSL_free(ssl_c); ssl_c = NULL;
2772+
wolfSSL_free(ssl_s); ssl_s = NULL;
2773+
wolfSSL_CTX_free(ctx_c); ctx_c = NULL;
2774+
wolfSSL_CTX_free(ctx_s); ctx_s = NULL;
2775+
2776+
/* Second connection: set the session on the client so the ClientHello
2777+
* contains a non-empty legacy_session_id. Verify the server does NOT
2778+
* echo it in the ServerHello. */
2779+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
2780+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
2781+
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
2782+
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
2783+
/* Use traditional groups to avoid HRR from key share mismatch */
2784+
ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);
2785+
/* Disable HRR cookie so the server directly sends a ServerHello */
2786+
ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS);
2787+
2788+
/* Client sends ClientHello (with non-empty legacy_session_id) */
2789+
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
2790+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
2791+
2792+
/* Server processes ClientHello and sends ServerHello + flight */
2793+
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
2794+
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
2795+
2796+
/* Verify the ServerHello on the wire.
2797+
* Layout: DTLS Record Header (13) + DTLS Handshake Header (12) +
2798+
* ProtocolVersion (2) + Random (32) = offset 59 for
2799+
* legacy_session_id_echo length byte. */
2800+
ExpectIntGE(test_ctx.c_len, 60);
2801+
ExpectIntEQ(test_ctx.c_buff[0], handshake);
2802+
ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello);
2803+
ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ +
2804+
DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], 0);
2805+
2806+
/* Complete the handshake */
2807+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
2808+
2809+
wolfSSL_SESSION_free(sess);
2810+
wolfSSL_free(ssl_c);
2811+
wolfSSL_free(ssl_s);
2812+
wolfSSL_CTX_free(ctx_c);
2813+
wolfSSL_CTX_free(ctx_s);
2814+
#endif
2815+
return EXPECT_RESULT();
2816+
}

0 commit comments

Comments
 (0)