Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -43491,8 +43491,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
if (certDer != NULL && certDerSz > 0 &&
certDerSz <= MAX_TICKET_PEER_CERT_SZ
#ifdef HAVE_MAX_FRAGMENT
/* We don't support fragmentation in
* SendTls13NewSessionTicket yet. */
/* The ticket returns in a ClientHello, which is never
* fragmented and after a HelloRetryRequest must fit the
* reduced limit. */
&& (!IsAtLeastTLSv1_3(ssl->version) ||
ssl->max_fragment == MAX_RECORD_SIZE)
#endif
Expand Down
63 changes: 53 additions & 10 deletions src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -14769,6 +14769,12 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl)
int sendSz;
word16 extSz;
word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
word32 hsSz = 0;
word32 fragSz;
word32 fragOff;
word32 fragRoom = 0;
int maxFrag = 0;
byte* plain;

WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_SEND);
WOLFSSL_ENTER("SendTls13NewSessionTicket");
Expand Down Expand Up @@ -14859,12 +14865,27 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl)

sendSz = (int)(idx + length + MAX_MSG_EXTRA);

/* DTLS 1.3 fragments in Dtls13HandshakeSend(). Otherwise reserve room
* for the records ahead of the plaintext so neither overlaps. */
if (!ssl->options.dtls) {
maxFrag = wolfssl_local_GetMaxPlaintextSize(ssl);
if (maxFrag <= 0)
return (maxFrag < 0) ? maxFrag : BUFFER_E;
hsSz = HANDSHAKE_HEADER_SZ + length;
if (hsSz > (word32)maxFrag) {
fragRoom = hsSz + ((hsSz + (word32)maxFrag - 1) /
(word32)maxFrag) *
(RECORD_HEADER_SZ + MAX_MSG_EXTRA);
sendSz = (int)(fragRoom + idx + length);
}
}

/* Check buffers are big enough and grow if needed. */
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
return ret;

/* Get position in output buffer to write new message to. */
output = GetOutputBuffer(ssl);
output = GetOutputBuffer(ssl) + fragRoom;

/* Put the record and handshake headers on. */
AddTls13Headers(output, length, session_ticket, ssl);
Expand Down Expand Up @@ -14914,7 +14935,7 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl)
#endif

if (idx > WOLFSSL_MAX_16BIT ||
sendSz > (int)WOLFSSL_MAX_16BIT) {
(fragRoom == 0 && sendSz > (int)WOLFSSL_MAX_16BIT)) {
return BAD_LENGTH_E;
}

Expand All @@ -14934,15 +14955,37 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl)
(word16)idx, session_ticket, 0);
#endif /* WOLFSSL_DTLS13 */

/* This message is always encrypted. */
sendSz = BuildTls13Message(ssl, output, sendSz,
output + RECORD_HEADER_SZ,
(word16)idx - RECORD_HEADER_SZ,
handshake, 0, 0, 0);
if (sendSz < 0)
return sendSz;
if (fragRoom > 0) {
/* RFC 8446 Section 5.1: split across adjacent handshake records so
* each fits the negotiated maximum fragment length. */
plain = output + RECORD_HEADER_SZ;
for (fragOff = 0; fragOff < hsSz; fragOff += fragSz) {
fragSz = min(hsSz - fragOff, (word32)maxFrag);
output = GetOutputBuffer(ssl);
sendSz = BuildTls13Message(ssl, output,
(int)(RECORD_HEADER_SZ + fragSz +
MAX_MSG_EXTRA),
plain + fragOff, (int)fragSz,
handshake, 0, 0, 0);
if (sendSz < 0)
break;
ssl->buffers.outputBuffer.length += (word32)sendSz;
}
ForceZero(plain, hsSz);
if (sendSz < 0)
return sendSz;
}
else {
/* This message is always encrypted. */
sendSz = BuildTls13Message(ssl, output, sendSz,
output + RECORD_HEADER_SZ,
(word16)idx - RECORD_HEADER_SZ,
handshake, 0, 0, 0);
if (sendSz < 0)
return sendSz;

ssl->buffers.outputBuffer.length += sendSz;
ssl->buffers.outputBuffer.length += sendSz;
}

/* Always send as this is either directly after server's Finished or only
* message after client's Finished.
Expand Down
73 changes: 73 additions & 0 deletions tests/api/test_tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -13979,3 +13979,76 @@ int test_tls13_psk_key_zeroized(void)
#endif
return EXPECT_RESULT();
}

/* A NewSessionTicket larger than the negotiated max fragment length must be
* split across records (RFC 8446 Section 5.1). With a 256 byte limit the
* ticket is split in builds whose internal ticket is large enough. */
int test_tls13_new_session_ticket_max_fragment(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
defined(HAVE_MAX_FRAGMENT) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
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[64];
int off;
int recSz = 0;
int recCnt = 0;

XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c, WOLFSSL_MFL_2_8),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

/* Process the ticket sent at the end of the handshake. */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(test_ctx.c_len, 0);

ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s), WOLFSSL_SUCCESS);
/* Each record holds at most 256 bytes plus content type and AEAD tag. */
for (off = 0; EXPECT_SUCCESS() && off + RECORD_HEADER_SZ <= test_ctx.c_len;
off += RECORD_HEADER_SZ + recSz) {
ExpectIntEQ(test_ctx.c_buff[off], application_data);
recSz = (test_ctx.c_buff[off + 3] << 8) | test_ctx.c_buff[off + 4];
ExpectIntLE(recSz, 256 + 1 + 16);
recCnt++;
}
ExpectIntEQ(off, test_ctx.c_len);

ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntGT(ssl_c->session->ticketLen, 0);
/* Handshake header, lifetime, age add, nonce, ticket length and empty
* extensions add 18 bytes to the ticket. */
if (ssl_c->session->ticketLen + 18 > 256)
ExpectIntGE(recCnt, 2);
Comment thread
embhorn marked this conversation as resolved.
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));

/* Resume with the reassembled ticket. */
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c, WOLFSSL_MFL_2_8),
WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_session_reused(ssl_c), 1);

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();
}
4 changes: 3 additions & 1 deletion tests/api/test_tls13.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ int test_tls13_cryptocb_async(void);
int test_tls13_ticket_psk_modes(void);
int test_tls13_psk_mode_mismatch_falls_back(void);
int test_tls13_ticket_psk_modes_uses_policy(void);
int test_tls13_new_session_ticket_max_fragment(void);
int test_tls13_send_session_ticket_psk_modes(void);
int test_tls13_new_session_ticket_ext_framing(void);
int test_tls13_new_session_ticket_keeps_ems(void);
Expand Down Expand Up @@ -302,6 +303,7 @@ int test_tls13_psk_key_zeroized(void);
TEST_DECL_GROUP("tls13", test_tls13_hs_secret_zeroized_psk_ke), \
TEST_DECL_GROUP("tls13", test_tls13_hs_secret_zeroized_sha384), \
TEST_DECL_GROUP("tls13", test_tls13_early_secret_zeroized), \
TEST_DECL_GROUP("tls13", test_tls13_psk_key_zeroized)
TEST_DECL_GROUP("tls13", test_tls13_psk_key_zeroized), \
TEST_DECL_GROUP("tls13", test_tls13_new_session_ticket_max_fragment)

#endif /* WOLFCRYPT_TEST_TLS13_H */
Loading