Skip to content
6 changes: 3 additions & 3 deletions src/dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -857,9 +857,9 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch)
nonConstSSL->options.tls1_1 = 1;
nonConstSSL->options.tls1_3 = 1;

XMEMCPY(nonConstSSL->session->sessionID, ch->sessionId.elements,
ch->sessionId.size);
nonConstSSL->session->sessionIDSz = (byte)ch->sessionId.size;
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
* legacy_session_id_echo. Don't copy the client's session ID. */
nonConstSSL->session->sessionIDSz = 0;
nonConstSSL->options.cipherSuite0 = cs.cipherSuite0;
nonConstSSL->options.cipherSuite = cs.cipherSuite;
nonConstSSL->extensions = parsedExts;
Expand Down
27 changes: 5 additions & 22 deletions src/ssl_sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -1142,10 +1142,8 @@ static int CheckSessionMatch(const WOLFSSL* ssl, const WOLFSSL_SESSION* sess)
XMEMCMP(ssl->sessionCtx, sess->sessionCtx, sess->sessionCtxSz) != 0))
return 0;
#endif
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
if (IsAtLeastTLSv1_3(ssl->version) != IsAtLeastTLSv1_3(sess->version))
return 0;
#endif
return 1;
}

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

#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
defined(HAVE_SESSION_TICKET))
ssl->version = ssl->session->version;
if (IsAtLeastTLSv1_3(ssl->version))
ssl->options.tls1_3 = 1;
#endif
if (ssl->session->version.major != 0) {
ssl->version = ssl->session->version;
if (IsAtLeastTLSv1_3(ssl->version))
ssl->options.tls1_3 = 1;
}
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
ssl->options.cipherSuite0 = ssl->session->cipherSuite0;
Expand Down Expand Up @@ -2601,11 +2598,8 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
for (i = 0; i < sess->chain.count; i++)
size += OPAQUE16_LEN + sess->chain.certs[i].length;
#endif
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
defined(HAVE_SESSION_TICKET))
/* Protocol version */
size += OPAQUE16_LEN;
Comment thread
julek-wolfssl marked this conversation as resolved.
#endif
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
Comment thread
julek-wolfssl marked this conversation as resolved.
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
/* cipher suite */
Expand Down Expand Up @@ -2681,11 +2675,8 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p)
idx += sess->chain.certs[i].length;
}
#endif
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
defined(HAVE_SESSION_TICKET))
data[idx++] = sess->version.major;
data[idx++] = sess->version.minor;
#endif
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
data[idx++] = sess->cipherSuite0;
Expand Down Expand Up @@ -2854,16 +2845,13 @@ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess,
idx += length;
}
#endif
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
defined(HAVE_SESSION_TICKET))
/* Protocol Version */
if (i - idx < OPAQUE16_LEN) {
ret = BUFFER_ERROR;
goto end;
}
s->version.major = data[idx++];
s->version.minor = data[idx++];
#endif
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
Comment thread
julek-wolfssl marked this conversation as resolved.
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
/* Cipher suite */
Expand Down Expand Up @@ -3176,10 +3164,8 @@ static void SESSION_ex_data_cache_update(WOLFSSL_SESSION* session, int idx,
if (cacheSession && cacheSession->sessionIDSz == ID_LEN &&
XMEMCMP(id, cacheSession->sessionID, ID_LEN) == 0
&& session->side == cacheSession->side
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)
&& (IsAtLeastTLSv1_3(session->version) ==
IsAtLeastTLSv1_3(cacheSession->version))
#endif
) {
if (get) {
if (getRet) {
Expand Down Expand Up @@ -3604,10 +3590,7 @@ void SetupSession(WOLFSSL* ssl)
#ifndef NO_ASN_TIME
session->bornOn = LowResTimer();
#endif
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
defined(HAVE_SESSION_TICKET))
session->version = ssl->version;
#endif
#if defined(SESSION_CERTS) || !defined(NO_RESUME_SUITE_CHECK) || \
(defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET))
session->cipherSuite0 = ssl->options.cipherSuite0;
Expand Down
2 changes: 0 additions & 2 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -12198,7 +12198,6 @@ static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, const byte* input,
}
list->chosen = 1;

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

return 0;
}
Expand Down
78 changes: 61 additions & 17 deletions src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -4574,8 +4574,8 @@ int SendTls13ClientHello(WOLFSSL* ssl)
}
#endif /* WOLFSSL_DTLS */

#ifdef HAVE_SESSION_TICKET
if (ssl->options.resuming &&
ssl->session->version.major != 0 &&
(ssl->session->version.major != ssl->version.major ||
ssl->session->version.minor != ssl->version.minor)) {
#ifndef WOLFSSL_NO_TLS12
Expand All @@ -4594,7 +4594,6 @@ int SendTls13ClientHello(WOLFSSL* ssl)
return VERSION_ERROR;
}
}
#endif

