Procházet zdrojové kódy

Pass the session handle to wolfSSL verify callbacks

The wolfSSL verify callback set VerifyContext::session to the raw WOLFSSL
pointer, while every other tls:: function takes the WolfSSLSession that
wraps it, so passing ctx.session on from a verifier read the wrong type.
Point each WOLFSSL back to its WolfSSLSession and hand that out instead,
as the OpenSSL and Mbed TLS backends already do with their own handles.
yhirose před 2 dny
rodič
revize
c11d95b26b
2 změnil soubory, kde provedl 55 přidání a 1 odebrání
  1. 15 1
      httplib.h
  2. 40 0
      test/test.cc

+ 15 - 1
httplib.h

@@ -21699,6 +21699,14 @@ inline int context_ex_data_index() {
   return index;
 }
 
+// Each WOLFSSL points back to its WolfSSLSession, the session_t that every
+// other tls:: function takes.
+inline int session_ex_data_index() {
+  static const auto index =
+      wolfSSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+  return index;
+}
+
 // wolfSSL verify callback wrapper
 inline int wolfssl_verify_callback(int preverify_ok,
                                    WOLFSSL_X509_STORE_CTX *x509_ctx) {
@@ -21716,7 +21724,7 @@ inline int wolfssl_verify_callback(int preverify_ok,
   int err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
 
   VerifyContext verify_ctx;
-  verify_ctx.session = static_cast<session_t>(ssl);
+  verify_ctx.session = wolfSSL_get_ex_data(ssl, session_ex_data_index());
   verify_ctx.cert = static_cast<cert_t>(cert);
   verify_ctx.depth = depth;
   verify_ctx.preverify_ok = (preverify_ok != 0);
@@ -21997,6 +22005,12 @@ inline session_t create_session(ctx_t ctx, socket_t sock) {
     return nullptr;
   }
 
+  if (wolfSSL_set_ex_data(session->ssl, impl::session_ex_data_index(),
+                          session) != WOLFSSL_SUCCESS) {
+    delete session;
+    return nullptr;
+  }
+
   wolfSSL_set_fd(session->ssl, static_cast<int>(sock));
 
   return static_cast<session_t>(session);

+ 40 - 0
test/test.cc

@@ -15706,6 +15706,46 @@ TEST(VerifyCallbackTest, VerifierStaysWithItsClient) {
   EXPECT_GT(accepting_calls, 0);
 }
 
+// VerifyContext::session is the same handle the other tls:: functions take.
+TEST(VerifyCallbackTest, SessionMatchesSessionVerifier) {
+  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_certificate_verification(false);
+
+  session_t verifier_session = nullptr;
+  cli.set_server_certificate_verifier([&](const VerifyContext &ctx) {
+    verifier_session = ctx.session;
+    return true;
+  });
+
+  session_t session_verifier_session = nullptr;
+  cli.set_session_verifier([&](session_t session) {
+    session_verifier_session = session;
+    return SSLVerifierResponse::NoDecisionMade;
+  });
+
+  auto res = cli.Get("/test");
+  ASSERT_TRUE(res) << "Error: " << to_string(res.error());
+  EXPECT_NE(nullptr, verifier_session);
+  EXPECT_EQ(session_verifier_session, verifier_session);
+}
+
 TEST(TlsVerifyErrorTest, GetVerifyErrorString) {
   using httplib::tls::TlsError;