mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
Keep an accepting verifier from overriding Mbed TLS verification
With built-in verification on, a server certificate verifier returning true made Mbed TLS accept a certificate its own check had rejected, such as a self-signed one, while OpenSSL and wolfSSL still failed with SSLServerVerification. On a client, keep the flags of Mbed TLS's own verification, so the verifier is an additional check as on the other backends. With verification off, the verifier is still the only check. A server still clears them: there all three backends let an accepting callback admit a client certificate.
This commit is contained in:
1 parent
3744227de2
commit
906a7bf04e
2 files changed
+46
-2
No files matched your search
@@ -20770,6 +20770,8 @@ struct MbedTlsSession {
|
|||||||
// ever runs the callback of its own context.
|
// ever runs the callback of its own context.
|
||||||
VerifyCallback verify_callback;
|
VerifyCallback verify_callback;
|
||||||
|
|
||||||
|
bool is_server = false;
|
||||||
|
|
||||||
MbedTlsSession() { mbedtls_ssl_init(&ssl); }
|
MbedTlsSession() { mbedtls_ssl_init(&ssl); }
|
||||||
|
|
||||||
~MbedTlsSession() { mbedtls_ssl_free(&ssl); }
|
~MbedTlsSession() { mbedtls_ssl_free(&ssl); }
|
||||||
@@ -20949,7 +20951,7 @@ inline int mbedtls_verify_callback(void *data, mbedtls_x509_crt *crt,
|
|||||||
|
|
||||||
// set_sni() disabled hostname verification for this session: ignore the
|
// set_sni() disabled hostname verification for this session: ignore the
|
||||||
// CN/SAN mismatch flag, as the OpenSSL/wolfSSL backends do. The final
|
// CN/SAN mismatch flag, as the OpenSSL/wolfSSL backends do. The final
|
||||||
// pass/fail decision still comes from the remaining flags (or, below, from
|
// pass/fail decision still comes from the remaining flags (and, below, from
|
||||||
// the user's own verify callback).
|
// the user's own verify callback).
|
||||||
if (session->suppress_hostname_mismatch) { mbedtls_clear_cn_mismatch(flags); }
|
if (session->suppress_hostname_mismatch) { mbedtls_clear_cn_mismatch(flags); }
|
||||||
|
|
||||||
@@ -20976,7 +20978,9 @@ inline int mbedtls_verify_callback(void *data, mbedtls_x509_crt *crt,
|
|||||||
bool accepted = run_verify_callback(callback, verify_ctx);
|
bool accepted = run_verify_callback(callback, verify_ctx);
|
||||||
|
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
*flags = 0; // Clear all error flags
|
// Overrides the built-in verification only on a server, as on OpenSSL and
|
||||||
|
// wolfSSL, whose clients check the verify result after the handshake
|
||||||
|
if (session->is_server) { *flags = 0; }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
|
return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
|
||||||
@@ -21379,6 +21383,7 @@ inline session_t create_session(ctx_t ctx, socket_t sock) {
|
|||||||
// may ask for. The session runs its own copy of the user's callback, which
|
// may ask for. The session runs its own copy of the user's callback, which
|
||||||
// set_verify_callback() cannot replace under a handshake.
|
// set_verify_callback() cannot replace under a handshake.
|
||||||
session->verify_callback = mctx->verify_callback;
|
session->verify_callback = mctx->verify_callback;
|
||||||
|
session->is_server = mctx->is_server;
|
||||||
mbedtls_ssl_set_verify(&session->ssl, impl::mbedtls_verify_callback, session);
|
mbedtls_ssl_set_verify(&session->ssl, impl::mbedtls_verify_callback, session);
|
||||||
|
|
||||||
return static_cast<session_t>(session);
|
return static_cast<session_t>(session);
|
||||||
|
|||||||
@@ -17060,6 +17060,45 @@ TEST(VerifyCallbackTest, VerifyContextFields) {
|
|||||||
EXPECT_TRUE(saw_leaf_cert);
|
EXPECT_TRUE(saw_leaf_cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A verifier that accepts runs alongside the built-in verification, and is the
|
||||||
|
// only check once that is turned off.
|
||||||
|
TEST(VerifyCallbackTest, AcceptingVerifierDoesNotOverrideVerification) {
|
||||||
|
using namespace httplib::tls;
|
||||||
|
|
||||||
|
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
|
||||||
|
ASSERT_TRUE(svr.is_valid());
|
||||||
|
svr.Get("/test", [](const Request &, Response &res) {
|
||||||
|
res.set_content("ok", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
auto port = svr.bind_to_any_port(HOST);
|
||||||
|
thread t([&]() { svr.listen_after_bind(); });
|
||||||
|
auto se = detail::scope_exit([&] {
|
||||||
|
svr.stop();
|
||||||
|
t.join();
|
||||||
|
});
|
||||||
|
svr.wait_until_ready();
|
||||||
|
|
||||||
|
SSLClient cli(HOST, port);
|
||||||
|
cli.enable_server_hostname_verification(false);
|
||||||
|
auto calls = 0;
|
||||||
|
cli.set_server_certificate_verifier([&](const VerifyContext &) {
|
||||||
|
calls++;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// cert.pem is not trusted
|
||||||
|
auto res = cli.Get("/test");
|
||||||
|
ASSERT_FALSE(res);
|
||||||
|
EXPECT_EQ(Error::SSLServerVerification, res.error());
|
||||||
|
EXPECT_GT(calls, 0);
|
||||||
|
|
||||||
|
cli.enable_server_certificate_verification(false);
|
||||||
|
res = cli.Get("/test");
|
||||||
|
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
|
||||||
|
EXPECT_EQ("ok", res->body);
|
||||||
|
}
|
||||||
|
|
||||||
// A verifier belongs to the client that set it, not to the thread that set it.
|
// A verifier belongs to the client that set it, not to the thread that set it.
|
||||||
TEST(VerifyCallbackTest, VerifierStaysWithItsClient) {
|
TEST(VerifyCallbackTest, VerifierStaysWithItsClient) {
|
||||||
using namespace httplib::tls;
|
using namespace httplib::tls;
|
||||||
|
|||||||
Reference in new issue
Block a user