mirror of https://github.com/wolfSSL/wolfssl.git
Merge pull request #11178 from julek-wolfssl/fix/rfc9846-session-ticket-compliance
Harden TLS 1.3 NewSessionTicket handling per RFC 9846pull/11340/merge
commit
5d17d603e2
|
|
@ -1148,6 +1148,7 @@ WOLFSSL_TLS13_DRAFT
|
|||
WOLFSSL_TLS13_IGNORE_AEAD_LIMITS
|
||||
WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
|
||||
WOLFSSL_TLS13_SHA512
|
||||
WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES
|
||||
WOLFSSL_TLS13_TICKET_BEFORE_FINISHED
|
||||
WOLFSSL_TLSX_PQC_MLKEM_STORE_PRIV_KEY
|
||||
WOLFSSL_TRACK_MEMORY_FULL
|
||||
|
|
|
|||
27
src/dtls.c
27
src/dtls.c
|
|
@ -816,16 +816,27 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch)
|
|||
if (ret != 0)
|
||||
goto dtls13_cleanup;
|
||||
if ((modes & (1 << PSK_DHE_KE)) &&
|
||||
!ssl->options.noPskDheKe) {
|
||||
!ssl->options.noPskDheKePolicy) {
|
||||
if (!haveKS)
|
||||
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
|
||||
doKE = 1;
|
||||
usePSK = 1;
|
||||
}
|
||||
else if ((modes & (1 << PSK_KE)) == 0 ||
|
||||
ssl->options.onlyPskDheKe) {
|
||||
else if ((modes & (1 << PSK_KE)) != 0 &&
|
||||
!ssl->options.onlyPskDheKe) {
|
||||
usePSK = 1;
|
||||
}
|
||||
else if (!haveKS || !haveSA || !haveSG) {
|
||||
/* No usable mode and nothing to fall back to. */
|
||||
ERROR_OUT(PSK_KEY_ERROR, dtls13_cleanup);
|
||||
}
|
||||
usePSK = 1;
|
||||
else {
|
||||
/* RFC 9846 Section 4.3.11: ignore the PSK and do a full
|
||||
* handshake. Mirrors PskModesUsable() so this stateless reply
|
||||
* and the stateful ClientHello agree on the cipher suite. */
|
||||
WOLFSSL_MSG("psk_key_exchange_modes offer no usable mode, "
|
||||
"ignoring PSK");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -857,6 +868,14 @@ static int SendStatelessReplyDtls13(const WOLFSSL* ssl, WolfSSL_CH* ch)
|
|||
else
|
||||
#endif /* defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) */
|
||||
{
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
/* Not using a PSK, so a key share is needed. DoTls13ClientHello() does
|
||||
* the same for the stateful pass. Without it a no-(EC)DHE-with-PSK
|
||||
* server omits key_share from the HelloRetryRequest while the cookie
|
||||
* still records the group, and the two transcripts diverge. The
|
||||
* configured policy is kept in noPskDheKePolicy. */
|
||||
((WOLFSSL*)ssl)->options.noPskDheKe = 0;
|
||||
#endif
|
||||
/* https://datatracker.ietf.org/doc/html/rfc8446#section-9.2 */
|
||||
if (!haveKS || !haveSA || !haveSG) {
|
||||
WOLFSSL_MSG("Client didn't send KeyShare or SigAlgs or "
|
||||
|
|
|
|||
|
|
@ -8476,6 +8476,7 @@ static void InitSSL_Tls13Options(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
|
|||
#endif
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
ssl->options.noPskDheKe = ctx->noPskDheKe;
|
||||
ssl->options.noPskDheKePolicy = ctx->noPskDheKe;
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
ssl->options.onlyPskDheKe = ctx->onlyPskDheKe;
|
||||
#endif /* HAVE_SUPPORTED_CURVES */
|
||||
|
|
|
|||
|
|
@ -5712,6 +5712,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
|
|||
#ifdef WOLFSSL_TLS13
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
ssl->options.noPskDheKe = ssl->ctx->noPskDheKe;
|
||||
ssl->options.noPskDheKePolicy = ssl->ctx->noPskDheKe;
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
ssl->options.onlyPskDheKe = ssl->ctx->onlyPskDheKe;
|
||||
#endif
|
||||
|
|
@ -5745,6 +5746,13 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
|
|||
#ifdef HAVE_SESSION_TICKET
|
||||
#ifdef WOLFSSL_TLS13
|
||||
ssl->options.ticketsSent = 0;
|
||||
#if !defined(NO_WOLFSSL_SERVER) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES)
|
||||
/* Recorded from the ClientHello, so it must not carry into the next
|
||||
* connection on a reused object. */
|
||||
ssl->options.pskKeModes = 0;
|
||||
ssl->options.pskKeModesRecvd = 0;
|
||||
#endif
|
||||
#endif
|
||||
ssl->options.rejectTicket = 0;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1052,8 +1052,11 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len)
|
|||
#else
|
||||
current = &sessRow->Sessions[clSess[idx].serverIdx];
|
||||
#endif
|
||||
if (current && XMEMCMP(current->serverID, id,
|
||||
(unsigned long)len) == 0) {
|
||||
/* Require the same length as well as the same bytes. Comparing only
|
||||
* the requested length lets a short ID alias the prefix of a longer
|
||||
* cached one, mixing sessions the application meant to keep apart. */
|
||||
if (current && current->idLen == (word16)len &&
|
||||
XMEMCMP(current->serverID, id, (unsigned long)len) == 0) {
|
||||
WOLFSSL_MSG("Found a serverid match for client");
|
||||
if (LowResTimer() < (current->bornOn + current->timeout)) {
|
||||
WOLFSSL_MSG("Session valid");
|
||||
|
|
|
|||
16
src/tls.c
16
src/tls.c
|
|
@ -13053,8 +13053,17 @@ static int TLSX_PskKeModes_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
|||
byte modes;
|
||||
|
||||
ret = TLSX_PskKeyModes_Parse_Modes(input, length, msgType, &modes);
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES)
|
||||
/* Keep the advertised modes for the NewSessionTicket decision. The
|
||||
* extension object is dropped with the rest of the handshake state
|
||||
* once the handshake is done. */
|
||||
ssl->options.pskKeModes = modes;
|
||||
ssl->options.pskKeModesRecvd = 1;
|
||||
#endif
|
||||
ret = TLSX_PskKeyModes_Use(ssl, modes);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
|
|
@ -19410,9 +19419,12 @@ WOLFSSL_TEST_VIS int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length,
|
|||
|
||||
#ifdef HAVE_EXTENDED_MASTER
|
||||
if (IsAtLeastTLSv1_3(ssl->version) &&
|
||||
(msgType == hello_retry_request || msgType == hello_verify_request)) {
|
||||
(msgType == hello_retry_request || msgType == hello_verify_request ||
|
||||
msgType == session_ticket)) {
|
||||
/* Don't change EMS status until server_hello received.
|
||||
* Second ClientHello must have same extensions.
|
||||
* NewSessionTicket is post-handshake and never carries the extension,
|
||||
* so its absence there says nothing about what was negotiated.
|
||||
*/
|
||||
}
|
||||
else if (!isRequest && ssl->options.haveEMS && !pendingEMS)
|
||||
|
|
|
|||
165
src/tls13.c
165
src/tls13.c
|
|
@ -79,6 +79,12 @@
|
|||
* WOLFSSL_TICKET_HAVE_ID: Session tickets include ID default: off
|
||||
* Forced on when WOLFSSL_EARLY_DATA is set.
|
||||
* WOLFSSL_TICKET_NONCE_MALLOC: Dynamically allocate ticket nonce default: off
|
||||
* WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES: Withhold NewSessionTicket default: off
|
||||
* when the ClientHello advertised no usable
|
||||
* psk_key_exchange_modes, as RFC 9846 Sections
|
||||
* 4.3.9 and 4.7.1 require. Off by default: a peer
|
||||
* that omits the extension but expects a ticket
|
||||
* stops getting one.
|
||||
*
|
||||
* TLS 1.3 Key Exchange:
|
||||
* HAVE_KEYING_MATERIAL: Export keying material (RFC 8446 7.5) default: off
|
||||
|
|
@ -7040,6 +7046,63 @@ cleanup:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Check whether a PSK may be used given the key exchange modes the client
|
||||
* advertised and the modes this server is configured to allow.
|
||||
*
|
||||
* RFC 9846 Section 4.3.9 forbids selecting a mode the client did not list.
|
||||
* Section 4.3.11 says a server that finds no acceptable PSK should perform a
|
||||
* non-PSK handshake instead of aborting. Deciding before a PSK is selected
|
||||
* leaves nothing to unwind: no ticket is decrypted, no binder is verified, no
|
||||
* secret is derived and no early data is accepted.
|
||||
*
|
||||
* The configured policy is read, not ssl->options.noPskDheKe, which also
|
||||
* carries negotiated state and is cleared by every certificate handshake.
|
||||
*
|
||||
* ssl SSL/TLS object.
|
||||
* clSuites Client's cipher suite list.
|
||||
* returns 1 when PSK selection may proceed and 0 when the PSK must be ignored.
|
||||
*/
|
||||
static int PskModesUsable(const WOLFSSL* ssl, const Suites* clSuites)
|
||||
{
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
TLSX* ext;
|
||||
word32 modes;
|
||||
|
||||
/* Offering pre_shared_key without psk_key_exchange_modes is a MUST-level
|
||||
* abort (Section 4.3.9). Leave it to CheckPreSharedKeys. */
|
||||
ext = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES);
|
||||
if (ext == NULL)
|
||||
return 1;
|
||||
modes = ext->val;
|
||||
|
||||
#ifdef WOLFSSL_CERT_WITH_EXTERN_PSK
|
||||
/* RFC 9973 requires psk_dhe_ke and overrides the no-(EC)DHE policy, so a
|
||||
* mismatch must abort rather than fall back. */
|
||||
if (TLSX_Find(ssl->extensions, TLSX_CERT_WITH_EXTERN_PSK) != NULL)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* Only decline when a certificate handshake can actually run instead.
|
||||
* These are the same two things DoTls13ClientHello() requires of a
|
||||
* ClientHello that negotiates no PSK. */
|
||||
if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL)
|
||||
return 1;
|
||||
if (clSuites == NULL || clSuites->hashSigAlgoSz == 0)
|
||||
return 1;
|
||||
|
||||
if ((modes & (1 << PSK_DHE_KE)) != 0 && !ssl->options.noPskDheKePolicy)
|
||||
return 1;
|
||||
if (ssl->options.onlyPskDheKe)
|
||||
return 0;
|
||||
return (modes & (1 << PSK_KE)) != 0;
|
||||
#else
|
||||
/* Without (EC)DHE there is no certificate handshake to fall back to. */
|
||||
(void)ssl;
|
||||
(void)clSuites;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Handle any Pre-Shared Key (PSK) extension.
|
||||
* Must do this in ClientHello as it requires a hash of the truncated message.
|
||||
* Don't know size of binders until Pre-Shared Key extension has been parsed.
|
||||
|
|
@ -7057,6 +7120,7 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
|||
TLSX* ext;
|
||||
word16 bindersLen;
|
||||
int first = 0;
|
||||
int usePsk;
|
||||
#ifndef WOLFSSL_PSK_ONE_ID
|
||||
int i;
|
||||
const Suites* suites;
|
||||
|
|
@ -7109,6 +7173,12 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
|||
|
||||
/* Refine list for PSK processing. */
|
||||
sslRefineSuites(ssl, clSuites);
|
||||
|
||||
usePsk = PskModesUsable(ssl, clSuites);
|
||||
if (!usePsk) {
|
||||
WOLFSSL_MSG("No usable psk_key_exchange_modes, ignoring PSK");
|
||||
}
|
||||
|
||||
#ifndef WOLFSSL_PSK_ONE_ID
|
||||
if (usingPSK == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
|
@ -7117,7 +7187,7 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
|||
suites = WOLFSSL_SUITES(ssl);
|
||||
/* Server list has only common suites from refining in server or client
|
||||
* order. */
|
||||
for (i = 0; !(*usingPSK) && i < suites->suiteSz; i += 2) {
|
||||
for (i = 0; usePsk && !(*usingPSK) && i < suites->suiteSz; i += 2) {
|
||||
ret = DoPreSharedKeys(ssl, input, helloSz - bindersLen,
|
||||
suites->suites + i, usingPSK, &first);
|
||||
if (ret != 0) {
|
||||
|
|
@ -7135,11 +7205,13 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
|||
CleanupClientTickets((PreSharedKey*)ext->data);
|
||||
#endif
|
||||
#else
|
||||
ret = DoPreSharedKeys(ssl, input, helloSz - bindersLen, suite, usingPSK,
|
||||
&first);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_MSG_EX("DoPreSharedKeys: %d", ret);
|
||||
return ret;
|
||||
if (usePsk) {
|
||||
ret = DoPreSharedKeys(ssl, input, helloSz - bindersLen, suite, usingPSK,
|
||||
&first);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_MSG_EX("DoPreSharedKeys: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -7306,8 +7378,8 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
|||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
ext = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
|
||||
/* Use (EC)DHE for forward-security if possible. */
|
||||
if (((modes & (1 << PSK_DHE_KE)) != 0 && !ssl->options.noPskDheKe &&
|
||||
ext != NULL)
|
||||
if (((modes & (1 << PSK_DHE_KE)) != 0 &&
|
||||
!ssl->options.noPskDheKePolicy && ext != NULL)
|
||||
#ifdef WOLFSSL_CERT_WITH_EXTERN_PSK
|
||||
|| usingCertWithExternPsk
|
||||
#endif
|
||||
|
|
@ -7327,7 +7399,11 @@ static int CheckPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 helloSz,
|
|||
(ssl->options.failNoPSK && !ssl->options.resuming)) {
|
||||
/* A mandatory external PSK (failNoPSK) must be combined with
|
||||
* (EC)DHE for forward secrecy, so reject a pure psk_ke
|
||||
* negotiation. Session-ticket resumption is exempt. */
|
||||
* negotiation. Session-ticket resumption is exempt.
|
||||
* onlyPskDheKe only reaches here when PskModesUsable() could not
|
||||
* decline, i.e. there is no certificate handshake to fall back
|
||||
* to. */
|
||||
WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR);
|
||||
return PSK_KEY_ERROR;
|
||||
}
|
||||
else
|
||||
|
|
@ -14472,12 +14548,12 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input,
|
|||
*inOutIdx += EXTS_SZ;
|
||||
if ((*inOutIdx - begin) + length != size)
|
||||
return BUFFER_ERROR;
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
ret = TLSX_Parse(ssl, (byte *)input + (*inOutIdx), length, session_ticket,
|
||||
NULL);
|
||||
/* RFC 9846 Section 4.7.1: the extensions are Section 4.3 Extension TLVs.
|
||||
* Malformed framing is a syntax error even when no extension in the list
|
||||
* is one we act on. */
|
||||
ret = TLSX_Parse(ssl, input + *inOutIdx, length, session_ticket, NULL);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#endif
|
||||
*inOutIdx += length;
|
||||
|
||||
SetupSession(ssl);
|
||||
|
|
@ -14623,6 +14699,50 @@ restore:
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Check the client advertised a PSK key exchange mode a resumption ticket can
|
||||
* be used with.
|
||||
*
|
||||
* RFC 9846 Section 4.3.9: psk_key_exchange_modes restricts both the PSKs
|
||||
* offered in the ClientHello and those the server might supply through
|
||||
* NewSessionTicket, and servers should not send tickets that are incompatible
|
||||
* with the advertised modes. RFC 9846 Section 4.7.1 makes sending a ticket
|
||||
* conditional on the client's hello carrying a suitable extension.
|
||||
*
|
||||
* ssl The SSL/TLS object.
|
||||
* returns 0 when a ticket may be sent, MISSING_HANDSHAKE_DATA when the
|
||||
* extension was not received and PSK_KEY_ERROR when none of the
|
||||
* advertised modes is usable.
|
||||
*/
|
||||
static int CheckTls13TicketPskModes(WOLFSSL* ssl)
|
||||
{
|
||||
#ifdef WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES
|
||||
if (!ssl->options.pskKeModesRecvd) {
|
||||
WOLFSSL_MSG("No psk_key_exchange_modes in ClientHello");
|
||||
return MISSING_HANDSHAKE_DATA;
|
||||
}
|
||||
|
||||
if ((ssl->options.pskKeModes & (1 << PSK_KE)) != 0
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
&& !ssl->options.onlyPskDheKe
|
||||
#endif
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
/* The configured policy, not noPskDheKe - a certificate handshake clears
|
||||
* that one before the ticket is sent, which would make this always true. */
|
||||
if ((ssl->options.pskKeModes & (1 << PSK_DHE_KE)) != 0 &&
|
||||
!ssl->options.noPskDheKePolicy) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
WOLFSSL_MSG("No usable psk_key_exchange_modes advertised by client");
|
||||
return PSK_KEY_ERROR;
|
||||
#else
|
||||
(void)ssl;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Send New Session Ticket handshake message.
|
||||
* Message contains the information required to perform resumption.
|
||||
*
|
||||
|
|
@ -14647,6 +14767,12 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (CheckTls13TicketPskModes(ssl) != 0) {
|
||||
WOLFSSL_MSG("Client advertised no usable PSK key exchange mode; "
|
||||
"skipping ticket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_DTLS13
|
||||
if (ssl->options.dtls)
|
||||
idx = Dtls13GetRlHeaderLength(ssl, 1) + DTLS_HANDSHAKE_HEADER_SZ;
|
||||
|
|
@ -17087,6 +17213,7 @@ int wolfSSL_no_dhe_psk(WOLFSSL* ssl)
|
|||
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
ssl->options.noPskDheKe = 1;
|
||||
ssl->options.noPskDheKePolicy = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
@ -18137,17 +18264,29 @@ int wolfSSL_accept_TLSv13(WOLFSSL* ssl)
|
|||
* returns BAD_FUNC_ARG when ssl is NULL, or not using TLS v1.3,
|
||||
* SIDE_ERROR when not a server,
|
||||
* NOT_READY_ERROR when handshake not complete,
|
||||
* MISSING_HANDSHAKE_DATA when the ClientHello had no
|
||||
* psk_key_exchange_modes extension and
|
||||
* WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES is defined,
|
||||
* PSK_KEY_ERROR when no advertised PSK key exchange mode is usable and
|
||||
* WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES is defined,
|
||||
* WOLFSSL_FATAL_ERROR when creating or sending message fails, and
|
||||
* WOLFSSL_SUCCESS on success.
|
||||
*/
|
||||
int wolfSSL_send_SessionTicket(WOLFSSL* ssl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ssl == NULL || !IsAtLeastTLSv1_3(ssl->version))
|
||||
return BAD_FUNC_ARG;
|
||||
if (ssl->options.side == WOLFSSL_CLIENT_END)
|
||||
return SIDE_ERROR;
|
||||
if (ssl->options.handShakeState != HANDSHAKE_DONE)
|
||||
return NOT_READY_ERROR;
|
||||
ret = CheckTls13TicketPskModes(ssl);
|
||||
if (ret != 0) {
|
||||
WOLFSSL_ERROR_VERBOSE(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ssl->error = SendTls13NewSessionTicket(ssl)) != 0) {
|
||||
WOLFSSL_ERROR(ssl->error);
|
||||
|
|
|
|||
|
|
@ -1739,3 +1739,82 @@ int test_wolfSSL_GetSessionAtIndex(void)
|
|||
|
||||
#endif /* SESSION_INDEX && HAVE_SESSION_TICKET && !NO_SESSION_CACHE &&
|
||||
* !NO_WOLFSSL_CLIENT && !NO_TLS */
|
||||
|
||||
/* RFC 9846 Appendix C.4: client applications should not offer tickets across
|
||||
* connections meant to be uncorrelated. wolfSSL_SetServerID() is how an
|
||||
* application keeps such connections apart, so a shorter ID must not match a
|
||||
* cached entry that merely starts with the same bytes. */
|
||||
int test_wolfSSL_client_cache_id_prefix(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_SESSION_CACHE) && !defined(NO_CLIENT_CACHE) && \
|
||||
!defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
WOLFSSL* ssl = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
static const byte prefix[] = { 'w', 'o', 'l', 'f', 'S', 'S', 'L', ':' };
|
||||
byte id[sizeof(prefix) + 4];
|
||||
byte sessId[ID_LEN];
|
||||
word32 i;
|
||||
/* The cache row is picked from a hash of the ID, so the prefix and any
|
||||
* one long ID rarely share a row. Every long ID here starts with the
|
||||
* prefix, and there are enough of them to cover all rows, so the prefix
|
||||
* lookup lands on a row holding one of them. */
|
||||
const word32 fill = 4096;
|
||||
|
||||
/* TLS 1.2 so the client has a complete session to cache as soon as the
|
||||
* handshake is done, with or without session tickets. */
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
ExpectIntEQ(ssl_c->session->isSetup, 1);
|
||||
|
||||
XMEMCPY(id, prefix, sizeof(prefix));
|
||||
XMEMSET(sessId, 0, sizeof(sessId));
|
||||
for (i = 0; i < fill && EXPECT_SUCCESS(); i++) {
|
||||
ClientSession* entry = NULL;
|
||||
|
||||
c32toa(i, id + sizeof(prefix));
|
||||
c32toa(i, sessId);
|
||||
ExpectIntEQ(wolfSSL_SetServerID(ssl_c, id, (int)sizeof(id), 1),
|
||||
WOLFSSL_SUCCESS);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
XMEMCPY(ssl_c->session->sessionID, sessId, ID_LEN);
|
||||
XMEMCPY(ssl_c->session->altSessionID, sessId, ID_LEN);
|
||||
ssl_c->session->sessionIDSz = ID_LEN;
|
||||
}
|
||||
ExpectIntEQ(AddSessionToCache(ctx_c, ssl_c->session, sessId, ID_LEN,
|
||||
NULL, WOLFSSL_CLIENT_END, 0, &entry), 0);
|
||||
ExpectNotNull(entry);
|
||||
}
|
||||
|
||||
/* The prefix is a distinct partition key: no cached session for it. */
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx_c));
|
||||
ExpectIntEQ(ssl->session->isSetup, 0);
|
||||
ExpectIntEQ(wolfSSL_SetServerID(ssl, prefix, (int)sizeof(prefix), 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(ssl->session->isSetup, 0);
|
||||
ExpectIntEQ(ssl->session->idLen, (int)sizeof(prefix));
|
||||
wolfSSL_free(ssl);
|
||||
ssl = NULL;
|
||||
|
||||
/* Control: the ID it was cached under still finds it. */
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx_c));
|
||||
ExpectIntEQ(wolfSSL_SetServerID(ssl, id, (int)sizeof(id), 0),
|
||||
WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(ssl->session->isSetup, 1);
|
||||
wolfSSL_free(ssl);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ int test_wolfSSL_CTX_sess_set_remove_cb(void);
|
|||
int test_wolfSSL_ticket_keys(void);
|
||||
int test_wolfSSL_SESSION_get_ex_new_index(void);
|
||||
int test_wolfSSL_GetSessionAtIndex(void);
|
||||
int test_wolfSSL_client_cache_id_prefix(void);
|
||||
|
||||
#define TEST_SESSION_DECLS \
|
||||
TEST_DECL_GROUP("session", test_wolfSSL_CTX_add_session), \
|
||||
|
|
@ -51,6 +52,7 @@ int test_wolfSSL_GetSessionAtIndex(void);
|
|||
TEST_DECL_GROUP("session", test_wolfSSL_CTX_sess_set_remove_cb), \
|
||||
TEST_DECL_GROUP("session", test_wolfSSL_ticket_keys), \
|
||||
TEST_DECL_GROUP("session", test_wolfSSL_SESSION_get_ex_new_index), \
|
||||
TEST_DECL_GROUP("session", test_wolfSSL_GetSessionAtIndex)
|
||||
TEST_DECL_GROUP("session", test_wolfSSL_GetSessionAtIndex), \
|
||||
TEST_DECL_GROUP("session", test_wolfSSL_client_cache_id_prefix)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_SESSION_H */
|
||||
|
|
|
|||
|
|
@ -2099,7 +2099,8 @@ int test_tls13_fail_if_no_psk_resumption_exempt_from_dhe(void)
|
|||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && !defined(NO_PSK) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
defined(HAVE_SUPPORTED_CURVES) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
defined(HAVE_SUPPORTED_CURVES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
|
||||
!defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
|
||||
(defined(HAVE_ECC) || !defined(NO_RSA))
|
||||
|
|
@ -10619,11 +10620,13 @@ int test_tls13_clear_preserves_psk_dhe(void)
|
|||
ExpectIntEQ(wolfSSL_CTX_no_dhe_psk(ctx), 0);
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
ExpectIntEQ(ssl->options.noPskDheKe, 1);
|
||||
ExpectIntEQ(ssl->options.noPskDheKePolicy, 1);
|
||||
|
||||
/* SSL reuse must preserve the CTX-level noPskDheKe; resetting to 0
|
||||
* would silently re-enable psk_dhe_ke for the next handshake. */
|
||||
ExpectIntEQ(wolfSSL_clear(ssl), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(ssl->options.noPskDheKe, 1);
|
||||
ExpectIntEQ(ssl->options.noPskDheKePolicy, 1);
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
|
|
@ -12662,3 +12665,531 @@ int test_tls13_cryptocb_async(void)
|
|||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
/* Drive a TLS 1.3 handshake up to, but not including, the server's final
|
||||
* wolfSSL_accept() - the call that runs the NewSessionTicket loop. */
|
||||
static int test_tls13_handshake_to_ticket(WOLFSSL* ssl_c, WOLFSSL* ssl_s)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
/* ClientHello. */
|
||||
ExpectIntEQ(wolfSSL_connect(ssl_c), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
|
||||
WOLFSSL_ERROR_WANT_READ);
|
||||
/* Server flight. */
|
||||
ExpectIntEQ(wolfSSL_accept(ssl_s), WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
|
||||
WOLFSSL_ERROR_WANT_READ);
|
||||
/* Client Finished. */
|
||||
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* RFC 9846 Section 4.3.9 and Section 4.7.1: a NewSessionTicket creates a
|
||||
* resumption PSK, so the server may only send one when the ClientHello
|
||||
* advertised a psk_key_exchange_modes mode it can be used with. */
|
||||
int test_tls13_ticket_psk_modes(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
|
||||
/* The wolfSSL client always advertises psk_key_exchange_modes, so drive
|
||||
* the no-extension case by clearing the recorded flag after the
|
||||
* handshake: a ClientHello without the extension gets no ticket. */
|
||||
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(test_tls13_handshake_to_ticket(ssl_c, ssl_s), TEST_SUCCESS);
|
||||
ExpectIntEQ(ssl_s->options.pskKeModesRecvd, 1);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ssl_s->options.pskKeModesRecvd = 0;
|
||||
}
|
||||
ExpectIntEQ(test_ctx.c_len, 0);
|
||||
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_len, 0);
|
||||
|
||||
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;
|
||||
|
||||
/* Control: the wolfSSL client advertises the modes, so a ticket is sent. */
|
||||
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(test_tls13_handshake_to_ticket(ssl_c, ssl_s), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_len, 0);
|
||||
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
|
||||
ExpectIntGT(test_ctx.c_len, 0);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* wolfSSL_send_SessionTicket() applies the same RFC 9846 precondition as the
|
||||
* automatic ticket path, and reports why it will not send. */
|
||||
int test_tls13_send_session_ticket_psk_modes(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
|
||||
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(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s), WOLFSSL_SUCCESS);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* No psk_key_exchange_modes extension in the ClientHello. */
|
||||
ssl_s->options.pskKeModesRecvd = 0;
|
||||
}
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s),
|
||||
WC_NO_ERR_TRACE(MISSING_HANDSHAKE_DATA));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* Extension present but carrying only unrecognized modes. */
|
||||
ssl_s->options.pskKeModesRecvd = 1;
|
||||
ssl_s->options.pskKeModes = 0;
|
||||
}
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s),
|
||||
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* psk_dhe_ke only, but the server refuses (EC)DHE with PSK. Set
|
||||
* through the public API - the handshake clears noPskDheKe, so the
|
||||
* decision has to read the configured policy. */
|
||||
ssl_s->options.pskKeModes = 1 << PSK_DHE_KE;
|
||||
}
|
||||
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s),
|
||||
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ssl_s->options.noPskDheKePolicy = 0;
|
||||
}
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s), WOLFSSL_SUCCESS);
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
if (EXPECT_SUCCESS()) {
|
||||
/* psk_ke only, but the server requires (EC)DHE with PSK. */
|
||||
ssl_s->options.pskKeModes = 1 << PSK_KE;
|
||||
}
|
||||
ExpectIntEQ(wolfSSL_only_dhe_psk(ssl_s), 0);
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s),
|
||||
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ssl_s->options.onlyPskDheKe = 0;
|
||||
}
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s), WOLFSSL_SUCCESS);
|
||||
#endif
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
/* Build a NewSessionTicket handshake message carrying the given extensions
|
||||
* block verbatim. Returns the message length, including the handshake
|
||||
* header, or -1 when it does not fit. */
|
||||
static int test_tls13_make_nst(byte* out, int outSz, const byte* exts,
|
||||
int extsSz)
|
||||
{
|
||||
static const byte body[] = {
|
||||
0x00, 0x00, 0x0e, 0x10, /* ticket_lifetime: 3600 */
|
||||
0x01, 0x02, 0x03, 0x04, /* ticket_age_add */
|
||||
0x01, 0x00, /* ticket_nonce<1> */
|
||||
0x00, 0x04, 0xde, 0xad, 0xbe, 0xef /* ticket<4> */
|
||||
};
|
||||
int len = (int)sizeof(body) + OPAQUE16_LEN + extsSz;
|
||||
|
||||
if (outSz < HANDSHAKE_HEADER_SZ + len)
|
||||
return -1;
|
||||
|
||||
out[0] = session_ticket;
|
||||
out[1] = (byte)(len >> 16);
|
||||
out[2] = (byte)(len >> 8);
|
||||
out[3] = (byte)len;
|
||||
XMEMCPY(out + HANDSHAKE_HEADER_SZ, body, sizeof(body));
|
||||
c16toa((word16)extsSz, out + HANDSHAKE_HEADER_SZ + sizeof(body));
|
||||
if (extsSz > 0) {
|
||||
XMEMCPY(out + HANDSHAKE_HEADER_SZ + sizeof(body) + OPAQUE16_LEN, exts,
|
||||
(size_t)extsSz);
|
||||
}
|
||||
|
||||
return HANDSHAKE_HEADER_SZ + len;
|
||||
}
|
||||
|
||||
/* Encrypt a post-handshake message with the server's keys and hand it to the
|
||||
* client. Returns 0 on success. */
|
||||
static int test_tls13_send_post_hs(struct test_memio_ctx* test_ctx,
|
||||
WOLFSSL* ssl_s, const byte* msg, int msgSz)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
byte rec[256];
|
||||
int recSz;
|
||||
|
||||
recSz = BuildTls13Message(ssl_s, rec, (int)sizeof(rec), msg, msgSz,
|
||||
handshake, 0, 0, 0);
|
||||
ExpectIntGT(recSz, 0);
|
||||
ExpectIntLE(recSz, (int)sizeof(rec));
|
||||
ExpectIntEQ(test_memio_inject_message(test_ctx, 1, (const char*)rec, recSz),
|
||||
0);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* RFC 9846 Section 4.7.1 defines NewSessionTicket.extensions as a list of
|
||||
* Section 4.3 Extension TLVs, and Section 6 requires a decode_error alert for
|
||||
* a message that cannot be parsed. The framing has to be checked whether or
|
||||
* not early data - the only extension wolfSSL acts on there - is compiled in.
|
||||
*/
|
||||
int test_tls13_new_session_ticket_ext_framing(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
/* Well formed extension of an unknown type - must be ignored. */
|
||||
static const byte extOk[] = { 0x12, 0x34, 0x00, 0x02, 0xaa, 0xbb };
|
||||
/* Two unknown types, the second with empty extension_data. */
|
||||
static const byte extTwo[] = { 0x12, 0x34, 0x00, 0x02, 0xaa, 0xbb,
|
||||
0x56, 0x78, 0x00, 0x00 };
|
||||
/* Vector too short to hold an Extension header. */
|
||||
static const byte extShort[] = { 0x00, 0x2a, 0x00 };
|
||||
/* extension_data length runs past the end of the vector. */
|
||||
static const byte extTrunc[] = { 0x12, 0x34, 0x00, 0x04, 0xaa, 0xbb };
|
||||
static const char appData[] = "still talking";
|
||||
struct {
|
||||
const byte* exts;
|
||||
int extsSz;
|
||||
int expectErr;
|
||||
} cases[] = {
|
||||
{ NULL, 0, 0 },
|
||||
{ extOk, (int)sizeof(extOk), 0 },
|
||||
{ extTwo, (int)sizeof(extTwo), 0 },
|
||||
{ extShort, (int)sizeof(extShort), BUFFER_ERROR },
|
||||
{ extTrunc, (int)sizeof(extTrunc), BUFFER_ERROR },
|
||||
};
|
||||
size_t i;
|
||||
char buf[64];
|
||||
|
||||
for (i = 0; i < XELEM_CNT(cases) && EXPECT_SUCCESS(); i++) {
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
WOLFSSL_ALERT_HISTORY h;
|
||||
byte msg[64];
|
||||
int msgSz;
|
||||
|
||||
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(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
|
||||
/* Consume the server's own NewSessionTicket. */
|
||||
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
|
||||
WOLFSSL_ERROR_WANT_READ);
|
||||
|
||||
msgSz = -1;
|
||||
if (EXPECT_SUCCESS()) {
|
||||
msgSz = test_tls13_make_nst(msg, (int)sizeof(msg), cases[i].exts,
|
||||
cases[i].extsSz);
|
||||
}
|
||||
ExpectIntGT(msgSz, 0);
|
||||
ExpectIntEQ(test_tls13_send_post_hs(&test_ctx, ssl_s, msg, msgSz),
|
||||
TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
||||
if (cases[i].expectErr == 0) {
|
||||
/* Accepted: no application data follows the ticket, and the
|
||||
* client raised no alert. */
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
|
||||
WOLFSSL_ERROR_WANT_READ);
|
||||
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(h.last_tx.code, -1);
|
||||
ExpectIntEQ(h.last_tx.level, -1);
|
||||
/* The connection carries on: data still flows both ways. */
|
||||
ExpectIntEQ(wolfSSL_write(ssl_s, appData, (int)sizeof(appData) - 1),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(XMEMCMP(buf, appData, sizeof(appData) - 1), 0);
|
||||
ExpectIntEQ(wolfSSL_write(ssl_c, appData, (int)sizeof(appData) - 1),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(XMEMCMP(buf, appData, sizeof(appData) - 1), 0);
|
||||
}
|
||||
else {
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
|
||||
cases[i].expectErr);
|
||||
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(h.last_tx.code, decode_error);
|
||||
ExpectIntEQ(h.last_tx.level, alert_fatal);
|
||||
}
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
}
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Parsing a NewSessionTicket must not disturb the extended_master_secret
|
||||
* state. TLSX_Parse() clears haveEMS for any non-request message that does
|
||||
* not carry the extension, and wolfSSL_clear() never puts it back, so a
|
||||
* cleared flag would leave a reused object negotiating TLS 1.2 without EMS. */
|
||||
int test_tls13_new_session_ticket_keeps_ems(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_EXTENDED_MASTER) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
byte msg[64];
|
||||
char buf[64];
|
||||
int msgSz;
|
||||
|
||||
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(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
|
||||
/* Consume the server's own NewSessionTicket. */
|
||||
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
|
||||
WOLFSSL_ERROR_WANT_READ);
|
||||
|
||||
if (EXPECT_SUCCESS() && ssl_c != NULL)
|
||||
ssl_c->options.haveEMS = 1;
|
||||
|
||||
/* A ticket with an empty extensions vector. */
|
||||
msgSz = -1;
|
||||
if (EXPECT_SUCCESS())
|
||||
msgSz = test_tls13_make_nst(msg, (int)sizeof(msg), NULL, 0);
|
||||
ExpectIntGT(msgSz, 0);
|
||||
ExpectIntEQ(test_tls13_send_post_hs(&test_ctx, ssl_s, msg, msgSz),
|
||||
TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)),
|
||||
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
|
||||
WOLFSSL_ERROR_WANT_READ);
|
||||
|
||||
if (EXPECT_SUCCESS() && ssl_c != NULL)
|
||||
ExpectIntEQ(ssl_c->options.haveEMS, 1);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* RFC 9846 Section 4.3.11: when the modes the client advertised leave no PSK
|
||||
* the server may use, the PSK is ignored and a certificate handshake runs.
|
||||
* Aborting instead would kill a connection that can still be completed. */
|
||||
int test_tls13_psk_mode_mismatch_falls_back(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
defined(HAVE_SUPPORTED_CURVES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
|
||||
!defined(NO_CERTS) && !defined(NO_FILESYSTEM)
|
||||
int round;
|
||||
|
||||
for (round = 0; round < 2 && EXPECT_SUCCESS(); round++) {
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
WOLFSSL_SESSION* sess = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
WOLFSSL_ALERT_HISTORY h;
|
||||
byte readBuf[16];
|
||||
char buf[32];
|
||||
static const char appData[] = "still talking";
|
||||
|
||||
/* Full handshake with no mode policy, to obtain a ticket. */
|
||||
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);
|
||||
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
/* Drain the NewSessionTicket so the session carries a ticket. */
|
||||
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));
|
||||
wolfSSL_free(ssl_c);
|
||||
ssl_c = NULL;
|
||||
wolfSSL_free(ssl_s);
|
||||
ssl_s = NULL;
|
||||
|
||||
/* Resume into a mode mismatch. */
|
||||
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);
|
||||
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, NULL);
|
||||
if (round == 0) {
|
||||
/* Client offers psk_ke only, server requires psk_dhe_ke. */
|
||||
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
|
||||
ExpectIntEQ(wolfSSL_only_dhe_psk(ssl_s), 0);
|
||||
}
|
||||
else {
|
||||
/* Client offers psk_dhe_ke only, server refuses (EC)DHE. */
|
||||
ExpectIntEQ(wolfSSL_only_dhe_psk(ssl_c), 0);
|
||||
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
|
||||
}
|
||||
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
|
||||
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 20, NULL), 0);
|
||||
/* The PSK was declined, not used, and no alert was raised. */
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_c), 0);
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0);
|
||||
ExpectIntEQ(ssl_s->options.resuming, 0);
|
||||
ExpectIntEQ(wolfSSL_get_alert_history(ssl_s, &h), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(h.last_tx.code, -1);
|
||||
ExpectIntEQ(h.last_tx.level, -1);
|
||||
if (round == 1) {
|
||||
/* The certificate handshake clears noPskDheKe, so the configured
|
||||
* policy has to be kept separately. */
|
||||
ExpectIntEQ(ssl_s->options.noPskDheKePolicy, 1);
|
||||
}
|
||||
/* The connection carries on: data still flows both ways. */
|
||||
ExpectIntEQ(wolfSSL_write(ssl_s, appData, (int)sizeof(appData) - 1),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(XMEMCMP(buf, appData, sizeof(appData) - 1), 0);
|
||||
ExpectIntEQ(wolfSSL_write(ssl_c, appData, (int)sizeof(appData) - 1),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf)),
|
||||
(int)sizeof(appData) - 1);
|
||||
ExpectIntEQ(XMEMCMP(buf, appData, sizeof(appData) - 1), 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();
|
||||
}
|
||||
|
||||
/* The ticket decision must use the configured (EC)DHE policy. A certificate
|
||||
* handshake clears ssl->options.noPskDheKe before the ticket is sent, so
|
||||
* reading that field would make the psk_dhe_ke case always look compatible. */
|
||||
int test_tls13_ticket_psk_modes_uses_policy(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) && \
|
||||
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
defined(HAVE_SUPPORTED_CURVES) && \
|
||||
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES) && \
|
||||
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
|
||||
/* Client advertises psk_dhe_ke only, server is configured to refuse
|
||||
* (EC)DHE with PSK, so no ticket it could issue is usable. */
|
||||
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_only_dhe_psk(ssl_c), 0);
|
||||
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_s), 0);
|
||||
ExpectIntEQ(test_tls13_handshake_to_ticket(ssl_c, ssl_s), TEST_SUCCESS);
|
||||
/* The handshake used a certificate, which clears the negotiated flag. */
|
||||
ExpectIntEQ(ssl_s->options.noPskDheKe, 0);
|
||||
ExpectIntEQ(ssl_s->options.noPskDheKePolicy, 1);
|
||||
ExpectIntEQ(test_ctx.c_len, 0);
|
||||
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_len, 0);
|
||||
ExpectIntEQ(wolfSSL_send_SessionTicket(ssl_s),
|
||||
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
|
||||
|
||||
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;
|
||||
|
||||
/* Control: same client, server with no policy, so a ticket is sent. */
|
||||
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_only_dhe_psk(ssl_c), 0);
|
||||
ExpectIntEQ(test_tls13_handshake_to_ticket(ssl_c, ssl_s), TEST_SUCCESS);
|
||||
ExpectIntEQ(test_ctx.c_len, 0);
|
||||
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS);
|
||||
ExpectIntGT(test_ctx.c_len, 0);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,6 +146,12 @@ int test_tls13_pha_status_request(void);
|
|||
int test_tls13_x25519_keyshare_masks_reserved_bit(void);
|
||||
int test_tls13_is_init_finished_want_write(void);
|
||||
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_send_session_ticket_psk_modes(void);
|
||||
int test_tls13_new_session_ticket_ext_framing(void);
|
||||
int test_tls13_new_session_ticket_keeps_ems(void);
|
||||
|
||||
#define TEST_TLS13_DECLS \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_apis), \
|
||||
|
|
@ -270,6 +276,12 @@ int test_tls13_cryptocb_async(void);
|
|||
TEST_DECL_GROUP("tls13", test_tls13_pha_status_request), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_x25519_keyshare_masks_reserved_bit), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_is_init_finished_want_write), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_cryptocb_async)
|
||||
TEST_DECL_GROUP("tls13", test_tls13_cryptocb_async), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_ticket_psk_modes), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_send_session_ticket_psk_modes), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_new_session_ticket_ext_framing), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_new_session_ticket_keeps_ems), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_psk_mode_mismatch_falls_back), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_ticket_psk_modes_uses_policy)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_TLS13_H */
|
||||
|
|
|
|||
|
|
@ -292,15 +292,13 @@ int test_tls13_feat_psk_ke_no_dhe(void)
|
|||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* The rejecting partner of the vector above, for the
|
||||
*
|
||||
* else if (onlyPskDheKe || (failNoPSK && !resumption))
|
||||
*
|
||||
* arms of CheckPreSharedKeys() and SetupPskKey(): a server that insists on
|
||||
* forward secrecy (wolfSSL_only_dhe_psk) facing a client that offers
|
||||
* psk_ke only. onlyPskDheKe had never been set on a live handshake -- the
|
||||
* group only exercised it through the argument-validation API test. */
|
||||
int test_tls13_feat_psk_only_dhe_rejects_psk_ke(void)
|
||||
/* The declining partner of the vector above, for the onlyPskDheKe arm of
|
||||
* PskModesUsable(): a server that insists on forward secrecy
|
||||
* (wolfSSL_only_dhe_psk) facing a client that offers psk_ke only. No mode is
|
||||
* usable, so the PSK is ignored and a certificate handshake runs instead.
|
||||
* onlyPskDheKe had never been set on a live handshake -- the group only
|
||||
* exercised it through the argument-validation API test. */
|
||||
int test_tls13_feat_psk_only_dhe_ignores_psk_ke(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if !defined(NO_PSK) && defined(HAVE_SUPPORTED_CURVES)
|
||||
|
|
@ -322,9 +320,11 @@ int test_tls13_feat_psk_only_dhe_rejects_psk_ke(void)
|
|||
ExpectIntEQ(wolfSSL_no_dhe_psk(ssl_c), 0);
|
||||
ExpectIntEQ(wolfSSL_only_dhe_psk(ssl_s), 0);
|
||||
|
||||
ExpectIntNE(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_s, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
|
||||
WC_NO_ERR_TRACE(PSK_KEY_ERROR));
|
||||
/* RFC 9846 Section 4.3.11: no advertised mode is usable, so the server
|
||||
* ignores the PSK and runs a certificate handshake instead of aborting. */
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
ExpectIntEQ(ssl_c->options.pskNegotiated, 0);
|
||||
ExpectIntEQ(ssl_s->options.pskNegotiated, 0);
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
|
|
@ -1183,7 +1183,7 @@ int test_tls13_feat_psk_ke_no_dhe(void)
|
|||
{
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
int test_tls13_feat_psk_only_dhe_rejects_psk_ke(void)
|
||||
int test_tls13_feat_psk_only_dhe_ignores_psk_ke(void)
|
||||
{
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
int test_tls13_feat_optional_client_cert(void);
|
||||
int test_tls13_feat_post_handshake_unexpected_msg(void);
|
||||
int test_tls13_feat_psk_ke_no_dhe(void);
|
||||
int test_tls13_feat_psk_only_dhe_rejects_psk_ke(void);
|
||||
int test_tls13_feat_psk_only_dhe_ignores_psk_ke(void);
|
||||
int test_tls13_feat_no_ticket_enc_cb(void);
|
||||
int test_tls13_feat_psk_ke_empty_key_share(void);
|
||||
int test_tls13_feat_optional_psk_falls_back_to_cert(void);
|
||||
|
|
@ -48,7 +48,7 @@ int test_tls13_feat_ech_psk_disabled_client(void);
|
|||
TEST_DECL_GROUP("tls13", test_tls13_feat_optional_client_cert), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_feat_post_handshake_unexpected_msg), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_feat_psk_ke_no_dhe), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_feat_psk_only_dhe_rejects_psk_ke), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_feat_psk_only_dhe_ignores_psk_ke), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_feat_no_ticket_enc_cb), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_feat_psk_ke_empty_key_share), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_feat_optional_psk_falls_back_to_cert), \
|
||||
|
|
|
|||
|
|
@ -290,3 +290,15 @@
|
|||
-u
|
||||
-v 4
|
||||
-l TLS13-SHA384-SHA384
|
||||
|
||||
# server DTLSv1.3 no (EC)DHE with PSK, must still key share in the HRR
|
||||
-u
|
||||
-v 4
|
||||
-l TLS13-AES128-GCM-SHA256
|
||||
-K
|
||||
|
||||
# client DTLSv1.3 HelloRetryRequest against a no-(EC)DHE-with-PSK server
|
||||
-u
|
||||
-v 4
|
||||
-l TLS13-AES128-GCM-SHA256
|
||||
-J
|
||||
|
|
|
|||
|
|
@ -5457,6 +5457,10 @@ struct Options {
|
|||
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_TLS13)
|
||||
unsigned int maxTicketTls13; /* maximum number of tickets to send */
|
||||
unsigned int ticketsSent; /* keep track of the total sent */
|
||||
#if !defined(NO_WOLFSSL_SERVER) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES)
|
||||
byte pskKeModes; /* modes client advertised in CH */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* on/off or small bit flags, optimize layout */
|
||||
|
|
@ -5509,6 +5513,11 @@ struct Options {
|
|||
word16 usingAnon_cipher:1; /* are we using an anon cipher */
|
||||
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
|
||||
word16 noPskDheKe:1; /* Don't use (EC)DHE with PSK */
|
||||
/* noPskDheKe doubles as negotiated state - it is set when psk_ke is chosen
|
||||
* and cleared on every certificate handshake. Decisions that must follow
|
||||
* what the application configured use this copy, which is only written by
|
||||
* the configuration APIs. */
|
||||
word16 noPskDheKePolicy:1; /* Configured no (EC)DHE with PSK */
|
||||
#ifdef HAVE_SUPPORTED_CURVES
|
||||
word16 onlyPskDheKe:1; /* Only use (EC)DHE with PSK */
|
||||
#endif
|
||||
|
|
@ -5539,6 +5548,10 @@ struct Options {
|
|||
#ifdef WOLFSSL_EARLY_DATA
|
||||
word16 ticketPredatesCtx:1; /* PSK ticket minted before ctx */
|
||||
#endif
|
||||
#if !defined(NO_WOLFSSL_SERVER) && \
|
||||
defined(WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES)
|
||||
word16 pskKeModesRecvd:1; /* CH had psk_key_exchange_modes */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WOLFSSL_DTLS
|
||||
|
|
|
|||
Loading…
Reference in New Issue