suites = WOLFSSL_SUITES(ssl);
if (suites == NULL) {
Expand Down Expand Up @@ -4648,6 +4647,13 @@ int SendTls13ClientHello(WOLFSSL* ssl)
ssl->session->sessionIDSz = 0;
ssl->options.tls13MiddleBoxCompat = 0;
}
#endif
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
/* RFC 9147 Section 5: DTLS implementations do not use the
* TLS 1.3 "compatibility mode" */
ssl->options.tls13MiddleBoxCompat = 0;
}
Comment thread
julek-wolfssl marked this conversation as resolved.
#endif
GetTls13SessionId(ssl, NULL, &sessIdSz);
args->length += (word16)sessIdSz;
Expand Down Expand Up @@ -5591,16 +5597,25 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
}
else
#endif /* WOLFSSL_TLS13_MIDDLEBOX_COMPAT */
#if defined(WOLFSSL_QUIC) || defined(WOLFSSL_DTLS13)
if (0
#ifdef WOLFSSL_QUIC
if (WOLFSSL_IS_QUIC(ssl)) {
|| WOLFSSL_IS_QUIC(ssl)
#endif
#ifdef WOLFSSL_DTLS13
|| ssl->options.dtls
#endif
) {
/* RFC 9147 Section 5.3 / RFC 9001 Section 8.4: DTLS 1.3 and QUIC
* ServerHello must have empty legacy_session_id_echo. */
if (args->sessIdSz != 0) {
WOLFSSL_MSG("args->sessIdSz != 0");
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
}
else
#endif /* WOLFSSL_QUIC */
#endif /* WOLFSSL_QUIC || WOLFSSL_DTLS13 */
if (args->sessIdSz != ssl->session->sessionIDSz || (args->sessIdSz > 0 &&
XMEMCMP(ssl->session->sessionID, args->sessId, args->sessIdSz) != 0))
{
Expand Down Expand Up @@ -6563,6 +6578,7 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
word16 length;
int keyShareExt = 0;
int ret;
byte sessIdSz;

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

/* Reconstruct the HelloRetryMessage for handshake hash. */
length = HRR_BODY_SZ - ID_LEN + ssl->session->sessionIDSz +
sessIdSz = ssl->session->sessionIDSz;
#ifdef WOLFSSL_DTLS13
Comment thread
douzzer marked this conversation as resolved.
/* RFC 9147 Section 5.3: DTLS 1.3 must use empty legacy_session_id. */
if (ssl->options.dtls)
sessIdSz = 0;
#endif
length = HRR_BODY_SZ - ID_LEN + sessIdSz +
HRR_COOKIE_HDR_SZ + cookie->len;
length += HRR_VERSIONS_SZ;
/* HashSz (1 byte) + Hash (HashSz bytes) + CipherSuite (2 bytes) */
Expand All @@ -6614,10 +6636,10 @@ static int RestartHandshakeHashWithCookie(WOLFSSL* ssl, Cookie* cookie)
XMEMCPY(hrr + hrrIdx, helloRetryRequestRandom, RAN_LEN);
hrrIdx += RAN_LEN;

hrr[hrrIdx++] = ssl->session->sessionIDSz;
if (ssl->session->sessionIDSz > 0) {
XMEMCPY(hrr + hrrIdx, ssl->session->sessionID, ssl->session->sessionIDSz);
hrrIdx += ssl->session->sessionIDSz;
hrr[hrrIdx++] = sessIdSz;
if (sessIdSz > 0) {
XMEMCPY(hrr + hrrIdx, ssl->session->sessionID, sessIdSz);
hrrIdx += sessIdSz;
}

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

/* Extensions' length */
length -= HRR_BODY_SZ - ID_LEN + ssl->session->sessionIDSz;
length -= HRR_BODY_SZ - ID_LEN + sessIdSz;
c16toa(length, hrr + hrrIdx);
hrrIdx += 2;

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

ssl->session->sessionIDSz = sessIdSz;
if (sessIdSz > 0)
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
#ifdef WOLFSSL_DTLS13
Comment thread
douzzer marked this conversation as resolved.
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
* legacy_session_id_echo. Don't store the client's value so it
* won't be echoed in SendTls13ServerHello. */
if (ssl->options.dtls) {
ssl->session->sessionIDSz = 0;
}
else
#endif
{
ssl->session->sessionIDSz = sessIdSz;
if (sessIdSz > 0)
XMEMCPY(ssl->session->sessionID, input + args->idx, sessIdSz);
}
Comment thread
julek-wolfssl marked this conversation as resolved.
args->idx += sessIdSz;

#ifdef WOLFSSL_TLS13_MIDDLEBOX_COMPAT
Expand Down Expand Up @@ -7630,10 +7663,21 @@ int SendTls13ServerHello(WOLFSSL* ssl, byte extMsgType)
WOLFSSL_BUFFER(ssl->arrays->serverRandom, RAN_LEN);
#endif

output[idx++] = ssl->session->sessionIDSz;
if (ssl->session->sessionIDSz > 0) {
XMEMCPY(output + idx, ssl->session->sessionID, ssl->session->sessionIDSz);
idx += ssl->session->sessionIDSz;
#ifdef WOLFSSL_DTLS13
if (ssl->options.dtls) {
/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
* legacy_session_id_echo. */
output[idx++] = 0;
}
else
#endif
{
output[idx++] = ssl->session->sessionIDSz;
if (ssl->session->sessionIDSz > 0) {
XMEMCPY(output + idx, ssl->session->sessionID,
ssl->session->sessionIDSz);
idx += ssl->session->sessionIDSz;
}
}
Comment thread
julek-wolfssl marked this conversation as resolved.

/* Chosen cipher suite */
Expand Down
13 changes: 5 additions & 8 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -4559,12 +4559,12 @@ static WC_INLINE int test_ssl_memio_write_cb(WOLFSSL *ssl, char *data, int sz,
* "Import from Hex Dump..." option ion and selecting the TCP
* encapsulation option. */
char dump_file_name[64];
WOLFSSL_BIO *dump_file;
XFILE dump_file;
sprintf(dump_file_name, "%s/%s.dump", tmpDirName, currentTestName);
dump_file = wolfSSL_BIO_new_file(dump_file_name, "a");
if (dump_file != NULL) {
(void)wolfSSL_BIO_write(dump_file, data, sz);
wolfSSL_BIO_free(dump_file);
dump_file = XFOPEN(dump_file_name, "ab");
if (dump_file != XBADFILE) {
(void)XFWRITE(data, 1, (size_t)sz, dump_file);
XFCLOSE(dump_file);
}
}
#endif
Expand Down Expand Up @@ -30950,10 +30950,7 @@ static int test_short_session_id_ssl_ready(WOLFSSL* ssl)
/* Setup the session to avoid errors */
ssl->session->timeout = (word32)-1;
ssl->session->side = WOLFSSL_CLIENT_END;
#if defined(SESSION_CERTS) || (defined(WOLFSSL_TLS13) && \
defined(HAVE_SESSION_TICKET))
ssl->session->version = ssl->version;
#endif
/* Force a short session ID to be sent */
ssl->session->sessionIDSz = 4;
#ifndef NO_SESSION_CACHE_REF
Expand Down
87 changes: 87 additions & 0 deletions tests/api/test_dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -2727,3 +2727,90 @@ int test_dtls13_min_rtx_interval(void)
#endif
return EXPECT_RESULT();
}

/* RFC 9147 Section 5.3: DTLS 1.3 ServerHello must have empty
* legacy_session_id_echo, even if the ClientHello had a non-empty
* legacy_session_id. */
int test_dtls13_no_session_id_echo(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) && \
defined(HAVE_SESSION_TICKET)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
char readBuf[1];
/* Use traditional groups to avoid HRR from PQ key share mismatch */
int groups[] = {
WOLFSSL_ECC_SECP256R1,
WOLFSSL_ECC_SECP384R1,
};

/* First connection: complete a DTLS 1.3 handshake to get a session */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

/* Read to process any NewSessionTicket */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));

/* Ensure the session has a non-empty session ID so the ClientHello
* will have a populated legacy_session_id field (which is legal per
* RFC 9147). */
if (sess != NULL && sess->sessionIDSz == 0) {
sess->sessionIDSz = ID_LEN;
XMEMSET(sess->sessionID, 0x42, ID_LEN);
}
Comment thread
julek-wolfssl marked this conversation as resolved.
Comment thread
julek-wolfssl marked this conversation as resolved.

wolfSSL_free(ssl_c); ssl_c = NULL;
wolfSSL_free(ssl_s); ssl_s = NULL;
wolfSSL_CTX_free(ctx_c); ctx_c = NULL;
wolfSSL_CTX_free(ctx_s); ctx_s = NULL;

/* Second connection: set the session on the client so the ClientHello
* contains a non-empty legacy_session_id. Verify the server does NOT
* echo it in the ServerHello. */
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
/* Use traditional groups to avoid HRR from key share mismatch */
ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);
/* Disable HRR cookie so the server directly sends a ServerHello */
Comment thread
julek-wolfssl marked this conversation as resolved.
ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS);

/* Client sends ClientHello (with non-empty legacy_session_id) */
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);

/* Server processes ClientHello and sends ServerHello + flight */
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);

/* Verify the ServerHello on the wire.
* Layout: DTLS Record Header (13) + DTLS Handshake Header (12) +
* ProtocolVersion (2) + Random (32) = offset 59 for
* legacy_session_id_echo length byte. */
ExpectIntGE(test_ctx.c_len, 60);
ExpectIntEQ(test_ctx.c_buff[0], handshake);
ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ], server_hello);
ExpectIntEQ(test_ctx.c_buff[DTLS_RECORD_HEADER_SZ +
DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN], 0);
Comment thread
julek-wolfssl marked this conversation as resolved.
Comment thread
julek-wolfssl marked this conversation as resolved.

Comment thread
julek-wolfssl marked this conversation as resolved.
Comment thread
julek-wolfssl marked this conversation as resolved.
/* Complete the handshake */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
Loading
Loading