Merge pull request #10594 from kareem-wolfssl/zd21873

Fix a few TLS compliance issues
master
JacobBarthelmeh 2026-09-17 16:39:10 -06:00 committed by GitHub
commit 31b9da2c8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 411 additions and 74 deletions

View File

@ -93,6 +93,10 @@
{"name": "dtls13-ocspstapling-cert-cb", "minutes": 3.1,
"configure": ["--enable-dtls", "--enable-dtls13", "--enable-ocspstapling",
"--enable-ocspstapling2", "--enable-cert-setup-cb", "--enable-sessioncerts"]},
{"name": "nullcipher-tls13-in-default", "minutes": 3.0,
"comment": "Legacy WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT mode: RFC 9150 integrity-only suites back in the default TLS 1.3/DTLS 1.3 cipher list. The only config that runs tests/test-tls13-null.conf and tests/test-dtls13-null.conf (they need the suites in the default list). The dtls-cid-renego-psk entry covers the default-exclusion mode of --enable-nullcipher.",
"configure": ["--enable-dtls", "--enable-dtls13", "--enable-nullcipher",
"CPPFLAGS=-DWOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT -DWOLFSSL_STATIC_RSA"]},
{"name": "tsp-verifier", "minutes": 3,
"comment": "Time-Stamp Protocol Verifier",
"configure": ["--enable-tsp", "--enable-opensslall",

View File

@ -1177,6 +1177,7 @@ WOLFSSL_TI_CURRTIME
WOLFSSL_TLS13_DRAFT
WOLFSSL_TLS13_IGNORE_AEAD_LIMITS
WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT
WOLFSSL_TLS13_SHA512
WOLFSSL_TLS13_TICKET_CHECK_PSK_MODES
WOLFSSL_TLS13_TICKET_BEFORE_FINISHED

View File

@ -97,6 +97,8 @@
* WOLFSSL_TICKET_ENC_CBC_HMAC:
* CBC+HMAC for ticket encryption (non-AEAD) default: off
* WOLFSSL_NO_TICKET_EXPIRE: Disable ticket expiration checking default: off
* (server-side resumption and the client-side check
* on a stored ticket before offering it)
*
* TLS 1.3 Internals:
* WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC:
@ -106,6 +108,9 @@
* WOLFSSL_TLS13_IGNORE_AEAD_LIMITS:
* Ignore AEAD message limits from RFC 9846 5.5, which
* makes observing them a MUST default: off
* WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT:
* Include RFC 9150 integrity-only suites in the
* default cipher suite list (HAVE_NULL_CIPHER) default: off
* WOLFSSL_DTLS13_SEND_MOREACK_DEFAULT:
* Send more ACKs by default in DTLS 1.3 default: off
*
@ -4054,19 +4059,35 @@ static word16 InitSuites_Tls13(Suites* suites, word16 idx, int tls1_3,
#endif
#ifdef HAVE_NULL_CIPHER
/* RFC 9150 integrity-only (zero-confidentiality) TLS 1.3 suites.
* These provide authentication and integrity but no confidentiality, so
* they are NOT advertised in the default cipher preference list. A caller
* that genuinely needs them (e.g. constrained/IoT deployments) must opt in
* explicitly with a cipher list, either by suite name:
* wolfSSL_set_cipher_list(ssl, "TLS13-SHA256-SHA256");
* or with the "eNULL" keyword. Define
* WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT to restore the legacy behaviour of
* including them in the default list. */
#ifndef WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT
if (haveNull == SUITES_NULL_EXPLICIT)
#else
if (haveNull)
#endif
{
#ifdef BUILD_TLS_SHA256_SHA256
if (tls1_3 && haveNull) {
if (tls1_3) {
suites->suites[idx++] = ECC_BYTE;
suites->suites[idx++] = TLS_SHA256_SHA256;
}
#endif
#ifdef BUILD_TLS_SHA384_SHA384
if (tls1_3 && haveNull) {
if (tls1_3) {
suites->suites[idx++] = ECC_BYTE;
suites->suites[idx++] = TLS_SHA384_SHA384;
}
#endif
}
#endif
return idx;
@ -27626,32 +27647,38 @@ int SendFinished(WOLFSSL* ssl)
AddSession(ssl);
#endif
if (ssl->options.side == WOLFSSL_SERVER_END) {
/* Mark the handshake done before the info callback so the
* callback (e.g. on WOLFSSL_CB_HANDSHAKE_DONE) can use APIs that
* require a completed handshake, such as
* wolfSSL_export_keying_material(). */
ssl->options.handShakeState = HANDSHAKE_DONE;
ssl->options.handShakeDone = 1;
#ifdef HAVE_SECURE_RENEGOTIATION
ssl->options.resumed = ssl->options.resuming;
#endif
#ifdef OPENSSL_EXTRA
ssl->options.serverState = SERVER_FINISHED_COMPLETE;
ssl->cbmode = WOLFSSL_CB_MODE_WRITE;
if (ssl->CBIS != NULL)
ssl->CBIS(ssl, WOLFSSL_CB_HANDSHAKE_DONE, WOLFSSL_SUCCESS);
#endif
}
}
else {
if (ssl->options.side == WOLFSSL_CLIENT_END) {
/* Same ordering as the server side above: flags first so the
* info callback sees a completed handshake. */
ssl->options.handShakeState = HANDSHAKE_DONE;
ssl->options.handShakeDone = 1;
#ifdef HAVE_SECURE_RENEGOTIATION
ssl->options.resumed = ssl->options.resuming;
#endif
}
}
else {
if (ssl->options.side == WOLFSSL_CLIENT_END) {
#ifdef OPENSSL_EXTRA
ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
ssl->cbmode = WOLFSSL_CB_MODE_WRITE;
if (ssl->CBIS != NULL)
ssl->CBIS(ssl, WOLFSSL_CB_HANDSHAKE_DONE, WOLFSSL_SUCCESS);
#endif
ssl->options.handShakeState = HANDSHAKE_DONE;
ssl->options.handShakeDone = 1;
#ifdef HAVE_SECURE_RENEGOTIATION
ssl->options.resumed = ssl->options.resuming;
#endif
}
}
@ -32161,7 +32188,7 @@ static int ParseCipherList(Suites* suites,
}
if (XSTRCMP(name, "eNULL") == 0 || XSTRCMP(name, "NULL") == 0) {
haveNull = allowing;
haveNull = allowing ? SUITES_NULL_EXPLICIT : 0;
/* Track exclusion (sticky) so an explicit NULL-cipher suite is
* dropped at the end regardless of "!eNULL"/"!NULL" position; a
* later allowing "eNULL" does not undo it. */
@ -34612,16 +34639,45 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
if (ssl->options.resuming && ssl->session->ticketLen > 0) {
SessionTicket* ticket;
ticket = TLSX_SessionTicket_Create(0, ssl->session->ticket,
ssl->session->ticketLen, ssl->heap);
if (ticket == NULL) return MEMORY_E;
ret = TLSX_UseSessionTicket(&ssl->extensions, ticket, ssl->heap);
if (ret != WOLFSSL_SUCCESS) {
TLSX_SessionTicket_Free(ticket, ssl->heap);
return ret;
#if !defined(WOLFSSL_NO_TICKET_EXPIRE) && !defined(NO_ASN_TIME)
/* RFC 5077 Section 3.3 / RFC 8446 Section 4.6.1: a client SHOULD
* NOT use a ticket whose lifetime has expired. Drop the expired
* ticket and fall back to a full handshake. Skip the check when
* bornOn or timeout is 0 (unknown lifetime) or a secret callback
* is set (session is managed externally, e.g. hostap). */
if (ssl->session->bornOn != 0 && ssl->session->timeout != 0 &&
#ifdef HAVE_SECRET_CALLBACK
ssl->sessionSecretCb == NULL &&
#endif
(LowResTimer() - ssl->session->bornOn) >=
ssl->session->timeout) {
WOLFSSL_MSG("Stored session ticket expired; full handshake");
ssl->options.resuming = 0;
/* The stale ticket stays on the session object, which may be
* shared with the application; the replacement ticket from
* the full handshake overwrites it in SetTicket(). */
/* Send an empty SessionTicket extension (NULL ticket) so the
* client still requests a new ticket from the server without
* sending the stale one. */
ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
if (ret != WOLFSSL_SUCCESS)
return ret;
}
else
#endif
{
ticket = TLSX_SessionTicket_Create(0, ssl->session->ticket,
ssl->session->ticketLen,
ssl->heap);
if (ticket == NULL) return MEMORY_E;
ret = TLSX_UseSessionTicket(&ssl->extensions, ticket,
ssl->heap);
if (ret != WOLFSSL_SUCCESS) {
TLSX_SessionTicket_Free(ticket, ssl->heap);
return ret;
}
}
idSz = 0;
}
#endif /* HAVE_SESSION_TICKET */
@ -41384,9 +41440,10 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
* Handles session resumption.
* Session tickets are checked for validity based on the time each ticket
* was created, timeout value and the current time. If the tickets are
* judged expired, falls back to full-handshake. If you want disable this
* session ticket validation check in TLS1.2 and below, define
* WOLFSSL_NO_TICKET_EXPIRE.
* judged expired, falls back to full-handshake. If you want disable
* this session ticket validation check in TLS1.2 and below (both here
* and the client-side check on a stored ticket in SendClientHello),
* define WOLFSSL_NO_TICKET_EXPIRE.
*/
int HandleTlsResumption(WOLFSSL* ssl, Suites* clSuites)
{

View File

@ -3357,6 +3357,16 @@ int wolfSSL_export_keying_material(WOLFSSL *ssl,
return WOLFSSL_FAILURE;
}
/* RFC 8446 Section 7.5 / RFC 5705: keying-material exporters derive from
* exporter_master_secret, which exists only after the handshake is
* complete. Refuse the export until the handshake has completed so that
* a premature call cannot derive material from an uninitialised
* exporterSecret buffer. */
if (ssl->options.handShakeDone == 0) {
WOLFSSL_MSG("Handshake not complete; refusing keying-material export");
return WOLFSSL_FAILURE;
}
/* Sanity check contextLen to prevent integer overflow when cast to word32
* and to ensure it fits in the 2-byte length encoding (max 65535). */
if (use_context && contextLen > WOLFSSL_MAX_16BIT) {
@ -7587,9 +7597,12 @@ long wolfSSL_set_options(WOLFSSL* ssl, long op)
* options limit the allowed ciphers so let's try to get as many as
* possible.
* - haveStaticECC turns off haveRSA
* - haveECDSAsig turns off haveRSAsig */
* - haveECDSAsig turns off haveRSAsig
* - SUITES_NULL_EXPLICIT includes the integrity-only suites, so
* an explicitly configured one is preserved */
InitSuites(&tmpSuites, ssl->version, 0, 1, 1, 1, haveECDSAsig, 1, 1,
haveStaticECC, 1, 1, 1, 1, 1, ssl->options.side);
haveStaticECC, 1, SUITES_NULL_EXPLICIT, 1, 1, 1,
ssl->options.side);
for (in = 0, out = 0; in < ssl->suites->suiteSz; in += SUITE_LEN) {
if (FindSuite(&tmpSuites, ssl->suites->suites[in],
ssl->suites->suites[in+1]) >= 0) {

View File

@ -69,6 +69,11 @@
* WOLFSSL_CHECK_SIG_FAULTS: Verify signature after ECC signing default: off
* to detect fault injection attacks
* WOLFSSL_CIPHER_TEXT_CHECK: Verify ciphertext integrity default: off
* WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT: Include RFC 9150 suites default: off
* in the default cipher suite list (requires
* HAVE_NULL_CIPHER). Without it the integrity-only
* suites must be requested explicitly in the
* cipher list, by name or with "eNULL".
*
* TLS 1.3 PSK:
* WOLFSSL_PSK_ONE_ID: Single PSK identity per connect default: off

View File

@ -2667,16 +2667,20 @@ static int test_wolfSSL_set_cipher_list_tls13_with_version(void)
#endif
#endif
#if defined(TEST_CIPHER_EXCLUDE_ANON) || defined(TEST_CIPHER_EXCLUDE_NULL)
/* Does the parsed suite list on ssl contain the given suite bytes? */
static int test_suites_contains(WOLFSSL* ssl, byte s0, byte s1)
#if defined(TEST_CIPHER_EXCLUDE_ANON) || defined(TEST_CIPHER_EXCLUDE_NULL) || \
defined(BUILD_TLS_SHA256_SHA256)
/* Does the parsed suite list on ssl contain the given suite bytes?
* WC_MAYBE_UNUSED: the TLS 1.3 null-cipher tests gate further inside their
* bodies, so some builds compile this helper without a caller. */
static WC_MAYBE_UNUSED int test_suites_contains(WOLFSSL* ssl, byte s0, byte s1)
{
int i;
if (ssl == NULL || ssl->suites == NULL)
const Suites* suites = (ssl != NULL) ? WOLFSSL_SUITES(ssl) : NULL;
if (suites == NULL)
return 0;
for (i = 0; (i + 1) < ssl->suites->suiteSz; i += 2) {
if ((ssl->suites->suites[i] == s0) &&
(ssl->suites->suites[i + 1] == s1))
for (i = 0; (i + 1) < suites->suiteSz; i += 2) {
if ((suites->suites[i] == s0) &&
(suites->suites[i + 1] == s1))
return 1;
}
return 0;
@ -2826,10 +2830,11 @@ static int test_wolfSSL_set_cipher_list_exclusions(void)
wolfSSL_free(ssl);
ssl = NULL;
/* OpenSSL compat: "ALL" is "all but eNULL" - it does not generate NULL
* suites, but it is not a delete directive, so a following "eNULL"
* re-enables them. (The earlier sticky excludeNull-for-ALL wrongly kept
* them disabled; only "!eNULL"/"DEFAULT" should.) */
/* The RFC 9150 integrity-only TLS 1.3 suites are zero-confidentiality:
* they are kept out of the default preference list (unless
* WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT is defined) and are never produced
* by "ALL" alone, but an explicit "eNULL" keyword or suite name requests
* them in either mode. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ALL"), WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
@ -2840,7 +2845,15 @@ static int test_wolfSSL_set_cipher_list_exclusions(void)
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ALL:eNULL"), WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_SHA256_SHA256), 1); /* "eNULL" after "ALL" re-enables NULL */
TLS_SHA256_SHA256), 1); /* explicit "eNULL" requests them */
wolfSSL_free(ssl);
ssl = NULL;
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-SHA256-SHA256"),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_SHA256_SHA256), 1); /* explicit suite name works too */
wolfSSL_free(ssl);
ssl = NULL;
#endif /* BUILD_TLS_SHA256_SHA256 */
@ -2858,6 +2871,77 @@ static int test_wolfSSL_set_cipher_list_exclusions(void)
#undef TEST_CIPHER_EXCLUDE_NULL
#endif
/* A client using the default cipher list must not offer the RFC 9150
* integrity-only TLS 1.3 suites unless WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT
* is defined. The server accepts only TLS13-SHA256-SHA256, so the handshake
* outcome shows whether the default list contained it. */
static int test_tls13_null_cipher_default_list(void)
{
EXPECT_DECLS;
#if defined(BUILD_TLS_SHA256_SHA256) && !defined(NO_RSA) && \
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
/* Client keeps the default cipher list. */
test_ctx.s_ciphers = "TLS13-SHA256-SHA256";
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
#ifdef WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(ssl_c->options.cipherSuite0, ECC_BYTE);
ExpectIntEQ(ssl_c->options.cipherSuite, TLS_SHA256_SHA256);
#else
/* no common suite: the server rejects the ClientHello */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), -1);
ExpectIntEQ(ssl_s->error, WC_NO_ERR_TRACE(MATCH_SUITE_ERROR));
#endif
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
/* An explicitly configured integrity-only suite must survive
* wolfSSL_[CTX_]set_options() and wolfSSL_new(): the preserve-overlap
* rebuild in wolfSSL_set_options() must keep explicitly requested NULL
* suites even though they are not in the default list. */
static int test_tls13_null_cipher_explicit_keep(void)
{
EXPECT_DECLS;
#if defined(BUILD_TLS_SHA256_SHA256) && defined(OPENSSL_EXTRA) && \
!defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
/* ctx-level cipher list set before ctx-level options */
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectIntEQ(wolfSSL_CTX_set_cipher_list(ctx, "TLS13-SHA256-SHA256"),
WOLFSSL_SUCCESS);
wolfSSL_CTX_set_options(ctx, WOLFSSL_OP_NO_SSLv3);
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE, TLS_SHA256_SHA256), 1);
wolfSSL_free(ssl);
ssl = NULL;
/* ssl-level options after an explicit ssl-level cipher list */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "TLS13-SHA256-SHA256"),
WOLFSSL_SUCCESS);
wolfSSL_set_options(ssl, WOLFSSL_OP_NO_SSLv3);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE, TLS_SHA256_SHA256), 1);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
static int test_wolfSSL_set_alpn_protos_default_fails(void)
{
EXPECT_DECLS;
@ -31466,6 +31550,18 @@ static int test_export_keying_material_cb(WOLFSSL_CTX *ctx, WOLFSSL *ssl)
/* Use some random context */
ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
"Test label", XSTR_SIZEOF("Test label"), ekm, 10, 1), 1);
/* The handshake-complete gate must be the deciding factor: clearing
* handShakeDone on this otherwise fully established connection flips an
* identical call from success to failure, and restoring it flips it
* back. */
ssl->options.handShakeDone = 0;
ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
"Test label", XSTR_SIZEOF("Test label"), NULL, 0, 1),
WOLFSSL_FAILURE);
ssl->options.handShakeDone = 1;
ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
"Test label", XSTR_SIZEOF("Test label"), NULL, 0, 1),
WOLFSSL_SUCCESS);
/* Failure cases */
ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
"client finished", XSTR_SIZEOF("client finished"), NULL, 0, 0), 0);
@ -31489,8 +31585,15 @@ static int test_export_keying_material_cb(WOLFSSL_CTX *ctx, WOLFSSL *ssl)
static int test_export_keying_material_ssl_cb(WOLFSSL* ssl)
{
EXPECT_DECLS;
byte ekm[32] = {0};
wolfSSL_KeepArrays(ssl);
return TEST_SUCCESS;
/* Export must be refused until the handshake has completed. */
ExpectIntEQ(wolfSSL_export_keying_material(ssl, ekm, sizeof(ekm),
"Test label", XSTR_SIZEOF("Test label"), NULL, 0, 1),
WOLFSSL_FAILURE);
return EXPECT_RESULT();
}
static int test_export_keying_material(void)
@ -31508,6 +31611,54 @@ static int test_export_keying_material(void)
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_TLS12)
static int test_ekm_info_cb_result = -1;
static void test_ekm_info_cb(const WOLFSSL* ssl, int type, int val)
{
byte ekm[32];
(void)val;
if (type == WOLFSSL_CB_HANDSHAKE_DONE) {
test_ekm_info_cb_result = wolfSSL_export_keying_material(
(WOLFSSL*)ssl, ekm, sizeof(ekm),
"Test label", XSTR_SIZEOF("Test label"), NULL, 0, 1);
}
}
static int test_ekm_info_ctx_ready(WOLFSSL_CTX* ctx)
{
wolfSSL_CTX_set_info_callback(ctx, test_ekm_info_cb);
return TEST_SUCCESS;
}
#endif /* OPENSSL_EXTRA && !WOLFSSL_NO_TLS12 */
/* wolfSSL_export_keying_material() must work from inside the
* WOLFSSL_CB_HANDSHAKE_DONE info callback: the handshake-done flags are set
* before the callback fires (TLS 1.2 SendFinished, server side here). */
static int test_export_keying_material_info_cb(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_TLS12)
test_ssl_cbf serverCb;
test_ssl_cbf clientCb;
XMEMSET(&serverCb, 0, sizeof(serverCb));
XMEMSET(&clientCb, 0, sizeof(clientCb));
clientCb.method = wolfTLSv1_2_client_method;
serverCb.method = wolfTLSv1_2_server_method;
serverCb.ctx_ready = test_ekm_info_ctx_ready;
/* exporter needs the handshake arrays kept on the exporting side */
serverCb.ssl_ready = test_export_keying_material_ssl_cb;
test_ekm_info_cb_result = -1;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&clientCb,
&serverCb, NULL), TEST_SUCCESS);
/* The callback fired and the export succeeded. */
ExpectIntEQ(test_ekm_info_cb_result, WOLFSSL_SUCCESS);
#endif
return EXPECT_RESULT();
}
#endif /* HAVE_KEYING_MATERIAL */
static int test_wolfSSL_THREADID_hash(void)
@ -35669,6 +35820,67 @@ static int test_ticket_ret_create(void)
}
#endif
/* RFC 5077 Section 3.3: a stored ticket whose lifetime has expired must not
* be offered; the client falls back to a full handshake. */
static int test_ticket_expired_full_handshake(void)
{
EXPECT_DECLS;
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_TLS12) && \
!defined(WOLFSSL_NO_TICKET_EXPIRE) && !defined(NO_ASN_TIME) && \
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && !defined(NO_RSA) && \
defined(HAVE_ECC) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)
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_SESSION *sess = NULL;
int i;
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);
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_NONE, 0);
wolfSSL_set_verify(ssl_c, WOLFSSL_VERIFY_NONE, 0);
ExpectIntEQ(wolfSSL_CTX_UseSessionTicket(ctx_c), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
/* Round 0: control, the ticket resumes as-is. Round 1: same ticket made
* to look expired; the client must do a full handshake instead. */
for (i = 0; i < 2; i++) {
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
if (i == 1 && ssl_c != NULL) {
ssl_c->session->bornOn -= ssl_c->session->timeout + 1;
}
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
if (ssl_c != NULL) {
ExpectIntEQ(ssl_c->options.resuming, i == 0 ? 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();
}
/* Build a valid TLS 1.2 ticket by completing an initial handshake, then tamper
* with enc_len so it is larger than the true encrypted payload. */
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_TLS12) && \
@ -42139,6 +42351,8 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_set_cipher_list_tls12_with_version),
TEST_DECL(test_wolfSSL_set_cipher_list_tls13_with_version),
TEST_DECL(test_wolfSSL_set_cipher_list_exclusions),
TEST_DECL(test_tls13_null_cipher_default_list),
TEST_DECL(test_tls13_null_cipher_explicit_keep),
TEST_DECL(test_wolfSSL_set_alpn_protos_default_fails),
TEST_DECL(test_wolfSSL_CTX_use_certificate),
TEST_DECL(test_wolfSSL_CTX_use_certificate_file),
@ -42388,6 +42602,7 @@ TEST_CASE testCases[] = {
#if defined(HAVE_KEYING_MATERIAL) && defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES)
TEST_DECL(test_export_keying_material),
TEST_DECL(test_export_keying_material_info_cb),
#endif
/* Can't memory test as client/server Asserts in thread. */
@ -42438,6 +42653,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_ticket_nonce_malloc),
#endif
TEST_DECL(test_ticket_ret_create),
TEST_DECL(test_ticket_expired_full_handshake),
TEST_DECL(test_ticket_enc_corrupted),
TEST_DECL(test_wrong_cs_downgrade),
TEST_DECL(test_tls13_no_ext_sh_alert),

View File

@ -37,6 +37,7 @@ EXTRA_DIST += tests/unit.h \
tests/test-tls13.conf \
tests/test-tls13-down.conf \
tests/test-tls13-ecc.conf \
tests/test-tls13-null.conf \
tests/test-tls13-psk.conf \
tests/test-tls13-pq-standalone.conf \
tests/test-tls13-pq-hybrid.conf \
@ -71,6 +72,7 @@ EXTRA_DIST += tests/unit.h \
tests/test-dtls-srtp.conf \
tests/test-dtls-srtp-fails.conf \
tests/test-dtls13.conf \
tests/test-dtls13-null.conf \
tests/test-dtls13-downgrade.conf \
tests/test-dtls13-downgrade-fails.conf \
tests/test-dtls13-psk.conf \

View File

@ -1180,6 +1180,20 @@ int SuiteTest(int argc, char** argv)
goto exit;
}
#endif
#if defined(HAVE_NULL_CIPHER) && \
defined(WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT)
/* add TLSv13 integrity-only suites; the harness repeats each case with
* the default cipher list on one side, so these can only pass when the
* default list includes the integrity-only suites */
XSTRLCPY(argv0[1], "tests/test-tls13-null.conf", sizeof(argv0[1]));
printf("starting TLSv13 integrity-only cipher suite tests\n");
test_harness(&args);
if (args.return_code != 0) {
printf("error from script %d\n", args.return_code);
args.return_code = EXIT_FAILURE;
goto exit;
}
#endif
#ifndef WOLFSSL_NO_TLS12
/* add TLSv13 downgrade tests */
XSTRLCPY(argv0[1], "tests/test-tls13-down.conf", sizeof(argv0[1]));
@ -1651,6 +1665,19 @@ int SuiteTest(int argc, char** argv)
goto exit;
}
#if defined(HAVE_NULL_CIPHER) && \
defined(WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT)
/* see the test-tls13-null.conf note on the default-cipher-list repeat */
XSTRLCPY(argv0[1], "tests/test-dtls13-null.conf", sizeof(argv0[1]));
printf("starting DTLSv1.3 integrity-only cipher suite tests\n");
test_harness(&args);
if (args.return_code != 0) {
printf("error from script %d\n", args.return_code);
args.return_code = EXIT_FAILURE;
goto exit;
}
#endif /* HAVE_NULL_CIPHER && WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT */
#ifndef WOLFSSL_NO_TLS12
args.argc = 2;
strcpy(argv0[1], "tests/test-dtls13-downgrade.conf");

