@@ -3687,6 +3687,69 @@ int test_tls13_cert_alias_uaf_sni(void)
36873687}
36883688
36893689
3690+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_TLS13 ) && \
3691+ defined(HAVE_SNI ) && !defined(WOLFSSL_COPY_KEY ) && \
3692+ !defined(WOLFSSL_BLIND_PRIVATE_KEY ) && \
3693+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
3694+ !defined(NO_RSA ) && !defined(NO_CERTS )
3695+ /* React to the client SNI by reloading the private key on the existing CTX.
3696+ * Without WOLFSSL_COPY_KEY the key buffer is shared between the CTX and SSL,
3697+ * so freeing it on the CTX would dangle the SSL's alias. The server signs its
3698+ * CertificateVerify with that key, so a dangling alias is a heap-use-after-free
3699+ * on the signing path; the handshake must still complete. */
3700+ static int test_key_alias_sni_cb (WOLFSSL * ssl , int * ad , void * arg )
3701+ {
3702+ WOLFSSL_CTX * ctx = wolfSSL_get_SSL_CTX (ssl );
3703+ (void )ad ;
3704+ (void )arg ;
3705+ (void )wolfSSL_CTX_use_PrivateKey_file (ctx , svrKeyFile ,
3706+ WOLFSSL_FILETYPE_PEM );
3707+ /* 0 means ack the servername and continue the handshake. */
3708+ return 0 ;
3709+ }
3710+ #endif
3711+
3712+ int test_tls13_key_alias_uaf_sni (void )
3713+ {
3714+ EXPECT_DECLS ;
3715+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_TLS13 ) && \
3716+ defined(HAVE_SNI ) && !defined(WOLFSSL_COPY_KEY ) && \
3717+ !defined(WOLFSSL_BLIND_PRIVATE_KEY ) && \
3718+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
3719+ !defined(NO_RSA ) && !defined(NO_CERTS )
3720+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
3721+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
3722+ struct test_memio_ctx test_ctx ;
3723+ const char * host = "example.com" ;
3724+
3725+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
3726+ /* Server cert/key are loaded on ctx_s, so ssl_s->buffers.key aliases
3727+ * ctx_s->privateKey. */
3728+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
3729+ wolfTLSv1_3_client_method , wolfTLSv1_3_server_method ), 0 );
3730+
3731+ /* Server swaps its CTX private key when the SNI arrives. */
3732+ wolfSSL_CTX_set_servername_callback (ctx_s , test_key_alias_sni_cb );
3733+
3734+ /* Client offers SNI so the server callback fires while parsing the
3735+ * ClientHello. */
3736+ ExpectIntEQ (wolfSSL_UseSNI (ssl_c , WOLFSSL_SNI_HOST_NAME , host ,
3737+ (word16 )XSTRLEN (host )), WOLFSSL_SUCCESS );
3738+
3739+ /* The callback frees the aliased key mid-handshake; the server then signs
3740+ * CertificateVerify with ssl->buffers.key. The handshake must complete
3741+ * without a UAF. */
3742+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
3743+
3744+ wolfSSL_free (ssl_c );
3745+ wolfSSL_free (ssl_s );
3746+ wolfSSL_CTX_free (ctx_c );
3747+ wolfSSL_CTX_free (ctx_s );
3748+ #endif
3749+ return EXPECT_RESULT ();
3750+ }
3751+
3752+
36903753#if defined(HAVE_IO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_TLS13 ) && \
36913754 defined(WOLFSSL_HAVE_MLKEM ) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE ) && \
36923755 !defined(WOLFSSL_MLKEM_NO_DECAPSULATE ) && \
0 commit comments