@@ -1671,6 +1671,112 @@ TEST(SSLTest, test_SSL_set_ocsp_response_leak_inside_select_certificate_cb) {
16711671}
16721672
16731673
1674+ #ifdef BSSL_COMPAT
1675+ /* *
1676+ * @brief This test exercises a leak that occurs in SSL_set_ocsp_response() if
1677+ * it returns early due to an error, when it is called from within a certificate
1678+ * selection callback.
1679+ *
1680+ * Without a fix for the leak, running this test under valgrind or similar
1681+ * memory checker tool will report the memory leak.
1682+ *
1683+ * Note that because this test uses knowledge of the internals of the
1684+ * SSL_set_ocsp_response() implementation, in bssl-compat, in order to provoke
1685+ * the leak, it will not work the same on BoringSSL proper.
1686+ */
1687+ TEST (SSLTest, test_SSL_set_ocsp_response_early_return_leak_inside_select_certificate_cb) {
1688+ TempFile server_2_key_pem { server_2_key_pem_str };
1689+ TempFile server_2_cert_chain_pem { server_2_cert_chain_pem_str };
1690+
1691+ static const uint8_t OCSP_RESPONSE[] { 1 , 2 , 3 , 4 , 5 };
1692+
1693+ int sockets[2 ];
1694+ ASSERT_EQ (0 , socketpair (AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0 , sockets));
1695+ SocketCloser close[] { sockets[0 ], sockets[1 ] };
1696+
1697+ bssl::UniquePtr<SSL_CTX> server_ctx (SSL_CTX_new (TLS_server_method ()));
1698+ bssl::UniquePtr<SSL_CTX> client_ctx (SSL_CTX_new (TLS_client_method ()));
1699+
1700+ // Register a dummy tlsext status callback. This will provoke the
1701+ // SSL_set_ocsp_response() call, inside the certificate selection callback, to
1702+ // fail and return early. This in turn will cause the leak to occur if the fix
1703+ // is not in place.
1704+ SSL_CTX_set_tlsext_status_cb (server_ctx.get (), [](SSL *ssl, void *arg) -> int {return 0 ;});
1705+
1706+ // Set up server with a select certificate callback that calls
1707+ // SSL_set_ocsp_response() - which will return early and leak because of the
1708+ // dummy status callback we installed above.
1709+ SSL_CTX_set_select_certificate_cb (server_ctx.get (), [](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
1710+ if (SSL_set_ocsp_response (client_hello->ssl , OCSP_RESPONSE, sizeof (OCSP_RESPONSE)) == 1 ) {
1711+ return ssl_select_cert_success;
1712+ }
1713+ return ssl_select_cert_error;
1714+ });
1715+ ASSERT_TRUE (SSL_CTX_use_certificate_chain_file (server_ctx.get (), server_2_cert_chain_pem.path ()));
1716+ ASSERT_TRUE (SSL_CTX_use_PrivateKey_file (server_ctx.get (), server_2_key_pem.path (), SSL_FILETYPE_PEM));
1717+ bssl::UniquePtr<SSL> server_ssl (SSL_new (server_ctx.get ()));
1718+ ASSERT_TRUE (SSL_set_fd (server_ssl.get (), sockets[0 ]));
1719+ SSL_set_accept_state (server_ssl.get ());
1720+
1721+ // Set up client with ocsp stapling enabled
1722+ SSL_CTX_set_verify (client_ctx.get (), SSL_VERIFY_NONE, nullptr );
1723+ bssl::UniquePtr<SSL> client_ssl (SSL_new (client_ctx.get ()));
1724+ ASSERT_TRUE (SSL_set_fd (client_ssl.get (), sockets[1 ]));
1725+ SSL_set_connect_state (client_ssl.get ());
1726+ SSL_enable_ocsp_stapling (client_ssl.get ());
1727+
1728+ // We expect this to fail because the SSL_set_ocsp_response() call inside the
1729+ // certificate selection callback above will return early with an error,
1730+ // causing the certificate selection callback to fail, which in turn will
1731+ // cause the handshake to fail.
1732+ ASSERT_FALSE (CompleteHandshakes (client_ssl.get (), server_ssl.get ()));
1733+ }
1734+ #endif // BSSL_COMPAT
1735+
1736+
1737+ /* *
1738+ * @brief This test exercises a leak in SSL_CTX_set_select_certificate_cb() when
1739+ * the certificate selection callback throws an exception.
1740+ *
1741+ * Without a fix for the leak, running this test under valgrind or similar
1742+ * memory checker tool will report the memory leak.
1743+ */
1744+ TEST (SSLTest, test_SSL_CTX_set_select_certificate_cb_leak_from_callback_exception) {
1745+ TempFile server_2_key_pem { server_2_key_pem_str };
1746+ TempFile server_2_cert_chain_pem { server_2_cert_chain_pem_str };
1747+
1748+ int sockets[2 ];
1749+ ASSERT_EQ (0 , socketpair (AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0 , sockets));
1750+ SocketCloser close[] { sockets[0 ], sockets[1 ] };
1751+
1752+ bssl::UniquePtr<SSL_CTX> server_ctx (SSL_CTX_new (TLS_server_method ()));
1753+ bssl::UniquePtr<SSL_CTX> client_ctx (SSL_CTX_new (TLS_client_method ()));
1754+
1755+ // Set up server with a select certificate callback that raises an exception
1756+ SSL_CTX_set_select_certificate_cb (server_ctx.get (), [](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
1757+ throw std::runtime_error (" Intentional exception to test for memory leaks" );
1758+ });
1759+
1760+ ASSERT_TRUE (SSL_CTX_use_certificate_chain_file (server_ctx.get (), server_2_cert_chain_pem.path ()));
1761+ ASSERT_TRUE (SSL_CTX_use_PrivateKey_file (server_ctx.get (), server_2_key_pem.path (), SSL_FILETYPE_PEM));
1762+ bssl::UniquePtr<SSL> server_ssl (SSL_new (server_ctx.get ()));
1763+ ASSERT_TRUE (SSL_set_fd (server_ssl.get (), sockets[0 ]));
1764+ SSL_set_accept_state (server_ssl.get ());
1765+
1766+ // Set up client
1767+ SSL_CTX_set_verify (client_ctx.get (), SSL_VERIFY_NONE, nullptr );
1768+ bssl::UniquePtr<SSL> client_ssl (SSL_new (client_ctx.get ()));
1769+ ASSERT_TRUE (SSL_set_fd (client_ssl.get (), sockets[1 ]));
1770+ SSL_set_connect_state (client_ssl.get ());
1771+
1772+ // Handshake will fail because of the exception in the callback
1773+ EXPECT_THROW (
1774+ CompleteHandshakes (client_ssl.get (), server_ssl.get ()),
1775+ std::runtime_error
1776+ );
1777+ }
1778+
1779+
16741780/* *
16751781 * Test that setting a TLS alert and returning ssl_verify_invalid, from a
16761782 * callback installed via SSL_CTX_set_custom_verify(), results in a handshake
0 commit comments