Explorar o código

Add WebSocketClient::enable_server_hostname_verification

WebSocketClient's TLS setup already threaded
ClientTlsSessionOptions::server_hostname_verification through
setup_client_tls_session(), the same path SSLClient uses, but never
exposed a way to set it: create_stream() called setup_client_tls_session()
without an options argument, so the default (verification on) was the
only reachable value.

Add the public setter, mirroring ClientImpl/SSLClient/Client, and wire
it into create_stream()'s ClientTlsSessionOptions. Last open item from
issue #2531's WebSocketClient/SSLClient API alignment.
yhirose hai 1 día
pai
achega
86d0210391
Modificáronse 3 ficheiros con 34 adicións e 5 borrados
  1. 2 0
      README-websocket.md
  2. 15 5
      httplib.h
  3. 17 0
      test/test.cc

+ 2 - 0
README-websocket.md

@@ -188,6 +188,7 @@ void set_ca_cert_path(const std::string &ca_cert_file_path,
                       const std::string &ca_cert_dir_path = std::string());
 void set_ca_cert_store(tls::ca_store_t store);
 void enable_server_certificate_verification(bool enabled);
+void enable_server_hostname_verification(bool enabled);
 ```
 
 ## Examples
@@ -395,6 +396,7 @@ if (ws.connect()) {
 httplib::ws::WebSocketClient ws("wss://example.com/ws");
 ws.set_ca_cert_path("/path/to/ca-bundle.crt");
 ws.enable_server_certificate_verification(true);
+ws.enable_server_hostname_verification(true); // default; false skips the identity check
 
 if (ws.connect()) {
     ws.send("secure message");

+ 15 - 5
httplib.h

@@ -4360,6 +4360,7 @@ public:
   void set_ca_cert_store(tls::ca_store_t store);
   void load_ca_cert_store(const char *ca_cert, std::size_t size);
   void enable_server_certificate_verification(bool enabled);
+  void enable_server_hostname_verification(bool enabled);
   void enable_system_ca(bool enabled);
 #endif
 
@@ -4406,6 +4407,7 @@ private:
   bool certs_loaded_ = false;
   SystemCAMode system_ca_mode_ = SystemCAMode::Auto;
   bool server_certificate_verification_ = true;
+  bool server_hostname_verification_ = true;
 #endif
 };
 
@@ -10137,11 +10139,12 @@ inline bool load_client_ca_config(tls::ctx_t ctx,
   return ret;
 }
 
-// The parts of session setup that only SSLClient needs. WebSocketClient takes
-// the defaults, which is what keeps the two clients on one implementation.
+// The parts of session setup that only SSLClient needs, plus the handful
+// WebSocketClient also exposes; everything else takes the defaults, which is
+// what keeps the two clients on one implementation.
 struct ClientTlsSessionOptions {
-  // SSLClient exposes this independently of certificate verification;
-  // WebSocketClient always checks the identity when it verifies the chain.
+  // Both SSLClient and WebSocketClient expose this independently of
+  // certificate verification.
   bool server_hostname_verification = true;
   std::function<SSLVerifierResponse(tls::session_t)> session_verifier;
   // When non-null, guards session creation against concurrent use of the
@@ -21463,11 +21466,14 @@ inline bool WebSocketClient::create_stream(std::unique_ptr<Stream> &strm,
       certs_loaded_ = true;
     }
 
+    detail::ClientTlsSessionOptions options;
+    options.server_hostname_verification = server_hostname_verification_;
+
     detail::ClientTlsSessionError tls_error;
     if (!detail::setup_client_tls_session(host_, tls_ctx_, tls_session_, sock_,
                                           server_certificate_verification_,
                                           read_timeout_sec_, read_timeout_usec_,
-                                          &tls_error)) {
+                                          &tls_error, options)) {
       error = tls_error.error;
       ssl_error = tls_error.ssl_error;
       ssl_backend_error = tls_error.backend_error;
@@ -21660,6 +21666,10 @@ WebSocketClient::enable_server_certificate_verification(bool enabled) {
   server_certificate_verification_ = enabled;
 }
 
+inline void WebSocketClient::enable_server_hostname_verification(bool enabled) {
+  server_hostname_verification_ = enabled;
+}
+
 inline void WebSocketClient::enable_system_ca(bool enabled) {
   system_ca_mode_ = enabled ? SystemCAMode::Enabled : SystemCAMode::Disabled;
 }

+ 17 - 0
test/test.cc

@@ -21123,6 +21123,23 @@ TEST_F(WebSocketSSLDnsHostTest, TrustedChainWrongNameFails) {
   EXPECT_EQ(-1, res.status());
 }
 
+// Same setup as TrustedChainWrongNameFails, but with hostname verification
+// disabled: the chain is still checked, only the identity check is skipped
+TEST_F(WebSocketSSLDnsHostTest, HostnameVerificationDisabledAcceptsWrongName) {
+  Start(SERVER_CERT_FILE);
+
+  ws::WebSocketClient client(url());
+  client.set_ca_cert_path(SERVER_CERT_FILE);
+  client.enable_server_hostname_verification(false);
+
+  ASSERT_TRUE(client.connect());
+  ASSERT_TRUE(client.send("hello"));
+  std::string msg;
+  EXPECT_EQ(ws::Text, client.read(msg));
+  EXPECT_EQ("hello", msg);
+  client.close();
+}
+
 // A CA that did not sign the server certificate fails the chain, even though
 // the name would match
 TEST_F(WebSocketSSLDnsHostTest, UntrustedChainFails) {