View File

@ -0,0 +1,24 @@
# DTLSv1.3 RFC 9150 integrity-only suites. Run only in HAVE_NULL_CIPHER builds
# that also define WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT: the harness repeats
# each case with the default cipher list on one side, which can only negotiate
# these suites when they are in the default list.
# server DTLSv1.3 Integrity-only SHA256
-u
-v 4
-l TLS13-SHA256-SHA256
# client DTLSv1.3 Integrity-only SHA256
-u
-v 4
-l TLS13-SHA256-SHA256
# server DTLSv1.3 Integrity-only SHA384
-u
-v 4
-l TLS13-SHA384-SHA384
# client DTLSv1.3 Integrity-only SHA384
-u
-v 4
-l TLS13-SHA384-SHA384

View File

@ -271,26 +271,6 @@
-v 4
-l TLS_AES_128_GCM_SHA256
# server DTLSv1.3 Integrity-only SHA256
-u
-v 4
-l TLS13-SHA256-SHA256
# client DTLSv1.3 Integrity-only SHA256
-u
-v 4
-l TLS13-SHA256-SHA256
# server DTSv1.3 Integrity-only SHA384
-u
-v 4
-l TLS13-SHA384-SHA384
# client DTLSv1.3 Integrity-only SHA384
-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

View File

