From 7861ab443cb4f56e7b22007c84b11635a6b90ebb Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 18 Aug 2026 12:13:03 -0700 Subject: [PATCH 1/2] Rework post-handshake checks for resumed connections. --- src/tls13.c | 55 +++++++----- tests/api/test_tls13.c | 189 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_tls13.h | 4 + 3 files changed, 226 insertions(+), 22 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 193bbd3916..76a9b44425 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -12725,6 +12725,16 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, * HAVE_FALCON || WOLFSSL_HAVE_MLDSA || WOLFSSL_HAVE_SLHDSA */ #endif /* !NO_CERTS */ +#ifdef WOLFSSL_POST_HANDSHAKE_AUTH +/* The message being processed belongs to a post-handshake exchange rather than + * to the enclosing handshake. Whatever resumption, PSK or deferred + * (post-handshake) verification excused during that handshake, a later + * post-handshake exchange has to stand on its own. */ +#define TLS13_POST_HANDSHAKE(ssl) ((ssl)->options.handShakeDone) +#else +#define TLS13_POST_HANDSHAKE(ssl) 0 +#endif + /* Parse and handle a TLS v1.3 Finished message. * * ssl The SSL/TLS object. @@ -12749,10 +12759,11 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) /* verify the client sent certificate if required */ - if (ssl->options.side == WOLFSSL_SERVER_END && !ssl->options.resuming && + if (ssl->options.side == WOLFSSL_SERVER_END && + (!ssl->options.resuming || TLS13_POST_HANDSHAKE(ssl)) && (ssl->options.mutualAuth || ssl->options.failNoCert)) { #ifdef OPENSSL_COMPATIBLE_DEFAULTS - if (ssl->options.isPSK) { + if (ssl->options.isPSK && !TLS13_POST_HANDSHAKE(ssl)) { WOLFSSL_MSG("TLS v1.3 client used PSK but cert required. Allowing " "for OpenSSL compatibility"); } @@ -12760,10 +12771,10 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #endif if ( #ifdef WOLFSSL_POST_HANDSHAKE_AUTH - /* Exempt only the initial handshake; a pending post-handshake - * CertificateRequest (certReqCtx != NULL) still requires a peer - * certificate and a valid CertificateVerify. */ - (!ssl->options.verifyPostHandshake || ssl->certReqCtx != NULL) && + /* Exempt only the enclosing handshake; a post-handshake exchange + * still requires a peer certificate and a valid + * CertificateVerify. */ + (!ssl->options.verifyPostHandshake || TLS13_POST_HANDSHAKE(ssl)) && #endif (!ssl->options.havePeerCert || !ssl->options.havePeerVerify)) { ret = NO_PEER_CERT; /* NO_PEER_VERIFY */ @@ -14302,8 +14313,9 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) } #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - /* Server's authenticating with PSK must not send this. */ - if (ssl->options.pskNegotiated + /* RFC 8446 4.3.2: a server authenticating with a PSK must not send + * this in the main handshake, but may send it post-handshake. */ + if (ssl->options.pskNegotiated && !TLS13_POST_HANDSHAKE(ssl) #ifdef WOLFSSL_CERT_WITH_EXTERN_PSK && !ssl->options.certWithExternPsk #endif @@ -14463,7 +14475,9 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) } #endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) - if (!ssl->options.pskNegotiated + if (!ssl->options.pskNegotiated || + (ssl->options.side == WOLFSSL_SERVER_END && + TLS13_POST_HANDSHAKE(ssl)) #ifdef WOLFSSL_CERT_WITH_EXTERN_PSK || ssl->options.certWithExternPsk #endif @@ -14477,18 +14491,13 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) if (ssl->options.verifyPeer && #ifdef WOLFSSL_POST_HANDSHAKE_AUTH /* The post-handshake-auth exemption is only valid during - * the initial handshake. On the server, once a - * post-handshake CertificateRequest is outstanding - * (certReqCtx != NULL), a Certificate is required again. - * Scoped to the server: certReqCtx means something - * different on the client (a received request) and the - * client does not process an inbound Finished in that - * state. Whether an empty Certificate is then accepted - * follows the verify mode (FAIL_IF_NO_PEER_CERT), exactly - * as for first-handshake client authentication. */ + * the enclosing handshake. Once the server has requested a + * certificate post-handshake, one is required again. + * Whether an empty Certificate is then accepted follows the + * verify mode (FAIL_IF_NO_PEER_CERT), exactly as for + * first-handshake client authentication. */ (!ssl->options.verifyPostHandshake || - (ssl->options.side == WOLFSSL_SERVER_END && - ssl->certReqCtx != NULL)) && + TLS13_POST_HANDSHAKE(ssl)) && #endif !ssl->msgsReceived.got_certificate) { WOLFSSL_MSG("Finished received out of order - " @@ -15565,7 +15574,8 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) return WOLFSSL_FATAL_ERROR; } #ifndef NO_CERTS - if (!ssl->options.resuming && ssl->options.sendVerify) { + if ((!ssl->options.resuming || TLS13_POST_HANDSHAKE(ssl)) && + ssl->options.sendVerify) { ssl->error = SendTls13Certificate(ssl); if (ssl->error != 0) { wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); @@ -15586,7 +15596,8 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) || \ defined(WOLFSSL_HAVE_SLHDSA))) && \ (!defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH)) - if (!ssl->options.resuming && ssl->options.sendVerify) { + if ((!ssl->options.resuming || TLS13_POST_HANDSHAKE(ssl)) && + ssl->options.sendVerify) { ssl->error = SendTls13CertificateVerify(ssl); if (ssl->error != 0) { wolfssl_local_MaybeCheckAlertOnErr(ssl, ssl->error); diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 2fe353732d..47754b98d3 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -3986,6 +3986,195 @@ int test_tls13_pha(void) return EXPECT_RESULT(); } +/* Post-handshake auth over a resumed (ticket-PSK) connection. Client + * credentials go on the CTX: FreeHandshakeResources() unloads SSL-owned + * certificates, leaving nothing to answer a later request with. */ +int test_tls13_pha_resumption(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_POST_HANDSHAKE_AUTH) && defined(HAVE_SESSION_TICKET) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_RSA) && !defined(NO_CERTS) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION* sess = NULL; + struct test_memio_ctx test_ctx; + char msg[] = "hello wolfssl!"; + char buf[sizeof(msg)]; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + /* PHA has to be offered in the ClientHello. */ + ExpectIntEQ(wolfSSL_CTX_allow_post_handshake_auth(ctx_c), 0); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL), + WOLFSSL_SUCCESS); + /* No client certificate wanted for the handshake itself. */ + wolfSSL_CTX_set_verify(ctx_s, WOLFSSL_VERIFY_NONE, NULL); + + for (i = 0; i < 2 && EXPECT_SUCCESS(); i++) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + + if (i == 1) + 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), i); + + if (i == 0) { + /* Drain the NewSessionTicket so the ticket gets cached. */ + ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), + WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + } + + if (EXPECT_SUCCESS()) { + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS); + } + + /* The server's write carries the CertificateRequest. */ + ExpectIntEQ(wolfSSL_write(ssl_s, msg, (int)sizeof(msg) - 1), + (int)sizeof(msg) - 1); + ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf) - 1), + (int)sizeof(msg) - 1); + ExpectIntEQ(wolfSSL_write(ssl_c, msg, (int)sizeof(msg) - 1), + (int)sizeof(msg) - 1); + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf) - 1), + (int)sizeof(msg) - 1); + + ExpectIntEQ(ssl_s->options.havePeerCert, 1); + ExpectIntEQ(ssl_s->options.havePeerVerify, 1); + + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + } + + 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(); +} + +/* Server must reject a post-handshake Finished that omits the Certificate + * flight on a resumed connection. A client answers the request from inside + * wolfSSL_read(), so handShakeState is parked for that read and the response is + * driven by hand with sendVerify cleared. handShakeDone stays set, so + * SendTls13Finished() still produces a valid MAC. */ +int test_tls13_pha_resumption_bare_finished(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_POST_HANDSHAKE_AUTH) && defined(HAVE_SESSION_TICKET) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ + !defined(NO_RSA) && !defined(NO_CERTS) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION* sess = NULL; + struct test_memio_ctx test_ctx; + char msg[] = "hello wolfssl!"; + char buf[sizeof(msg)]; + int i; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile, + WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_allow_post_handshake_auth(ctx_c), 0); + ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL), + WOLFSSL_SUCCESS); + wolfSSL_CTX_set_verify(ctx_s, WOLFSSL_VERIFY_NONE, NULL); + + /* First connection only exists to obtain a ticket. */ + for (i = 0; i < 2 && EXPECT_SUCCESS(); i++) { + test_ctx.c_len = test_ctx.s_len = 0; + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + + if (i == 1) + 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), i); + + if (i == 0) { + ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), + WOLFSSL_ERROR_WANT_READ); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + } + else { + if (EXPECT_SUCCESS()) { + wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER | + WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + ExpectIntEQ(wolfSSL_request_certificate(ssl_s), + WOLFSSL_SUCCESS); + } + ExpectIntEQ(wolfSSL_write(ssl_s, msg, (int)sizeof(msg) - 1), + (int)sizeof(msg) - 1); + + /* Consume the CertificateRequest without answering it. */ + if (EXPECT_SUCCESS()) { + ssl_c->options.handShakeState = CLIENT_FINISHED_COMPLETE; + } + ExpectIntEQ(wolfSSL_read(ssl_c, buf, sizeof(buf) - 1), + (int)sizeof(msg) - 1); + ExpectIntEQ(ssl_c->options.sendVerify, SEND_CERT); + + /* Answer with a bare Finished over that same transcript. */ + if (EXPECT_SUCCESS()) { + ssl_c->options.sendVerify = 0; + ssl_c->options.clientState = CLIENT_HELLO_COMPLETE; + ssl_c->options.connectState = FIRST_REPLY_DONE; + ssl_c->options.handShakeState = CLIENT_HELLO_COMPLETE; + ssl_c->options.processReply = 0; + ExpectIntEQ(wolfSSL_connect_TLSv13(ssl_c), WOLFSSL_SUCCESS); + } + + /* Data behind the Finished: a server that wrongly accepted it + * returns this instead of an error. */ + ExpectIntEQ(wolfSSL_write(ssl_c, msg, (int)sizeof(msg) - 1), + (int)sizeof(msg) - 1); + + ExpectIntEQ(wolfSSL_read(ssl_s, buf, sizeof(buf) - 1), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), OUT_OF_ORDER_E); + ExpectIntEQ(ssl_s->options.havePeerCert, 0); + ExpectIntEQ(ssl_s->options.havePeerVerify, 0); + } + + wolfSSL_free(ssl_c); + ssl_c = NULL; + wolfSSL_free(ssl_s); + ssl_s = NULL; + } + + 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(); +} + #if defined(HAVE_RPK) && defined(WOLFSSL_TLS13) && \ !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \ !defined(NO_SHA256) diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index 707f3b8771..ec11d13b15 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -31,6 +31,8 @@ int test_tls13_bad_psk_binder(void); int test_tls13_rpk_handshake(void); int test_tls13_rpk_handshake_no_negotiation(void); int test_tls13_pha(void); +int test_tls13_pha_resumption(void); +int test_tls13_pha_resumption_bare_finished(void); int test_tls13_rpk_untrusted(void); int test_tls13_rpk_trust(void); int test_tls13_rpk_unoffered_cert_type(void); @@ -118,6 +120,8 @@ int test_tls13_pha_status_request(void); TEST_DECL_GROUP("tls13", test_tls13_rpk_handshake), \ TEST_DECL_GROUP("tls13", test_tls13_rpk_handshake_no_negotiation), \ TEST_DECL_GROUP("tls13", test_tls13_pha), \ + TEST_DECL_GROUP("tls13", test_tls13_pha_resumption), \ + TEST_DECL_GROUP("tls13", test_tls13_pha_resumption_bare_finished), \ TEST_DECL_GROUP("tls13", test_tls13_rpk_untrusted), \ TEST_DECL_GROUP("tls13", test_tls13_rpk_trust), \ TEST_DECL_GROUP("tls13", test_tls13_rpk_unoffered_cert_type), \ From 1f0190e7dfada26008575e49e1c1a62e111586fe Mon Sep 17 00:00:00 2001 From: Kareem Date: Tue, 18 Aug 2026 13:29:26 -0700 Subject: [PATCH 2/2] Code review feedback --- src/tls13.c | 27 +++++++++++++-------------- tests/api/test_tls13.c | 4 ++++ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/tls13.c b/src/tls13.c index 76a9b44425..bc6ed03ce2 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -12726,13 +12726,12 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, #endif /* !NO_CERTS */ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH -/* The message being processed belongs to a post-handshake exchange rather than - * to the enclosing handshake. Whatever resumption, PSK or deferred - * (post-handshake) verification excused during that handshake, a later - * post-handshake exchange has to stand on its own. */ -#define TLS13_POST_HANDSHAKE(ssl) ((ssl)->options.handShakeDone) +/* Message is being processed after the enclosing handshake completed. Whatever + * resumption, PSK or deferred (post-handshake) verification excused during that + * handshake, a later post-handshake exchange has to stand on its own. */ +#define TLS13_AFTER_HANDSHAKE(ssl) ((ssl)->options.handShakeDone) #else -#define TLS13_POST_HANDSHAKE(ssl) 0 +#define TLS13_AFTER_HANDSHAKE(ssl) 0 #endif /* Parse and handle a TLS v1.3 Finished message. @@ -12760,10 +12759,10 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_CLIENT_AUTH) /* verify the client sent certificate if required */ if (ssl->options.side == WOLFSSL_SERVER_END && - (!ssl->options.resuming || TLS13_POST_HANDSHAKE(ssl)) && + (!ssl->options.resuming || TLS13_AFTER_HANDSHAKE(ssl)) && (ssl->options.mutualAuth || ssl->options.failNoCert)) { #ifdef OPENSSL_COMPATIBLE_DEFAULTS - if (ssl->options.isPSK && !TLS13_POST_HANDSHAKE(ssl)) { + if (ssl->options.isPSK && !TLS13_AFTER_HANDSHAKE(ssl)) { WOLFSSL_MSG("TLS v1.3 client used PSK but cert required. Allowing " "for OpenSSL compatibility"); } @@ -12774,7 +12773,7 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* Exempt only the enclosing handshake; a post-handshake exchange * still requires a peer certificate and a valid * CertificateVerify. */ - (!ssl->options.verifyPostHandshake || TLS13_POST_HANDSHAKE(ssl)) && + (!ssl->options.verifyPostHandshake || TLS13_AFTER_HANDSHAKE(ssl)) && #endif (!ssl->options.havePeerCert || !ssl->options.havePeerVerify)) { ret = NO_PEER_CERT; /* NO_PEER_VERIFY */ @@ -14315,7 +14314,7 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) /* RFC 8446 4.3.2: a server authenticating with a PSK must not send * this in the main handshake, but may send it post-handshake. */ - if (ssl->options.pskNegotiated && !TLS13_POST_HANDSHAKE(ssl) + if (ssl->options.pskNegotiated && !TLS13_AFTER_HANDSHAKE(ssl) #ifdef WOLFSSL_CERT_WITH_EXTERN_PSK && !ssl->options.certWithExternPsk #endif @@ -14477,7 +14476,7 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) if (!ssl->options.pskNegotiated || (ssl->options.side == WOLFSSL_SERVER_END && - TLS13_POST_HANDSHAKE(ssl)) + TLS13_AFTER_HANDSHAKE(ssl)) #ifdef WOLFSSL_CERT_WITH_EXTERN_PSK || ssl->options.certWithExternPsk #endif @@ -14497,7 +14496,7 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type) * verify mode (FAIL_IF_NO_PEER_CERT), exactly as for * first-handshake client authentication. */ (!ssl->options.verifyPostHandshake || - TLS13_POST_HANDSHAKE(ssl)) && + TLS13_AFTER_HANDSHAKE(ssl)) && #endif !ssl->msgsReceived.got_certificate) { WOLFSSL_MSG("Finished received out of order - " @@ -15574,7 +15573,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) return WOLFSSL_FATAL_ERROR; } #ifndef NO_CERTS - if ((!ssl->options.resuming || TLS13_POST_HANDSHAKE(ssl)) && + if ((!ssl->options.resuming || TLS13_AFTER_HANDSHAKE(ssl)) && ssl->options.sendVerify) { ssl->error = SendTls13Certificate(ssl); if (ssl->error != 0) { @@ -15596,7 +15595,7 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) defined(HAVE_FALCON) || defined(WOLFSSL_HAVE_MLDSA) || \ defined(WOLFSSL_HAVE_SLHDSA))) && \ (!defined(NO_WOLFSSL_SERVER) || !defined(WOLFSSL_NO_CLIENT_AUTH)) - if ((!ssl->options.resuming || TLS13_POST_HANDSHAKE(ssl)) && + if ((!ssl->options.resuming || TLS13_AFTER_HANDSHAKE(ssl)) && ssl->options.sendVerify) { ssl->error = SendTls13CertificateVerify(ssl); if (ssl->error != 0) { diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 47754b98d3..781f0c79d5 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -4004,6 +4004,8 @@ int test_tls13_pha_resumption(void) char buf[sizeof(msg)]; int i; + /* Setup only creates a CTX when the pointer is NULL, so the call in the + * loop reuses these and creates just the SSL objects. */ XMEMSET(&test_ctx, 0, sizeof(test_ctx)); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); @@ -4091,6 +4093,8 @@ int test_tls13_pha_resumption_bare_finished(void) char buf[sizeof(msg)]; int i; + /* Setup only creates a CTX when the pointer is NULL, so the call in the + * loop reuses these and creates just the SSL objects. */ XMEMSET(&test_ctx, 0, sizeof(test_ctx)); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, NULL, NULL, wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);