diff --git a/src/internal.c b/src/internal.c index 267c75a5d65..b950af6198c 100644 --- a/src/internal.c +++ b/src/internal.c @@ -8952,6 +8952,11 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl) #ifdef HAVE_TLS_EXTENSIONS #if !defined(NO_TLS) TLSX_FreeAll(ssl->extensions, ssl->heap); + ssl->extensions = NULL; +#if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) + ssl->secure_renegotiation = NULL; +#endif #endif /* !NO_TLS */ #ifdef HAVE_ALPN if (ssl->alpn_peer_requested != NULL) { @@ -9315,6 +9320,10 @@ void FreeHandshakeResources(WOLFSSL* ssl) /* Some extensions need to be kept for post-handshake querying. */ TLSX_FreeAll(ssl->extensions, ssl->heap); ssl->extensions = NULL; +#if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) + ssl->secure_renegotiation = NULL; +#endif #else #if !defined(NO_CERTS) && !defined(WOLFSSL_NO_SIGALG) TLSX_Remove(&ssl->extensions, TLSX_SIGNATURE_ALGORITHMS, ssl->heap); diff --git a/src/ssl.c b/src/ssl.c index 58cd6701c02..284b09c6013 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -10051,6 +10051,10 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #if defined(HAVE_TLS_EXTENSIONS) && !defined(NO_TLS) TLSX_FreeAll(ssl->extensions, ssl->heap); ssl->extensions = NULL; + #if defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) + ssl->secure_renegotiation = NULL; + #endif #endif if (ssl->keys.encryptionOn) { diff --git a/tests/api.c b/tests/api.c index 0e9cbe29824..35ddd983718 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10203,6 +10203,39 @@ static int test_wolfSSL_wolfSSL_UseSecureRenegotiation(void) return EXPECT_RESULT(); } +/* TLSX_FreeAll frees the SecureRenegotiation struct but the cached pointer + * ssl->secure_renegotiation was not cleared, causing a use-after-free when + * queried after wolfSSL_clear(). */ +static int test_wolfSSL_clear_secure_renegotiation(void) +{ + EXPECT_DECLS; +#if (defined(HAVE_SECURE_RENEGOTIATION) || \ + defined(HAVE_SERVER_RENEGOTIATION_INFO)) && \ + (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \ + !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) + WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + WOLFSSL *ssl = wolfSSL_new(ctx); + long support; + + ExpectNotNull(ctx); + ExpectNotNull(ssl); + + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_UseSecureRenegotiation(ssl)); + ExpectNotNull(ssl->secure_renegotiation); + if (ssl->secure_renegotiation != NULL) + ssl->secure_renegotiation->enabled = 1; + + ExpectIntEQ(WOLFSSL_SUCCESS, wolfSSL_clear(ssl)); + support = wolfSSL_SSL_get_secure_renegotiation_support(ssl); + ExpectNull(ssl->secure_renegotiation); + ExpectIntEQ(WOLFSSL_FAILURE, support); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif + return EXPECT_RESULT(); +} + /* Test reconnecting with a different ciphersuite after a renegotiation. */ static int test_wolfSSL_SCR_Reconnect(void) { @@ -35770,6 +35803,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_TLSX_TCA_Find), TEST_DECL(test_TLSX_SNI_GetSize_overflow), TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation), + TEST_DECL(test_wolfSSL_clear_secure_renegotiation), TEST_DECL(test_wolfSSL_SCR_Reconnect), TEST_DECL(test_wolfSSL_SCR_check_enabled), TEST_DECL(test_tls_ext_duplicate),