@ -0,0 +1,20 @@
# TLSv1.3 RFC 9150 integrity-only suites. Run only in HAVE_NULL_CIPHER builds
# that also define WOLFSSL_TLS13_NULL_CIPHER_IN_DEFAULT: the harness repeats
# each case with the default cipher list on one side, which can only negotiate
# these suites when they are in the default list.
# server TLSv1.3 Integrity-only SHA256
-v 4
-l TLS13-SHA256-SHA256
# client TLSv1.3 Integrity-only SHA256
-v 4
-l TLS13-SHA256-SHA256
# server TLSv1.3 Integrity-only SHA384
-v 4
-l TLS13-SHA384-SHA384
# client TLSv1.3 Integrity-only SHA384
-v 4
-l TLS13-SHA384-SHA384

View File

@ -213,19 +213,3 @@
# client TLSv1.3 Send Ticket explicitly
-v 4
-l TLS13-AES128-GCM-SHA256
# server TLSv1.3 Integrity-only SHA256
-v 4
-l TLS13-SHA256-SHA256
# client TLSv1.3 Integrity-only SHA256
-v 4
-l TLS13-SHA256-SHA256
# server TLSv1.3 Integrity-only SHA384
-v 4
-l TLS13-SHA384-SHA384
# client TLSv1.3 Integrity-only SHA384
-v 4
-l TLS13-SHA384-SHA384

View File

@ -1940,6 +1940,10 @@ WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group);
/* 150 suites for now! */
#endif
/* InitSuites() haveNull value used when NULL suites are requested explicitly
* (cipher list "eNULL" keyword) rather than merely allowed by default (1). */
#define SUITES_NULL_EXPLICIT 2
/* number of items in the signature algo list */
#ifndef WOLFSSL_MAX_SIGALGO
#if (defined(WOLFSSL_LEANPSK) || defined(WOLFSSL_LEANTLS)) && \