mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 12:00:51 +02:00
TLS 1.3: fix for post-handshake authentication
Only exempt the missing-certificate check during the initial handshake; once a post-handshake CertificateRequest is outstanding the server again requires the client certificate (and its CertificateVerify). Adds a post-handshake auth test.
This commit is contained in:
+17
-2
@@ -11835,7 +11835,10 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#endif
|
||||
if (
|
||||
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|
||||
!ssl->options.verifyPostHandshake &&
|
||||
/* 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) &&
|
||||
#endif
|
||||
(!ssl->options.havePeerCert || !ssl->options.havePeerVerify)) {
|
||||
ret = NO_PEER_CERT; /* NO_PEER_VERIFY */
|
||||
@@ -13507,7 +13510,19 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type)
|
||||
*/
|
||||
if (ssl->options.verifyPeer &&
|
||||
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|
||||
!ssl->options.verifyPostHandshake &&
|
||||
/* 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. */
|
||||
(!ssl->options.verifyPostHandshake ||
|
||||
(ssl->options.side == WOLFSSL_SERVER_END &&
|
||||
ssl->certReqCtx != NULL)) &&
|
||||
#endif
|
||||
!ssl->msgsReceived.got_certificate) {
|
||||
WOLFSSL_MSG("Finished received out of order - "
|
||||
|
||||
@@ -2820,6 +2820,74 @@ int test_tls13_rpk_handshake_no_negotiation(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Post-handshake authentication (PHA) positive guard. A server configured with
|
||||
* WOLFSSL_VERIFY_POST_HANDSHAKE must complete the initial handshake WITHOUT a
|
||||
* client certificate (verification is deferred) and then be able to request one
|
||||
* post-handshake. This guards the property the auth-bypass fix must preserve:
|
||||
* the missing-certificate exemption stays in force while no post-handshake
|
||||
* request is outstanding (certReqCtx == NULL). If the fix wrongly treated the
|
||||
* initial handshake as a pending PHA request, the handshake below would fail.
|
||||
*
|
||||
* Scope: this is a positive guard only.
|
||||
* - The bypass itself is NOT reproduced here: the
|
||||
* SanityCheckTls13MsgReceived / DoTls13Finished branches the fix re-enables
|
||||
* only fire when a client sends a Finished with NO Certificate message at all
|
||||
* (got_certificate == 0). A conformant wolfSSL client always sends at least
|
||||
* an empty Certificate, so reproducing the bypass needs a non-conformant
|
||||
* client; the report used a state-machine model. The negative direction
|
||||
* rests on code review.
|
||||
* - Driving the full post-handshake certificate exchange to completion is
|
||||
* intentionally not asserted: whether the peer chain ends up populated
|
||||
* depends on build options unrelated to this fix (it differs between
|
||||
* --enable-all and the user_settings_all header build), so it is not a
|
||||
* portable assertion. */
|
||||
int test_tls13_pha(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
|
||||
defined(WOLFSSL_POST_HANDSHAKE_AUTH) && defined(SESSION_CERTS) && \
|
||||
!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;
|
||||
struct test_memio_ctx test_ctx;
|
||||
WOLFSSL_X509_CHAIN* chain = NULL;
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
|
||||
|
||||
/* Server: trust the (self-signed) client certificate and defer
|
||||
* verification to post-handshake. */
|
||||
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL),
|
||||
WOLFSSL_SUCCESS);
|
||||
wolfSSL_set_verify(ssl_s,
|
||||
WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_POST_HANDSHAKE, NULL);
|
||||
|
||||
/* Client: load a cert/key and advertise post-handshake auth. */
|
||||
ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
|
||||
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
|
||||
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
|
||||
|
||||
/* Initial handshake must complete even though no client cert was sent -
|
||||
* the verifyPostHandshake exemption (certReqCtx == NULL) is intact. */
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
|
||||
ExpectIntEQ(wolfSSL_get_chain_count(chain), 0);
|
||||
|
||||
/* And the server can issue a post-handshake certificate request. */
|
||||
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
|
||||
|
||||
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_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
|
||||
defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
|
||||
|
||||
@@ -29,6 +29,7 @@ int test_tls13_cipher_suites(void);
|
||||
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_pq_groups(void);
|
||||
int test_tls13_multi_pqc_key_share(void);
|
||||
int test_tls13_early_data(void);
|
||||
@@ -90,6 +91,7 @@ int test_tls13_AEAD_limit_KU_aes128_ccm_8_sha256(void);
|
||||
TEST_DECL_GROUP("tls13", test_tls13_bad_psk_binder), \
|
||||
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_pq_groups), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_multi_pqc_key_share), \
|
||||
TEST_DECL_GROUP("tls13", test_tls13_early_data), \
|
||||
|
||||
Reference in New Issue
Block a user