11#include <QtNetwork/private/qsslcertificate_p.h>
12#include <QtNetwork/private/qsslcipher_p.h>
13#include <QtNetwork/private/qssl_p.h>
15#include <QtNetwork/qsslcertificate.h>
16#include <QtNetwork/qsslcertificateextension.h>
17#include <QtNetwork/qsslsocket.h>
19#include <QtCore/qscopeguard.h>
20#include <QtCore/qoperatingsystemversion.h>
21#include <QtCore/qregularexpression.h>
22#include <QtCore/qdatastream.h>
23#include <QtCore/qmutex.h>
29#if NTDDI_VERSION >= NTDDI_WINBLUE && !defined(Q_CC_MINGW)
31#define SUPPORTS_ALPN 1
35#ifndef SECBUFFER_ALERT
36#define SECBUFFER_ALERT 17
38#ifndef SECPKG_ATTR_APPLICATION_PROTOCOL
39#define SECPKG_ATTR_APPLICATION_PROTOCOL 35
43#ifndef SEC_E_APPLICATION_PROTOCOL_MISMATCH
44#define SEC_E_APPLICATION_PROTOCOL_MISMATCH _HRESULT_TYPEDEF_(0x80090367L)
48#ifndef SP_PROT_TLS1_SERVER
49#define SP_PROT_TLS1_SERVER 0x00000040
51#ifndef SP_PROT_TLS1_CLIENT
52#define SP_PROT_TLS1_CLIENT 0x00000080
54#ifndef SP_PROT_TLS1_0_SERVER
55#define SP_PROT_TLS1_0_SERVER SP_PROT_TLS1_SERVER
57#ifndef SP_PROT_TLS1_0_CLIENT
58#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
61#define SP_PROT_TLS1_0 (SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER)
63#ifndef SP_PROT_TLS1_1_SERVER
64#define SP_PROT_TLS1_1_SERVER 0x00000100
66#ifndef SP_PROT_TLS1_1_CLIENT
67#define SP_PROT_TLS1_1_CLIENT 0x00000200
70#define SP_PROT_TLS1_1 (SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER)
72#ifndef SP_PROT_TLS1_2_SERVER
73#define SP_PROT_TLS1_2_SERVER 0x00000400
75#ifndef SP_PROT_TLS1_2_CLIENT
76#define SP_PROT_TLS1_2_CLIENT 0x00000800
79#define SP_PROT_TLS1_2 (SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER)
81#ifndef SP_PROT_TLS1_3_SERVER
82#define SP_PROT_TLS1_3_SERVER 0x00001000
84#ifndef SP_PROT_TLS1_3_CLIENT
85#define SP_PROT_TLS1_3_CLIENT 0x00002000
88#define SP_PROT_TLS1_3 (SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER)
90#ifndef BCRYPT_ECDH_ALGORITHM
91#define BCRYPT_ECDH_ALGORITHM L"ECDH"
93#ifndef BCRYPT_ECDSA_ALGORITHM
94#define BCRYPT_ECDSA_ALGORITHM L"ECDSA"
156 {
"TLS_AES_256_GCM_SHA384",
"TLS_AES_256_GCM_SHA384",
"",
"",
"AES", 256,
"SHA384", {
QSsl::TlsV1_3}},
157 {
"TLS_AES_128_GCM_SHA256",
"TLS_AES_128_GCM_SHA256",
"",
"",
"AES", 128,
"SHA256", {
QSsl::TlsV1_3}},
158 {
"ECDHE-ECDSA-AES256-GCM-SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"ECDH",
"ECDSA",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
159 {
"ECDHE-ECDSA-AES128-GCM-SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"ECDH",
"ECDSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
160 {
"ECDHE-RSA-AES256-GCM-SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"ECDH",
"RSA",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
161 {
"ECDHE-RSA-AES128-GCM-SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"ECDH",
"RSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
162 {
"DHE-RSA-AES256-GCM-SHA384",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"DH",
"RSA",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
163 {
"DHE-RSA-AES128-GCM-SHA256",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"DH",
"RSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
164 {
"ECDHE-ECDSA-AES256-SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"ECDH",
"ECDSA",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
165 {
"ECDHE-ECDSA-AES128-SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"ECDH",
"ECDSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
166 {
"ECDHE-RSA-AES256-SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"ECDH",
"RSA",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
167 {
"ECDHE-RSA-AES128-SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"ECDH",
"RSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
168 {
"ECDHE-ECDSA-AES256-SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"ECDH",
"ECDSA",
"AES", 256,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
169 {
"ECDHE-ECDSA-AES128-SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"ECDH",
"ECDSA",
"AES", 128,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
170 {
"ECDHE-RSA-AES256-SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"ECDH",
"RSA",
"AES", 256,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
171 {
"ECDHE-RSA-AES128-SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"ECDH",
"RSA",
"AES", 128,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
172 {
"AES256-GCM-SHA384",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"RSA",
"RSA",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
173 {
"AES128-GCM-SHA256",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"RSA",
"RSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
174 {
"AES256-SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"RSA",
"RSA",
"AES", 256,
"SHA256", {
QSsl::TlsV1_2}},
175 {
"AES128-SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"RSA",
"RSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
176 {
"AES256-SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"RSA",
"RSA",
"AES", 256,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
177 {
"AES128-SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"RSA",
"RSA",
"AES", 128,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
178 {
"DES-CBC3-SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"RSA",
"RSA",
"3DES", 168,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
179 {
"NULL-SHA256",
"TLS_RSA_WITH_NULL_SHA256",
"RSA",
"RSA",
"", 0,
"SHA256", {
QSsl::TlsV1_2}},
180 {
"NULL-SHA",
"TLS_RSA_WITH_NULL_SHA",
"RSA",
"RSA",
"", 0,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
183 {
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_CHACHA20_POLY1305_SHA256",
"",
"",
"CHACHA20_POLY1305", 0,
"", {
QSsl::TlsV1_3}},
184 {
"DHE-RSA-AES256-SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"DH",
"RSA",
"AES", 256,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
185 {
"DHE-RSA-AES128-SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"DH",
"RSA",
"AES", 128,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
186 {
"DHE-DSS-AES256-SHA256",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
"DH",
"DSA",
"AES", 256,
"SHA256", {
QSsl::TlsV1_2}},
187 {
"DHE-DSS-AES128-SHA256",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
"DH",
"DSA",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
188 {
"DHE-DSS-AES256-SHA",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"DH",
"DSA",
"AES", 256,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
189 {
"DHE-DSS-AES128-SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"DH",
"DSA",
"AES", 128,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
190 {
"EDH-DSS-DES-CBC3-SHA",
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"DH",
"DSA",
"3DES", 168,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
191 {
"RC4-SHA",
"TLS_RSA_WITH_RC4_128_SHA",
"RSA",
"RSA",
"RC4", 128,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
192 {
"RC4-MD5",
"TLS_RSA_WITH_RC4_128_MD5",
"RSA",
"RSA",
"RC4", 128,
"MD5", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
193 {
"DES-CBC-SHA",
"TLS_RSA_WITH_DES_CBC_SHA",
"RSA",
"RSA",
"DES", 56,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
194 {
"EDH-DSS-DES-CBC-SHA",
"TLS_DHE_DSS_WITH_DES_CBC_SHA",
"DH",
"DSA",
"DES", 56,
"SHA1", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
195 {
"NULL-MD5",
"TLS_RSA_WITH_NULL_MD5",
"RSA",
"RSA",
"", 0,
"MD5", {
QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
198 {
"PSK-AES256-GCM-SHA384",
"TLS_PSK_WITH_AES_256_GCM_SHA384",
"PSK",
"",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
199 {
"PSK-AES128-GCM-SHA256",
"TLS_PSK_WITH_AES_128_GCM_SHA256",
"PSK",
"",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
200 {
"PSK-AES256-CBC-SHA384",
"TLS_PSK_WITH_AES_256_CBC_SHA384",
"PSK",
"",
"AES", 256,
"SHA384", {
QSsl::TlsV1_2}},
201 {
"PSK-AES128-CBC-SHA256",
"TLS_PSK_WITH_AES_128_CBC_SHA256",
"PSK",
"",
"AES", 128,
"SHA256", {
QSsl::TlsV1_2}},
202 {
"PSK-NULL-SHA384",
"TLS_PSK_WITH_NULL_SHA384",
"PSK",
"",
"", 0,
"SHA384", {
QSsl::TlsV1_2}},
203 {
"PSK-NULL-SHA256",
"TLS_PSK_WITH_NULL_SHA256",
"PSK",
"",
"", 0,
"SHA256", {
QSsl::TlsV1_2}},
218 sizeof(BCRYPT_CHAIN_MODE_CBC) - 2,
219 sizeof(BCRYPT_CHAIN_MODE_CBC),
220 const_cast<PWSTR
>(BCRYPT_CHAIN_MODE_CBC)
224 sizeof(BCRYPT_CHAIN_MODE_GCM) - 2,
225 sizeof(BCRYPT_CHAIN_MODE_GCM),
226 const_cast<PWSTR
>(BCRYPT_CHAIN_MODE_GCM)
237 if (defaultCipherList == ciphers) {
244 for (
const auto &cipher : ciphers) {
255 const auto assignUnicodeString = [](UNICODE_STRING &unicodeString,
const wchar_t *
characters) {
256 unicodeString.Length =
static_cast<USHORT
>(wcslen(
characters) *
sizeof(WCHAR));
257 unicodeString.MaximumLength = unicodeString.Length +
sizeof(UNICODE_NULL);
258 unicodeString.Buffer =
const_cast<wchar_t*
>(
characters);
262 const auto allKeyExchangeAlgorithms = {BCRYPT_RSA_ALGORITHM,
264 BCRYPT_DH_ALGORITHM};
266 for (
const auto &algorithm : allKeyExchangeAlgorithms) {
273 const bool exclude = std::none_of(cipherInfo.
cbegin(), cipherInfo.
cend(), usesMethod);
277 settings.eAlgorithmUsage = TlsParametersCngAlgUsageKeyExchange;
278 assignUnicodeString(
settings.strCngAlgId, algorithm);
284 const auto allAuthenticationAlgorithms = {BCRYPT_RSA_ALGORITHM,
285 BCRYPT_DSA_ALGORITHM,
287 BCRYPT_DH_ALGORITHM};
289 for (
const auto &algorithm : allAuthenticationAlgorithms) {
296 const bool exclude = std::none_of(cipherInfo.
begin(), cipherInfo.
end(), usesMethod);
300 settings.eAlgorithmUsage = TlsParametersCngAlgUsageSignature;
301 assignUnicodeString(
settings.strCngAlgId, algorithm);
308 const auto allEncryptionAlgorithms = {BCRYPT_AES_ALGORITHM,
309 BCRYPT_RC4_ALGORITHM,
310 BCRYPT_DES_ALGORITHM,
311 BCRYPT_3DES_ALGORITHM};
313 for (
const auto &algorithm : allEncryptionAlgorithms) {
317 bool uses128Bit =
false;
318 bool uses256Bit =
false;
319 bool usesGcm =
false;
320 bool usesCbc =
false;
321 for (
const auto *
info : cipherInfo) {
323 uses128Bit = uses128Bit || (
info->encryptionBits == 128);
324 uses256Bit = uses256Bit || (
info->encryptionBits == 256);
333 settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
334 assignUnicodeString(
settings.strCngAlgId, algorithm);
336 if (usesGcm && !usesCbc) {
339 }
else if (!usesGcm && usesCbc) {
344 if (!uses128Bit && uses256Bit) {
347 }
else if (uses128Bit && !uses256Bit) {
350 }
else if (!uses128Bit && !uses256Bit) {
358 const bool exclude = std::none_of(cipherInfo.
begin(), cipherInfo.
end(), usesMethod);
362 settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
363 assignUnicodeString(
settings.strCngAlgId, algorithm);
370 const auto allHashAlgorithms = {BCRYPT_MD5_ALGORITHM,
371 BCRYPT_SHA1_ALGORITHM,
372 BCRYPT_SHA256_ALGORITHM,
373 BCRYPT_SHA384_ALGORITHM};
375 for (
const auto &algorithm : allHashAlgorithms) {
382 const bool exclude = std::none_of(cipherInfo.
begin(), cipherInfo.
end(), usesMethod);
386 settings.eAlgorithmUsage = TlsParametersCngAlgUsageDigest;
387 assignUnicodeString(
settings.strCngAlgId, algorithm);
392 return cryptoSettings;
401 for (
const auto &protocol : cipher.protocols) {
416 cipher.encryptionBits,
417 protocol, protocolName));
427 ULONG contextFunctionsCount = {};
428 PCRYPT_CONTEXT_FUNCTIONS contextFunctions = {};
430 const auto status = BCryptEnumContextFunctions(CRYPT_LOCAL, L
"SSL", NCRYPT_SCHANNEL_INTERFACE,
431 &contextFunctionsCount, &contextFunctions);
432 if (!NT_SUCCESS(status)) {
433 qCWarning(lcTlsBackendSchannel,
"Failed to enumerate ciphers");
437 const bool supportsV13 = supportsTls13();
442 const auto suiteName =
QStringView(contextFunctions->rgpszFunctions[
index]);
446 for (
const auto &cipher : allCiphers) {
454 BCryptFreeBuffer(contextFunctions);
461 return std::any_of(ciphers.
cbegin(), ciphers.
cend(),
462 [](
const QSslCipher &cipher) { return cipher.protocol() == QSsl::TlsV1_3; });
467bool QSchannelBackend::s_loadedCiphersAndCerts =
false;
473 return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
479 return "Secure Channel, %1 %2.%3.%4"_L1
493 return "Secure Channel (NTDDI: 0x%1)"_L1
505 if (s_loadedCiphersAndCerts)
507 s_loadedCiphersAndCerts =
true;
509 setDefaultCaCertificates(systemCaCertificatesImplementation());
513 resetDefaultCiphers();
516void QSchannelBackend::resetDefaultCiphers()
535 protocols << QSsl::TlsV1_0;
536 protocols << QSsl::TlsV1_0OrLater;
537 protocols << QSsl::TlsV1_1;
538 protocols << QSsl::TlsV1_1OrLater;
543 if (supportsTls13()) {
586 return systemCaCertificatesImplementation();
601 PCCERT_CONTEXT pc =
nullptr;
602 while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
603 CERT_FIND_ANY,
nullptr, pc))) {
627SecBuffer createSecBuffer(
void *
ptr,
unsigned long length,
unsigned long bufferType)
629 return SecBuffer{
length, bufferType,
ptr };
634 return createSecBuffer(
buffer.data(),
static_cast<unsigned long>(
buffer.length()), bufferType);
640 case SEC_E_INSUFFICIENT_MEMORY:
641 return QSslSocket::tr(
"Insufficient memory");
642 case SEC_E_INTERNAL_ERROR:
643 return QSslSocket::tr(
"Internal error");
644 case SEC_E_INVALID_HANDLE:
645 return QSslSocket::tr(
"An internal handle was invalid");
646 case SEC_E_INVALID_TOKEN:
647 return QSslSocket::tr(
"An internal token was invalid");
648 case SEC_E_LOGON_DENIED:
651 return QSslSocket::tr(
"Access denied");
652 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
653 return QSslSocket::tr(
"No authority could be contacted for authorization");
654 case SEC_E_NO_CREDENTIALS:
655 return QSslSocket::tr(
"No credentials");
656 case SEC_E_TARGET_UNKNOWN:
657 return QSslSocket::tr(
"The target is unknown or unreachable");
658 case SEC_E_UNSUPPORTED_FUNCTION:
659 return QSslSocket::tr(
"An unsupported function was requested");
660 case SEC_E_WRONG_PRINCIPAL:
662 return QSslSocket::tr(
"The hostname provided does not match the one received from the peer");
664 return QSslSocket::tr(
"No common protocol exists between the client and the server");
665 case SEC_E_ILLEGAL_MESSAGE:
666 return QSslSocket::tr(
"Unexpected or badly-formatted message received");
667 case SEC_E_ENCRYPT_FAILURE:
668 return QSslSocket::tr(
"The data could not be encrypted");
669 case SEC_E_ALGORITHM_MISMATCH:
670 return QSslSocket::tr(
"No cipher suites in common");
671 case SEC_E_UNKNOWN_CREDENTIALS:
673 return QSslSocket::tr(
"The credentials were not recognized / Invalid argument");
674 case SEC_E_MESSAGE_ALTERED:
677 return QSslSocket::tr(
"The message was tampered with, damaged or out of sequence.");
678 case SEC_E_OUT_OF_SEQUENCE:
679 return QSslSocket::tr(
"A message was received out of sequence.");
680 case SEC_E_CONTEXT_EXPIRED:
681 return QSslSocket::tr(
"The TLS/SSL connection has been closed");
683 return QSslSocket::tr(
"Unknown error occurred: %1").arg(status);
689 static bool supported = []() {
702 DWORD protocols = SP_PROT_NONE;
709 case QSsl::DtlsV1_0OrLater:
735 protocols = DWORD(-1);
739 case QSsl::TlsV1_0OrLater:
744 case QSsl::TlsV1_1OrLater:
756 protocols = DWORD(-1);
765DWORD negatedSchannelProtocols(DWORD wantedProtocols)
767 DWORD protocols = SP_PROT_ALL;
768 protocols &= ~wantedProtocols;
781#define MAP_PROTOCOL(sp_protocol, q_protocol) \
782 if (protocol & sp_protocol) { \
783 Q_ASSERT(!(protocol & ~sp_protocol)); \
805 const auto netscapeIt = std::find_if(
808 const auto netscapeCertType = QStringLiteral(
"2.16.840.1.113730.1.1");
809 return extension.oid() == netscapeCertType;
811 if (netscapeIt != extensions.
cend()) {
812 const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
813 int netscapeCertType = 0;
815 dataStream >> netscapeCertType;
818 const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
819 : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
820 if ((netscapeCertType & expectedPeerCertType) == 0)
835 auto it = std::find_if(extensions.
cbegin(), extensions.
cend(),
837 return extension.name() ==
"basicConstraints"_L1;
839 if (
it != extensions.
cend()) {
841 return basicConstraints.
value(
"ca"_L1,
false).
toBool();
851bool matchesContextRequirements(DWORD attributes, DWORD requirements,
855#ifdef QSSLSOCKET_DEBUG
856#define DEBUG_WARN(message) qCWarning(lcTlsBackendSchannel, message)
858#define DEBUG_WARN(message)
861#define CHECK_ATTRIBUTE(attributeName) \
863 const DWORD req##attributeName = isClient ? ISC_REQ_##attributeName : ASC_REQ_##attributeName; \
864 const DWORD ret##attributeName = isClient ? ISC_RET_##attributeName : ASC_RET_##attributeName; \
865 if (!(requirements & req##attributeName) != !(attributes & ret##attributeName)) { \
866 DEBUG_WARN("Missing attribute \"" #attributeName "\""); \
880 const auto reqManualCredValidation = ISC_REQ_MANUAL_CRED_VALIDATION;
881 const auto retManualCredValidation = ISC_RET_MANUAL_CRED_VALIDATION;
882 if (!(requirements & reqManualCredValidation) != !(attributes & retManualCredValidation)) {
883 DEBUG_WARN(
"Missing attribute \"MANUAL_CRED_VALIDATION\"");
889#undef CHECK_ATTRIBUTE
893template<
typename Required,
typename Actual>
894Required const_reinterpret_cast(Actual *
p)
903 if (!nextAllowedProtocols.isEmpty()) {
906 for (
QByteArray proto : nextAllowedProtocols) {
907 if (proto.size() > 255) {
909 <<
"TLS ALPN extension" << proto <<
"is too long and will be ignored.";
911 }
else if (proto.isEmpty()) {
914 protocolString += char(proto.length()) + proto;
916 return protocolString;
922 const quint32 alpnId = SecApplicationProtocolNegotiationExt_ALPN;
923 const quint32 totalSize =
sizeof(alpnId) +
sizeof(namesSize) + namesSize;
936 static const qint64 shrinkCutoff = 1024 * 12;
937 static const qint64 defaultRead = 1024 * 16;
940 const auto toRead = std::min(defaultRead, plainSocket->
bytesAvailable());
942 const auto bufferSize =
buffer.size();
943 buffer.reserve(bufferSize + toRead);
944 buffer.resize(bufferSize + toRead);
945 bytesRead = plainSocket->
read(
buffer.data() + bufferSize, toRead);
946 buffer.resize(bufferSize + bytesRead);
948 if (
buffer.size() < shrinkCutoff &&
buffer.capacity() > defaultRead)
957 Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
958 if (
int(secBuffer.cbBuffer) >=
buffer.size())
961#ifdef QSSLSOCKET_DEBUG
962 qCDebug(lcTlsBackendSchannel,
"We got SECBUFFER_EXTRA, will retain %lu bytes",
966 buffer.resize(secBuffer.cbBuffer);
969qint64 checkIncompleteData(
const SecBuffer &secBuffer)
971 if (secBuffer.BufferType == SECBUFFER_MISSING) {
972#ifdef QSSLSOCKET_DEBUG
973 qCDebug(lcTlsBackendSchannel,
"Need %lu more bytes.", secBuffer.cbBuffer);
975 return secBuffer.cbBuffer;
980DWORD defaultCredsFlag()
991 SecInvalidateHandle(&credentialHandle);
992 SecInvalidateHandle(&contextHandle);
998 closeCertificateStores();
1000 freeCredentialsHandle();
1001 CertFreeCertificateContext(localCertContext);
1015bool TlsCryptographSchannel::sendToken(
void *
token,
unsigned long tokenLength,
bool emitError)
1017 if (tokenLength == 0)
1024 const qint64 written = plainSocket->
write(
static_cast<const char *
>(
token), tokenLength);
1025 if (written !=
qint64(tokenLength)) {
1034QString TlsCryptographSchannel::targetName()
const
1041 return verificationPeerName.
isEmpty() ?
q->peerName() : verificationPeerName;
1044ULONG TlsCryptographSchannel::getContextRequirements()
1052 req |= ISC_REQ_ALLOCATE_MEMORY;
1053 req |= ISC_REQ_CONFIDENTIALITY;
1054 req |= ISC_REQ_REPLAY_DETECT;
1055 req |= ISC_REQ_SEQUENCE_DETECT;
1056 req |= ISC_REQ_STREAM;
1059 req |= ISC_REQ_MANUAL_CRED_VALIDATION;
1061 switch (
q->peerVerifyMode()) {
1068 req |= ISC_REQ_MUTUAL_AUTH;
1076bool TlsCryptographSchannel::acquireCredentialsHandle()
1080 const auto &configuration =
q->sslConfiguration();
1082 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1085 DWORD protocols = toSchannelProtocol(configuration.protocol());
1086 if (protocols == DWORD(-1)) {
1088 QSslSocket::tr(
"Invalid protocol chosen"));
1092 const CERT_CHAIN_CONTEXT *chainContext =
nullptr;
1093 auto freeCertChain =
qScopeGuard([&chainContext]() {
1095 CertFreeCertificateChain(chainContext);
1098 DWORD certsCount = 0;
1100 initializeCertificateStores();
1105 if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
1108 if (localCertificateStore !=
nullptr) {
1109 CERT_CHAIN_FIND_BY_ISSUER_PARA findParam;
1110 ZeroMemory(&findParam,
sizeof(findParam));
1111 findParam.cbSize =
sizeof(findParam);
1112 findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH;
1115 chainContext = CertFindChainInStore(localCertificateStore.get(),
1118 CERT_CHAIN_FIND_BY_ISSUER,
1121 if (!chainContext) {
1123 ? QSslSocket::tr(
"The certificate provided cannot be used for a client.")
1124 :
QSslSocket::
tr(
"The certificate provided cannot be used for a server.");
1128 Q_ASSERT(chainContext->cChain == 1);
1129 Q_ASSERT(chainContext->rgpChain[0]);
1130 Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1);
1131 Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]);
1133 localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0]
1142 protocols &= ~SP_PROT_TLS1_3;
1146 TLS_PARAMETERS tlsParameters = {
1149 negatedSchannelProtocols(protocols),
1150 static_cast<DWORD
>(cryptoSettings.
size()),
1155 SCH_CREDENTIALS credentials = {
1156 SCH_CREDENTIALS_VERSION,
1164 SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(),
1169 TimeStamp expiration{};
1170 auto status = AcquireCredentialsHandle(
nullptr,
1171 const_cast<wchar_t *
>(UNISP_NAME),
1172 isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND,
1181 if (status != SEC_E_OK) {
1188void TlsCryptographSchannel::deallocateContext()
1190 if (SecIsValidHandle(&contextHandle)) {
1191 DeleteSecurityContext(&contextHandle);
1192 SecInvalidateHandle(&contextHandle);
1196void TlsCryptographSchannel::freeCredentialsHandle()
1198 if (SecIsValidHandle(&credentialHandle)) {
1199 FreeCredentialsHandle(&credentialHandle);
1200 SecInvalidateHandle(&credentialHandle);
1204void TlsCryptographSchannel::closeCertificateStores()
1206 localCertificateStore.reset();
1207 peerCertificateStore.reset();
1208 caCertificateStore.reset();
1211bool TlsCryptographSchannel::createContext()
1216 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1217 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1219 ULONG contextReq = getContextRequirements();
1221 SecBuffer outBuffers[3];
1222 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1224 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1226 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1227 if (outBuffers[
i].pvBuffer)
1228 FreeContextBuffer(outBuffers[
i].pvBuffer);
1231 SecBufferDesc outputBufferDesc{
1233 ARRAYSIZE(outBuffers),
1239 SecBufferDesc alpnBufferDesc;
1240 bool useAlpn =
false;
1243 QByteArray alpnString = createAlpnString(
q->sslConfiguration().allowedNextProtocols());
1244 useAlpn = !alpnString.
isEmpty();
1245 SecBuffer alpnBuffers[1];
1246 alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1249 ARRAYSIZE(alpnBuffers),
1254 auto status = InitializeSecurityContext(&credentialHandle,
1256 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1260 useAlpn ? &alpnBufferDesc :
nullptr,
1270 if (status != SEC_I_CONTINUE_NEEDED) {
1272 QSslSocket::tr(
"Error creating SSL context (%1)").
arg(schannelErrorToString(status)));
1276 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1278 schannelState = SchannelState::PerformHandshake;
1282bool TlsCryptographSchannel::acceptContext()
1290 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1291 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1293 ULONG contextReq = getContextRequirements();
1299 readToBuffer(intermediateBuffer, plainSocket);
1300 if (intermediateBuffer.
isEmpty())
1303 SecBuffer inBuffers[2];
1304 inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1309 QByteArray alpnString = createAlpnString(
q->sslConfiguration().allowedNextProtocols());
1311 inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1315 inBuffers[1] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1318 SecBufferDesc inputBufferDesc{
1320 ARRAYSIZE(inBuffers),
1324 SecBuffer outBuffers[3];
1325 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1327 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1329 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1330 if (outBuffers[
i].pvBuffer)
1331 FreeContextBuffer(outBuffers[
i].pvBuffer);
1334 SecBufferDesc outputBufferDesc{
1336 ARRAYSIZE(outBuffers),
1341 auto status = AcceptSecurityContext(
1353 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1355 missingData = checkIncompleteData(outBuffers[0]);
1359 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
1363 retainExtraData(intermediateBuffer, inBuffers[1]);
1365 intermediateBuffer.
resize(0);
1368 if (status != SEC_I_CONTINUE_NEEDED) {
1370 QSslSocket::tr(
"Error creating SSL context (%1)").
arg(schannelErrorToString(status)));
1373 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1375 schannelState = SchannelState::PerformHandshake;
1379bool TlsCryptographSchannel::performHandshake()
1387 QSslSocket::tr(
"The TLS/SSL connection has been closed"));
1390 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1391 Q_ASSERT(SecIsValidHandle(&contextHandle));
1392 Q_ASSERT(schannelState == SchannelState::PerformHandshake);
1394#ifdef QSSLSOCKET_DEBUG
1395 qCDebug(lcTlsBackendSchannel,
"Bytes available from socket: %lld",
1397 qCDebug(lcTlsBackendSchannel,
"intermediateBuffer size: %d", intermediateBuffer.
size());
1404 readToBuffer(intermediateBuffer, plainSocket);
1405 if (intermediateBuffer.
isEmpty())
1408 SecBuffer outBuffers[3] = {};
1409 const auto freeOutBuffers = [&outBuffers]() {
1410 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1411 if (outBuffers[
i].pvBuffer)
1412 FreeContextBuffer(outBuffers[
i].pvBuffer);
1415 const auto outBuffersGuard =
qScopeGuard(freeOutBuffers);
1421 SECURITY_STATUS status;
1424 SecBuffer inputBuffers[2];
1425 inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1426 inputBuffers[1] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1427 SecBufferDesc inputBufferDesc{
1429 ARRAYSIZE(inputBuffers),
1434 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1436 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1437 SecBufferDesc outputBufferDesc{
1439 ARRAYSIZE(outBuffers),
1443 ULONG contextReq = getContextRequirements();
1445 status = InitializeSecurityContext(
1448 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1460 if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
1464 retainExtraData(intermediateBuffer, inputBuffers[1]);
1465 }
else if (status != SEC_E_INCOMPLETE_MESSAGE) {
1467 intermediateBuffer.
resize(0);
1471 }
while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
1476 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1478 schannelState = SchannelState::VerifyHandshake;
1480 case SEC_I_CONTINUE_NEEDED:
1481 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1485 case SEC_I_INCOMPLETE_CREDENTIALS:
1489 QSslSocket::tr(
"Server did not accept any certificate we could present."));
1491 case SEC_I_CONTEXT_EXPIRED:
1493 if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
1494 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1499 QSslSocket::tr(
"The TLS/SSL connection has been closed"));
1502 case SEC_E_INCOMPLETE_MESSAGE:
1504 missingData = checkIncompleteData(outBuffers[0]);
1506 case SEC_E_ALGORITHM_MISMATCH:
1508 QSslSocket::tr(
"Algorithm mismatch"));
1517 QSslSocket::tr(
"Handshake failed: %1").
arg(schannelErrorToString(status)));
1521bool TlsCryptographSchannel::verifyHandshake()
1525 const auto &configuration =
q->sslConfiguration();
1530#define CHECK_STATUS(status) \
1531 if (status != SEC_E_OK) { \
1532 setErrorAndEmit(d, QAbstractSocket::SslInternalError, \
1533 QSslSocket::tr("Failed to query the TLS context: %1") \
1534 .arg(schannelErrorToString(status))); \
1539 if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
1540 configuration.peerVerifyMode(), isClient)) {
1542 QSslSocket::tr(
"Did not get the required attributes for the connection."));
1547 auto status = QueryContextAttributes(&contextHandle,
1548 SECPKG_ATTR_STREAM_SIZES,
1553 status = QueryContextAttributes(&contextHandle,
1554 SECPKG_ATTR_CIPHER_INFO,
1558 status = QueryContextAttributes(&contextHandle,
1559 SECPKG_ATTR_CONNECTION_INFO,
1564 const auto allowedProtos = configuration.allowedNextProtocols();
1565 if (!allowedProtos.isEmpty()) {
1566 SecPkgContext_ApplicationProtocol alpn;
1567 status = QueryContextAttributes(&contextHandle,
1571 if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
1573 alpn.ProtocolIdSize);
1574 if (!allowedProtos.contains(negotiatedProto)) {
1576 QSslSocket::tr(
"Unwanted protocol was negotiated"));
1579 QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
1582 QTlsBackend::setNegotiatedProtocol(d, {});
1591 CERT_CONTEXT *certificateContext =
nullptr;
1592 auto freeCertificate =
qScopeGuard([&certificateContext]() {
1593 if (certificateContext)
1594 CertFreeCertificateContext(certificateContext);
1596 status = QueryContextAttributes(&contextHandle,
1597 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1598 &certificateContext);
1608 if (status != SEC_E_OK) {
1609#ifdef QSSLSOCKET_DEBUG
1610 qCDebug(lcTlsBackendSchannel) <<
"Couldn't retrieve peer certificate, status:"
1611 << schannelErrorToString(status);
1622 if (certificateContext && !verifyCertContext(certificateContext))
1626#ifdef QSSLSOCKET_DEBUG
1627 qCDebug(lcTlsBackendSchannel) << __func__ <<
"was unsuccessful. Paused:" << d->
isPaused();
1633 schannelState = SchannelState::Done;
1637bool TlsCryptographSchannel::renegotiate()
1641 SecBuffer outBuffers[3];
1642 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1644 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1646 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1647 if (outBuffers[
i].pvBuffer)
1648 FreeContextBuffer(outBuffers[
i].pvBuffer);
1651 SecBufferDesc outputBufferDesc{
1653 ARRAYSIZE(outBuffers),
1657 ULONG contextReq = getContextRequirements();
1659 SECURITY_STATUS status;
1661 status = InitializeSecurityContext(&credentialHandle,
1663 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1675 status = AcceptSecurityContext(
1687 if (status == SEC_I_CONTINUE_NEEDED) {
1688 schannelState = SchannelState::PerformHandshake;
1689 return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
1690 }
else if (status == SEC_E_OK) {
1691 schannelState = SchannelState::PerformHandshake;
1695 QSslSocket::tr(
"Renegotiation was unsuccessful: %1").
arg(schannelErrorToString(status)));
1703void TlsCryptographSchannel::reset()
1707 closeCertificateStores();
1708 deallocateContext();
1709 freeCredentialsHandle();
1712 connectionInfo = {};
1715 CertFreeCertificateContext(localCertContext);
1716 localCertContext =
nullptr;
1718 contextAttributes = 0;
1719 intermediateBuffer.
clear();
1720 schannelState = SchannelState::InitializeHandshake;
1725 renegotiating =
false;
1734 if (
q->isEncrypted())
1744 if (
q->isEncrypted())
1764 if (schannelState != SchannelState::Done) {
1771 if (
q->isEncrypted()) {
1772 qint64 totalBytesWritten = 0;
1774 while ((writeBufferSize =
writeBuffer.size()) > 0) {
1775 const int headerSize = int(streamSizes.cbHeader);
1776 const int trailerSize = int(streamSizes.cbTrailer);
1778 const int size = int(std::min(writeBufferSize,
qint64(streamSizes.cbMaximumMessage)));
1786 SecBuffer inputBuffers[4]{
1787 createSecBuffer(fullMessage.
data(),
headerSize, SECBUFFER_STREAM_HEADER),
1789 createSecBuffer(fullMessage.
data() +
headerSize +
size, trailerSize, SECBUFFER_STREAM_TRAILER),
1790 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY)
1794 ARRAYSIZE(inputBuffers),
1797 auto status = EncryptMessage(&contextHandle, 0, &
message, 0);
1798 if (status != SEC_E_OK) {
1800 QSslSocket::tr(
"Schannel failed to encrypt data: %1")
1801 .
arg(schannelErrorToString(status)));
1808 fullMessage.
resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer + inputBuffers[2].cbBuffer);
1810#ifdef QSSLSOCKET_DEBUG
1822 if (totalBytesWritten > 0) {
1825 if (!emittedBytesWritten) {
1826 emittedBytesWritten =
true;
1827 emit q->bytesWritten(totalBytesWritten);
1828 emittedBytesWritten =
false;
1830 emit q->channelBytesWritten(0, totalBytesWritten);
1835 bool hadIncompleteData =
false;
1837 while (!readBufferMaxSize ||
buffer.size() < readBufferMaxSize) {
1839 && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
1840#ifdef QSSLSOCKET_DEBUG
1841 qCDebug(lcTlsBackendSchannel,
"We're still missing %lld bytes, will check later.",
1848 const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
1849#ifdef QSSLSOCKET_DEBUG
1850 qCDebug(lcTlsBackendSchannel,
"Read %lld encrypted bytes from the socket", bytesRead);
1852 if (intermediateBuffer.
length() == 0 || (hadIncompleteData && bytesRead == 0)) {
1853#ifdef QSSLSOCKET_DEBUG
1855 hadIncompleteData ?
"No new data received, leaving loop!"
1856 :
"Nothing to decrypt, leaving loop!");
1860 hadIncompleteData =
false;
1861#ifdef QSSLSOCKET_DEBUG
1862 qCDebug(lcTlsBackendSchannel,
"Total amount of bytes to decrypt: %d",
1863 intermediateBuffer.
length());
1866 SecBuffer dataBuffer[4]{
1867 createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
1868 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY),
1869 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY),
1870 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY)
1874 ARRAYSIZE(dataBuffer),
1877 auto status = DecryptMessage(&contextHandle, &
message, 0,
nullptr);
1878 if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
1880 if (dataBuffer[1].cbBuffer > 0) {
1884 buffer.append(
static_cast<char *
>(dataBuffer[1].pvBuffer),
1885 dataBuffer[1].cbBuffer);
1886 totalRead += dataBuffer[1].cbBuffer;
1887#ifdef QSSLSOCKET_DEBUG
1888 qCDebug(lcTlsBackendSchannel,
"Decrypted %lu bytes. New read buffer size: %d",
1889 dataBuffer[1].cbBuffer,
buffer.size());
1892 if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
1896 retainExtraData(intermediateBuffer, dataBuffer[3]);
1898 intermediateBuffer.
resize(0);
1902 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1903 missingData = checkIncompleteData(dataBuffer[0]);
1904#ifdef QSSLSOCKET_DEBUG
1905 qCDebug(lcTlsBackendSchannel,
"We didn't have enough data to decrypt anything, will try again!");
1908 hadIncompleteData =
true;
1909 }
else if (status == SEC_E_INVALID_HANDLE) {
1911 qCWarning(lcTlsBackendSchannel,
"The internal SSPI handle is invalid!");
1913 }
else if (status == SEC_E_INVALID_TOKEN) {
1914 qCWarning(lcTlsBackendSchannel,
"Got SEC_E_INVALID_TOKEN!");
1916 }
else if (status == SEC_E_MESSAGE_ALTERED) {
1921 schannelErrorToString(status));
1923 }
else if (status == SEC_E_OUT_OF_SEQUENCE) {
1930 schannelErrorToString(status));
1932 }
else if (status == SEC_I_CONTEXT_EXPIRED) {
1936 }
else if (status == SEC_I_RENEGOTIATE) {
1938#ifdef QSSLSOCKET_DEBUG
1939 qCDebug(lcTlsBackendSchannel,
"The peer wants to renegotiate.");
1941 schannelState = SchannelState::Renegotiate;
1942 renegotiating =
true;
1952 *readyReadEmittedPointer =
true;
1953 emit q->readyRead();
1954 emit q->channelReadyRead(0);
1958void TlsCryptographSchannel::sendShutdown()
1963 DWORD shutdownToken = SCHANNEL_SHUTDOWN;
1964 SecBuffer
buffer = createSecBuffer(&shutdownToken,
sizeof(DWORD), SECBUFFER_TOKEN);
1965 SecBufferDesc
token{
1970 auto status = ApplyControlToken(&contextHandle, &
token);
1972 if (status != SEC_E_OK) {
1973#ifdef QSSLSOCKET_DEBUG
1975 <<
"Failed to apply shutdown control token:" << schannelErrorToString(status);
1980 SecBuffer outBuffers[3];
1981 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1983 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1985 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1986 if (outBuffers[
i].pvBuffer)
1987 FreeContextBuffer(outBuffers[
i].pvBuffer);
1990 SecBufferDesc outputBufferDesc{
1992 ARRAYSIZE(outBuffers),
1996 ULONG contextReq = getContextRequirements();
1999 status = InitializeSecurityContext(&credentialHandle,
2001 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
2013 status = AcceptSecurityContext(
2025 if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
2026 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer,
false)) {
2032#ifdef QSSLSOCKET_DEBUG
2034 <<
"Failed to initialize shutdown:" << schannelErrorToString(status);
2046 if (SecIsValidHandle(&contextHandle)) {
2076 deallocateContext();
2077 freeCredentialsHandle();
2085 if (!
q->isEncrypted())
2088 const auto sessionProtocol = toQtSslProtocol(connectionInfo.dwProtocol);
2091 for (
const auto& cipher : ciphers) {
2101 if (!
q->isEncrypted())
2103 return toQtSslProtocol(connectionInfo.dwProtocol);
2114 switch (schannelState) {
2115 case SchannelState::InitializeHandshake:
2116 if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
2120 if (!SecIsValidHandle(&credentialHandle))
2122 if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
2126 if (schannelState != SchannelState::PerformHandshake)
2129 case SchannelState::PerformHandshake:
2130 if (!performHandshake()) {
2134 if (schannelState != SchannelState::VerifyHandshake)
2137 case SchannelState::VerifyHandshake:
2140 if (!verifyHandshake()) {
2146 if (schannelState != SchannelState::Done)
2149 case SchannelState::Done:
2151 if (!
q->isEncrypted()) {
2153 emit q->encrypted();
2155 renegotiating =
false;
2163 case SchannelState::Renegotiate:
2164 if (!renegotiate()) {
2182bool TlsCryptographSchannel::checkSslErrors()
2189 const auto &configuration =
q->sslConfiguration();
2192 emit q->sslErrors(sslErrors);
2199 if (doVerifyPeer && doEmitSslError) {
2214void TlsCryptographSchannel::initializeCertificateStores()
2219 const auto &configuration =
q->sslConfiguration();
2222 const wchar_t *passphrase = L
"";
2227 CRYPT_DATA_BLOB pfxBlob;
2228 pfxBlob.cbData = DWORD(pkcs12.
length());
2229 pfxBlob.pbData =
reinterpret_cast<unsigned char *
>(pkcs12.
data());
2233 if (!configuration.localCertificateChain().isEmpty()) {
2234 if (configuration.privateKey().isNull()) {
2236 QSslSocket::tr(
"Cannot provide a certificate with no key"));
2239 if (localCertificateStore ==
nullptr) {
2240 localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
2241 configuration.privateKey());
2242 if (localCertificateStore ==
nullptr)
2243 qCWarning(lcTlsBackendSchannel,
"Failed to load certificate chain!");
2247 if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
2248 caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
2253bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
2263 auto tempCertCollection =
QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
2266 CERT_STORE_CREATE_NEW_FLAG,
2268 if (!tempCertCollection) {
2269#ifdef QSSLSOCKET_DEBUG
2270 qCWarning(lcTlsBackendSchannel,
"Failed to create certificate store collection!");
2275 if (rootCertOnDemandLoadingAllowed()) {
2282#ifdef QSSLSOCKET_DEBUG
2283 qCWarning(lcTlsBackendSchannel,
"Failed to open the system root CA certificate store!");
2286 }
else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
2287#ifdef QSSLSOCKET_DEBUG
2289 "Failed to add the system root CA certificate store to the certificate store "
2295 if (caCertificateStore) {
2296 if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
2297#ifdef QSSLSOCKET_DEBUG
2299 "Failed to add the user's CA certificate store to the certificate store "
2306 if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
2307#ifdef QSSLSOCKET_DEBUG
2309 "Failed to add certificate's origin store to the certificate store collection!");
2314 CERT_CHAIN_PARA parameters;
2315 ZeroMemory(¶meters,
sizeof(parameters));
2316 parameters.cbSize =
sizeof(CERT_CHAIN_PARA);
2317 parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
2318 parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
2319 LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
2320 : szOID_PKIX_KP_CLIENT_AUTH);
2321 parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
2323 QTlsBackend::clearPeerCertificates(d);
2324 const CERT_CHAIN_CONTEXT *chainContext =
nullptr;
2325 auto freeCertChain =
qScopeGuard([&chainContext]() {
2327 CertFreeCertificateChain(chainContext);
2329 BOOL status = CertGetCertificateChain(
nullptr,
2332 tempCertCollection.get(),
2334 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
2338 if (status == FALSE || !chainContext || chainContext->cChain == 0) {
2346 static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
2350 const CERT_CONTEXT *certContext = element->pCertContext;
2357 CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
2359 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
2361 getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
2367 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2377 static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
2378 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2379 | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
2380 | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
2381 if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
2389 DWORD verifyDepth = chain->cElement;
2390 if (
q->peerVerifyDepth() > 0 && DWORD(
q->peerVerifyDepth()) < verifyDepth)
2391 verifyDepth = DWORD(
q->peerVerifyDepth());
2393 const auto &caCertificates =
q->sslConfiguration().caCertificates();
2395 if (!rootCertOnDemandLoadingAllowed()
2396 && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
2404 CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
2405 QSslCertificate certificate = getCertificateFromChainElement(element);
2406 if (!caCertificates.contains(certificate)) {
2416 for (DWORD
i = 0;
i < verifyDepth;
i++) {
2417 CERT_CHAIN_ELEMENT *element = chain->rgpElement[
i];
2418 QSslCertificate certificate = getCertificateFromChainElement(element);
2421#ifdef QSSLSOCKET_DEBUG
2424 <<
"\nQSslCertificate info:" << certificate
2425 <<
"\nextended error info:" << element->pwszExtendedErrorInfo
2426 <<
"\nerror status:" << element->TrustStatus.dwErrorStatus;
2429 peerCertificateChain.
append(certificate);
2430 QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
2440 LONG
result = CertVerifyTimeValidity(
nullptr , element->pCertContext->pCertInfo);
2452 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
2456 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
2463 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
2474 if (netscapeWrongCertType(extensions, isClient))
2475 element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
2477 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
2484 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
2486 const bool isTrustedRoot = caCertificates.contains(certificate);
2487 if (!isTrustedRoot) {
2495 static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
2496 | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
2497 if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
2502 static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
2503 | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2504 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
2505 | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
2506 | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
2507 | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
2508 | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
2509 | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
2510 if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
2517 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2518 auto it = std::find_if(extensions.
cbegin(), extensions.
cend(),
2520 return extension.name() ==
"basicConstraints"_L1;
2522 if (
it != extensions.
cend()) {
2528 if (
i > 0 && !basicConstraints.
value(
"ca"_L1,
false).
toBool())
2538 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
2546 if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
2551 const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
2552 || certificate.
version() ==
"1";
2555 if (!isRootCertificateAuthority) {
2565 if (!peerCertificateChain.
isEmpty())
2566 QTlsBackend::storePeerCertificate(d, peerCertificateChain.
first());
2568 const auto &configuration =
q->sslConfiguration();
2576 if (!configuration.peerCertificate().isNull()) {
2581 const QString peerName(verificationPeerName.isEmpty() ?
q->peerName() : verificationPeerName);
2582 if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
2591 }
else if (doVerifyPeer) {
2604bool TlsCryptographSchannel::rootCertOnDemandLoadingAllowed()
qint64 bytesAvailable() const override
Returns the number of incoming bytes that are waiting to be read.
virtual void disconnectFromHost()
Attempts to close the socket.
SocketState state() const
Returns the state of the socket.
@ SslInvalidUserDataError
@ SslHandshakeFailedError
SocketError error() const
Returns the type of error that last occurred.
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
qsizetype length() const noexcept
Same as size().
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
void clear()
Clears the contents of the byte array and makes it null.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
\inmodule QtCore\reentrant
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
bool contains(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
qsizetype size() const noexcept
bool isEmpty() const noexcept
const T & constFirst() const noexcept
const_iterator cend() const noexcept
void append(parameter_type t)
const_iterator cbegin() const noexcept
T value(const Key &key, const T &defaultValue=T()) const
static QOperatingSystemVersion current()
[0]
QTlsPrivate::X509Certificate * createCertificate() const override
QString backendName() const override
long tlsLibraryBuildVersionNumber() const override
QTlsPrivate::TlsKey * createKey() const override
QList< QSslCertificate > systemCaCertificates() const override
QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override
QList< QSsl::SupportedFeature > supportedFeatures() const override
QString tlsLibraryVersionString() const override
void ensureInitialized() const override
QTlsPrivate::X509DerReaderPtr X509DerReader() const override
QList< QSsl::SslProtocol > supportedProtocols() const override
QTlsPrivate::TlsCryptograph * createTlsCryptograph() const override
QTlsPrivate::X509PemReaderPtr X509PemReader() const override
QList< QSsl::ImplementedClass > implementedClasses() const override
QString tlsLibraryBuildVersionString() const override
static void ensureInitializedImplementation()
The QSslCertificateExtension class provides an API for accessing the extensions of an X509 certificat...
The QSslCertificate class provides a convenient API for an X509 certificate.
QString issuerDisplayName() const
QByteArray version() const
Returns the certificate's version string.
QString subjectDisplayName() const
QList< QSslCertificateExtension > extensions() const
Returns a list containing the X509 extensions of this certificate.
bool isBlacklisted() const
Returns true if this certificate is blacklisted; otherwise returns false.
The QSslCipher class represents an SSL cryptographic cipher.
@ NextProtocolNegotiationNone
@ NextProtocolNegotiationUnsupported
@ NextProtocolNegotiationNegotiated
The QSslError class provides an SSL error.
QString errorString() const
Returns a short localized human-readable description of the error.
@ UnableToVerifyFirstCertificate
@ UnableToGetIssuerCertificate
@ CertificateSignatureFailed
The QSslKey class provides an interface for private and public keys.
bool * readyReadPointer()
bool verifyErrorsHaveBeenIgnored()
void setEncrypted(bool enc)
void setMaxReadBufferSize(qint64 maxSize)
QTcpSocket * plainTcpSocket() const
QString verificationName() const
static void setRootCertOnDemandLoadingSupported(bool supported)
bool isRootsOnDemandAllowed() const
qint64 maxReadBufferSize() const
bool & tlsEmittedBytesWritten()
QRingBufferRef & tlsBuffer()
static bool rootCertOnDemandLoadingSupported()
void setPendingClose(bool pc)
static void pauseSocketNotifiers(QSslSocket *)
QRingBufferRef & tlsWriteBuffer()
QSslSocket::SslMode tlsMode() const
bool isPendingClose() const
The QSslSocket class provides an SSL encrypted socket for both clients and servers.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
The QTcpSocket class provides a TCP socket.
static constexpr const int nameIndexSchannel
static const QString builtinBackendNames[]
void startClientEncryption() override
void disconnected() override
void continueHandshake() override
void init(QSslSocket *q, QSslSocketPrivate *d) override
void startServerEncryption() override
QSsl::SslProtocol sessionProtocol() const override
void disconnectFromHost() override
~TlsCryptographSchannel()
bool hasUndecryptedData() const override
QSslCipher sessionCipher() const override
QList< QSslError > tlsErrors() const override
TlsKey is an abstract class, that allows a TLS plugin to provide an underlying implementation for the...
static QList< QSslCertificate > certificatesFromDer(const QByteArray &der, int count)
static QList< QSslCertificate > certificatesFromPem(const QByteArray &pem, int count)
static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert, QList< QSslCertificate > *caCertificates, const QByteArray &passPhrase)
static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
X509Certificate is an abstract class that allows a TLS backend to provide an implementation of the QS...
bool toBool() const
Returns the variant as a bool if the variant has userType() Bool.
QSet< QString >::iterator it
SslProtocol
Describes the protocol of the cipher.
Combined button and popup list for selecting options.
Namespace containing onternal types that TLS backends implement.
QList< QSslCipher > defaultCiphers()
bool(*)(QIODevice *device, QSslKey *key, QSslCertificate *cert, QList< QSslCertificate > *caCertificates, const QByteArray &passPhrase) X509Pkcs12ReaderPtr
UNICODE_STRING cbcChainingMode
QList< CRYPTO_SETTINGS > cryptoSettingsForCiphers(const QList< QSslCipher > &ciphers)
bool containsTls13Cipher(const QList< QSslCipher > &ciphers)
UNICODE_STRING gcmChainingMode
QT_WARNING_POP const SchannelCipherInfo * cipherInfoByOpenSslName(const QString &name)
QList< QSslCipher > ciphersByName(QStringView schannelSuiteName)
QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED std::array< SchannelCipherInfo, 44 > schannelCipherInfo
constexpr Initialization Uninitialized
QVector3D minimum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
#define QT_WARNING_DISABLE_DEPRECATED
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
static const qint64 headerSize
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
static ControlElement< T > * ptr(QWidget *widget)
GLenum GLsizei GLuint GLint * bytesWritten
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLuint GLsizei const GLchar * message
GLdouble GLdouble GLdouble GLdouble q
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
#define QStringLiteral(str)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
#define SECPKG_ATTR_APPLICATION_PROTOCOL
#define BCRYPT_ECDSA_ALGORITHM
#define MAP_PROTOCOL(sp_protocol, q_protocol)
#define CHECK_STATUS(status)
#define CHECK_ATTRIBUTE(attributeName)
#define DEBUG_WARN(message)
QByteArray _q_makePkcs12(const QList< QSslCertificate > &certs, const QSslKey &key, const QString &passPhrase)
#define BCRYPT_ECDH_ALGORITHM
#define SEC_E_APPLICATION_PROTOCOL_MISMATCH
std::unique_ptr< void, QHCertStoreDeleter > QHCertStorePointer
QList< QChar > characters
QFileInfo info(fileName)
[8]
QSettings settings("MySoft", "Star Runner")
[0]
bool contains(const AT &t) const noexcept
const char * openSslCipherSuite
const char * encryptionMethod
const char * schannelCipherSuite
QList< QSsl::SslProtocol > protocols
const char * authenticationMethod
const char * keyExchangeMethod