[cpp-sp] 02/02: CPPSP-18 Investigate tlsCipherList for WinHttp
Codeberg
noreply at shibboleth.net
Thu Aug 20 18:43:38 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository cpp-sp.
View the commit online:
https://codeberg.org/Shibboleth/cpp-sp/commit/7748bf71864ad7b695bbb02dfcd8df32154e7932
commit 7748bf71864ad7b695bbb02dfcd8df32154e7932
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Thu Aug 20 14:43:47 2026 +0100
CPPSP-18 Investigate tlsCipherList for WinHttp
https://shibboleth.atlassian.net/browse/CPPSP-18
1) Add support for tlsCipherList and tls13CipherList
2) Add support for enableTls12 and enableTls13
---
shibsp/remoting/impl/WinHTTPRemotingService.cpp | 120 ++++++++++++++++++++++--
1 file changed, 110 insertions(+), 10 deletions(-)
diff --git a/shibsp/remoting/impl/WinHTTPRemotingService.cpp b/shibsp/remoting/impl/WinHTTPRemotingService.cpp
index 05ae2de4..f4eb2603 100644
--- a/shibsp/remoting/impl/WinHTTPRemotingService.cpp
+++ b/shibsp/remoting/impl/WinHTTPRemotingService.cpp
@@ -21,6 +21,7 @@
#include "internal.h"
#include "exceptions.h"
#include <Windows.h>
+#include <schannel.h>
#include <winhttp.h>
#include "Agent.h"
@@ -29,6 +30,7 @@
#include "remoting/SecretSource.h"
#include "remoting/impl/AbstractHTTPRemotingService.h"
#include "util/BoostPropertySet.h"
+#include "util/Misc.h"
#include <stdexcept>
#include <boost/algorithm/string.hpp>
@@ -55,10 +57,14 @@ namespace {
wstring utf8ToUtf16(const char* input) const;
+ string utf16ToUtf8(const wchar_t* input) const;
+
void send(const char* path, istream& input, ostream& output) const;
void handleCert(HINTERNET handle) const;
+ void handleCipher(HINTERNET handle) const;
+
void logSecureFailure(DWORD status) const;
private:
@@ -66,7 +72,6 @@ namespace {
bool m_init;
HINTERNET m_session;
HINTERNET m_connection;
- string m_ciphers;
bool m_secure;
wstring m_baseURLPath;
wstring m_username;
@@ -74,6 +79,8 @@ namespace {
HCERTCHAINENGINE m_caChainEngine;
HCERTSTORE m_caStore;
void setupCaChecking();
+ set<string> m_cipherSet;
+ set<string> m_tls13CipherSet;
string getCertName(PCCERT_CONTEXT certContext) const;
};
@@ -116,6 +123,26 @@ wstring WinHTTPRemotingService::utf8ToUtf16(const char* input) const {
return result;
}
+string WinHTTPRemotingService::utf16ToUtf8(const wchar_t* input) const {
+ DWORD sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, input, -1, nullptr, 0, nullptr, nullptr);
+
+ LPSTR output = new CHAR[sizeNeeded + 1];
+ if (output == nullptr) {
+ m_log.crit("Out of memory allocating %d bytes for conversion buffer", sizeNeeded + 1);
+ throw runtime_error("Utf16toUtf8 conversion failed");
+ }
+ ZeroMemory(output, sizeNeeded + 1);
+
+ if (WideCharToMultiByte(CP_UTF8, 0, input, -1, output, sizeNeeded, nullptr, nullptr) == 0) {
+ m_log.crit("MultiByteToWideChar failure: %d", GetLastError());
+ throw runtime_error("Utf16toUtf8 conversion failed");
+ }
+
+ string result(output);
+ delete[] output;
+ return result;
+}
+
void WinHTTPRemotingService::setupCaChecking() {
if (!getCAFile())
@@ -206,9 +233,12 @@ StatusCallback(
if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDING_REQUEST) {
service->handleCert(hInternet);
+ service->handleCipher(hInternet);
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) {
service->logSecureFailure(*((DWORD*)lpvStatusInformation));
}
+
+
};
WinHTTPRemotingService::WinHTTPRemotingService(ptree& pt)
@@ -216,19 +246,22 @@ WinHTTPRemotingService::WinHTTPRemotingService(ptree& pt)
AbstractHTTPRemotingService(pt),
m_log(Category::getInstance(SHIBSP_LOGCAT ".RemotingService")),
m_secure(false), m_caChainEngine(nullptr), m_caStore(nullptr),
- m_init(false)
+ m_init(false), m_cipherSet(), m_tls13CipherSet()
{
if (getUserAgent() == nullptr) {
string useragent = string(PACKAGE_NAME) + '/' + PACKAGE_VERSION + '/' + "WINHTTP";
setUserAgent(useragent.c_str());
}
- //static const char CIPHER_LIST_PROP_NAME[] = "tlsCipherList";
- static const char CHUNKED_PROP_NAME[] = "chunkedEncoding";
-
+ static const char TLS_12_PROP_NAME[] = "enableTls12";
+ static const char TLS_13_PROP_NAME[] = "enableTls13";
+
BoostPropertySet props;
props.load(pt);
+ bool enableTls12 = props.getBool(TLS_12_PROP_NAME, true);
+ bool enableTls13 = props.getBool(TLS_13_PROP_NAME, true);
+
m_username = utf8ToUtf16(getAgentID());
switch (getAuthMethod()) {
case agent_auth_basic: m_authScheme = WINHTTP_AUTH_SCHEME_BASIC; break;
@@ -247,12 +280,13 @@ WinHTTPRemotingService::WinHTTPRemotingService(ptree& pt)
throw runtime_error("WinHHHTP failed to initialize service (WinHttpOpen)");
}
+ split_to_container(m_cipherSet, getCiphers().c_str());
+ split_to_container(m_tls13CipherSet, getTls13Ciphers().c_str());
//
// Set up our CaPath environment
//
setupCaChecking();
-
//
// Pop the URL into a wstring which we can parse and then point
// other wstring constructors at
@@ -288,7 +322,7 @@ WinHTTPRemotingService::WinHTTPRemotingService(ptree& pt)
}
m_secure = (components.nScheme == INTERNET_SCHEME_HTTPS);
- if (m_secure && (m_caChainEngine != NULL)) {
+ if (m_secure) {
//
// Arrange to be called back so we can check certificates
//
@@ -299,12 +333,30 @@ WinHTTPRemotingService::WinHTTPRemotingService(ptree& pt)
m_log.crit("WinHttpSetOption failure: %d", GetLastError());
throw runtime_error("WinHHHTP failed to initialize: Could not set callback option");
}
+ DWORD flags = WINHTTP_CALLBACK_STATUS_SENDING_REQUEST |
+ WINHTTP_CALLBACK_STATUS_SECURE_FAILURE;
// And register the callback
- if (WinHttpSetStatusCallback(m_session, StatusCallback, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_SECURE_FAILURE, NULL) == WINHTTP_INVALID_STATUS_CALLBACK) {
+ if (WinHttpSetStatusCallback(m_session, StatusCallback, flags, NULL) == WINHTTP_INVALID_STATUS_CALLBACK) {
m_log.crit("WinHttpSetStatusCallback failure: %d", GetLastError());
throw runtime_error("WinHHHTP failed to initialize: Could not register callback");
}
+
+ flags = 0;
+ if (enableTls12)
+ flags |= WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
+ if (enableTls13)
+ flags |= WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3;
+
+ if (flags) {
+ if (!WinHttpSetOption(m_session, WINHTTP_OPTION_SECURE_PROTOCOLS, &flags, sizeof(flags))) {
+ m_log.crit("WinHttpSetOption failure: %d", GetLastError());
+ throw runtime_error("WinHHHTP failed to initialize: Could not set tls options");
+ }
+ } else {
+ // both set to false == use machine defaults
+ // https://learn.microsoft.com/en-us/windows-server/networking/configure-secure-protocol-options-winhttp
+ }
}
wstring host(components.lpszHostName, components.dwHostNameLength);
@@ -568,6 +620,52 @@ void WinHTTPRemotingService::logSecureFailure(DWORD Status) const
m_log.crit("WinHttp Security Error 0x%x (%s)", Status, details.c_str());
}
+
+
+//
+// Called during WinHttpSendRequest to allow us to police the cipher.
+//
+void WinHTTPRemotingService::handleCipher(HINTERNET handle) const
+{
+ if (m_tls13CipherSet.empty() && m_cipherSet.empty())
+ return;
+
+ WINHTTP_SECURITY_INFO secinfo;
+ DWORD len = sizeof(secinfo);
+ if (!WinHttpQueryOption(handle, WINHTTP_OPTION_SECURITY_INFO, &secinfo, &len)) {
+ m_log.crit("Could not get the securty info on connect %d", GetLastError());
+ throw RemotingException("Could not get securty info");
+ }
+ string cipher(utf16ToUtf8(secinfo.CipherInfo.szCipherSuite));
+ if (cipher.empty())
+ return;
+
+ m_log.debug("cipher presented : {} ", cipher);
+
+ if (secinfo.ConnectionInfo.dwProtocol == SP_PROT_TLS1_2_CLIENT) {
+ if (m_cipherSet.count(cipher)) {
+ // match, nothing to do
+ return;
+ }
+ m_log.crit("Cipher {} not enabled for TLS1.2", cipher);
+ throw RemotingException("Cipher not enabled");
+ }
+
+ if (secinfo.ConnectionInfo.dwProtocol == SP_PROT_TLS1_3_CLIENT) {
+ if (m_tls13CipherSet.count(cipher)) {
+ // match, nothing to do
+ return;
+ }
+ m_log.crit("Cipher {} not enabled for TLS1.3", cipher);
+ throw RemotingException("Cipher not enabled");
+
+ }
+ //
+ // Nothing else to do
+ //
+}
+
+
//
// Called during WinHttpSendRequest to allow us to police the certificate.
//
@@ -576,10 +674,12 @@ void WinHTTPRemotingService::handleCert(HINTERNET handle) const
PCCERT_CONTEXT certCtx = NULL;
DWORD size = sizeof(certCtx);
+ if (m_caChainEngine == NULL)
+ return;
+
if (!WinHttpQueryOption(handle, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &certCtx, &size)) {
- m_log.crit("Could not get the certificate on connect");
+ m_log.crit("Could not get the certificate on connect %d", GetLastError());
throw RemotingException("Could not get certificate");
-
}
if (m_log.isDebugEnabled()) {
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list