From d440554c58db532cad458817a713c158a4e5c985 Mon Sep 17 00:00:00 2001 From: Jason Sandlin Date: Thu, 18 Jun 2026 00:26:39 -0700 Subject: [PATCH] Fix Linux WebSocket cert verification, response buffer bounds check, and init/cleanup docs --- Include/httpClient/httpClient.h | 15 +++++++++++++- Source/HTTP/httpcall_response.cpp | 5 +++++ .../Websocketpp/x509_cert_utilities.hpp | 20 +++++++++++-------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Include/httpClient/httpClient.h b/Include/httpClient/httpClient.h index 8744a7649..72d696c1d 100644 --- a/Include/httpClient/httpClient.h +++ b/Include/httpClient/httpClient.h @@ -123,7 +123,11 @@ STDAPI HCMemGetFunctions( /// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL. /// /// This must be called before any other method, except for HCMemSetFunctions() and HCMemGetFunctions(). -/// Should have a corresponding call to HCGlobalCleanup(). +/// Should have a corresponding call to HCCleanup() or HCCleanupAsync(). +/// +/// Initialization is reference counted. Multiple calls to HCInitialize are allowed and will +/// succeed, but each call must be balanced with a corresponding call to HCCleanup/HCCleanupAsync. +/// The library is not fully cleaned up until the last reference is released. /// STDAPI HCInitialize(_In_opt_ HCInitArgs* args) noexcept; @@ -139,6 +143,10 @@ STDAPI_(bool) HCIsInitialized() noexcept; /// /// /// Deprecated, Use HCCleanupAsync instead which allows control of which queue is running the cleanup work and does not potentially deadlock. +/// +/// Initialization is reference counted. Each call to HCInitialize must be balanced with a +/// corresponding call to HCCleanup or HCCleanupAsync. Resources are not fully released until +/// the last reference is closed. /// /// STDAPI_(void) HCCleanup() noexcept; @@ -149,6 +157,11 @@ STDAPI_(void) HCCleanup() noexcept; /// /// Pointer to the XAsyncBlock for the asynchronous call. /// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, or E_FAIL. +/// +/// Initialization is reference counted. Each call to HCInitialize must be balanced with a +/// corresponding call to HCCleanup or HCCleanupAsync. Resources are not fully released until +/// the last reference is closed. +/// STDAPI HCCleanupAsync(XAsyncBlock* async) noexcept; /// diff --git a/Source/HTTP/httpcall_response.cpp b/Source/HTTP/httpcall_response.cpp index fc845f220..310e8831c 100644 --- a/Source/HTTP/httpcall_response.cpp +++ b/Source/HTTP/httpcall_response.cpp @@ -147,6 +147,11 @@ try return E_FAIL; } + if (bufferSize < call->responseBodyBytes.size()) + { + return E_NOT_SUFFICIENT_BUFFER; + } + #if HC_PLATFORM_IS_MICROSOFT memcpy_s(buffer, bufferSize, call->responseBodyBytes.data(), call->responseBodyBytes.size()); #else diff --git a/Source/WebSocket/Websocketpp/x509_cert_utilities.hpp b/Source/WebSocket/Websocketpp/x509_cert_utilities.hpp index 4787ddfe3..b84d26a0c 100644 --- a/Source/WebSocket/Websocketpp/x509_cert_utilities.hpp +++ b/Source/WebSocket/Websocketpp/x509_cert_utilities.hpp @@ -29,6 +29,7 @@ #pragma warning(pop) #endif +#include #include #if HC_PLATFORM_IS_APPLE @@ -104,8 +105,10 @@ bool verify_cert_chain_platform_specific(asio::ssl::verify_context &verifyCtx, c #else verify_result = verify_X509_cert_chain(certChain, hostName); #endif - // The Windows Crypto APIs don't do host name checks, use Boost's implementation. -#if HC_PLATFORM_IS_MICROSOFT + // The platform chain-verify routines (Windows Crypto, Linux X509_verify_cert) don't + // perform host name checks, so apply Boost's RFC 2818 hostname verification to match + // the certificate against the requested host. +#if HC_PLATFORM_IS_MICROSOFT || (HC_PLATFORM == HC_PLATFORM_LINUX) if (verify_result) { asio::ssl::rfc2818_verification rfc2818(hostName.data()); @@ -306,15 +309,16 @@ static bool verify_X509_cert_chain(asio::ssl::verify_context& verifyCtx, const h return false; } - X509_STORE* store = X509_STORE_new(); - X509_STORE_CTX_trusted_stack(storeContext, certStack); - SSL_CTX* sslContext = SSL_CTX_new(TLS_method()); - store = SSL_CTX_get_cert_store(sslContext); - - if (sslContext == NULL) { + std::unique_ptr sslContext{ SSL_CTX_new(TLS_method()), &SSL_CTX_free }; + if (sslContext == nullptr) + { return false; } + X509_STORE_CTX_trusted_stack(storeContext, certStack); + // The cert store is owned by sslContext and freed with it; do not free it separately. + X509_STORE* store = SSL_CTX_get_cert_store(sslContext.get()); + int ret = X509_STORE_set_default_paths(store); if (ret != 1) {