Carry the server certificate verifier over to the redirect client (#2634)

* Carry the server certificate verifier over to the redirect client

create_redirect_client() now copies the CA store and the session verifier
to the SSLClient it builds for a cross-host https redirect (#2632), but a
verifier given to set_server_certificate_verifier() was still dropped: the
redirect client's ctx never had the verify callback wired in, so a
pinning verifier never ran on the host the server redirects to.

SSLClient now keeps its own copy of the verifier, since ctx_ cannot report
it back and the backends hold it in a slot shared by every client, and
installs it on the redirect client. The copy also replaces the
Windows-only server_certificate_verifier_set_ flag.

SSLClientRedirectTest.ServerCertificateVerifier fails before this change
and passes after (OpenSSL 3, Mbed TLS 2.28, wolfSSL 5.6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAYpQgXt95LdDQcJYgjB8

* Clarify the server_certificate_verifier_ comment

The backends keep the verify callback in a per-thread slot, not one
shared by every client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGAYpQgXt95LdDQcJYgjB8

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
yhiroseandClaude Opus 5.5 authored and GitHub committed 2026-10-16 14:12:01 -04:00
1 parent d78a3cbb82
commit 9f6dcf1230
2 files changed
+69 -8

No files matched your search

+14 -8
View File
@@ -3454,11 +3454,13 @@ private:
std::function<SSLVerifierResponse(tls::session_t)> session_verifier_;
// The verifier given to set_server_certificate_verifier(), kept for the
// redirect client: ctx_ cannot report it back, and the backends keep it in
// a per-thread slot that any other client may overwrite.
tls::VerifyCallback server_certificate_verifier_;
#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
bool enable_windows_cert_verification_ = true;
// Like ca_cert_store_set_, tracks what ctx_ cannot report back: whether
// set_server_certificate_verifier() installed a verifier.
bool server_certificate_verifier_set_ = false;
#endif
friend class ClientImpl;
@@ -15944,6 +15946,11 @@ inline bool ClientImpl::create_redirect_client(
}
redirect_client.session_verifier_ = self.session_verifier_;
if (self.server_certificate_verifier_) {
redirect_client.set_server_certificate_verifier(
self.server_certificate_verifier_);
}
}
// Client certificates are set through constructor for SSLClient
@@ -18751,10 +18758,8 @@ inline void SSLClient::set_ca_cert_store(tls::ca_store_t ca_cert_store) {
inline void
SSLClient::set_server_certificate_verifier(tls::VerifyCallback verifier) {
if (!ctx_) { return; }
#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
server_certificate_verifier_set_ = static_cast<bool>(verifier);
#endif
tls::set_verify_callback(ctx_, verifier);
server_certificate_verifier_ = verifier;
tls::set_verify_callback(ctx_, std::move(verifier));
}
inline void SSLClient::set_session_verifier(
@@ -18817,7 +18822,8 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
ca_cert_dir_path_.empty() && ca_cert_pem_.empty() && !ca_cert_store_set_;
// Only a verifier set through set_server_certificate_verifier() is seen
// here, not one installed with tls::set_verify_callback() directly.
options.server_certificate_verifier_set = server_certificate_verifier_set_;
options.server_certificate_verifier_set =
static_cast<bool>(server_certificate_verifier_);
#endif
tls::session_t session = nullptr;