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(SECBUFFER_APPLICATION_PROTOCOLS)
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)
235 static const QList<QSslCipher> defaultCipherList =
defaultCiphers();
237 if (defaultCipherList == ciphers) {
242 QList<const SchannelCipherInfo*> cipherInfo;
244 for (
const auto &cipher : ciphers) {
249 if (!cipherInfo.contains(
info))
250 cipherInfo.append(
info);
253 QList<CRYPTO_SETTINGS> cryptoSettings;
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;
397 QList<QSslCipher> ciphers;
401 for (
const auto &protocol : cipher.protocols) {
412 ciphers.append(QTlsBackend::createCiphersuite(
QLatin1StringView(cipher.openSslCipherSuite),
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();
439 QList<QSslCipher> ciphers;
442 const auto suiteName =
QStringView(contextFunctions->rgpszFunctions[
index]);
444 const QList<QSslCipher> allCiphers =
ciphersByName(suiteName);
446 for (
const auto &cipher : allCiphers) {
450 ciphers.append(cipher);
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
504 const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
505 if (s_loadedCiphersAndCerts)
507 s_loadedCiphersAndCerts =
true;
509 setDefaultCaCertificates(systemCaCertificatesImplementation());
513 resetDefaultCiphers();
516void QSchannelBackend::resetDefaultCiphers()
529 QList<QSsl::SslProtocol> protocols;
535 protocols << QSsl::TlsV1_0;
536 protocols << QSsl::TlsV1_0OrLater;
537 protocols << QSsl::TlsV1_1;
538 protocols << QSsl::TlsV1_1OrLater;
543 if (supportsTls13()) {
553 QList<QSsl::SupportedFeature> features;
565 QList<QSsl::ImplementedClass> classes;
586 return systemCaCertificatesImplementation();
594QList<QSslCertificate> QSchannelBackend::systemCaCertificatesImplementation()
598 QList<QSslCertificate> systemCerts;
601 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
602 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L
"ROOT"));
605 PCCERT_CONTEXT pc =
nullptr;
606 while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
607 CERT_FIND_ANY,
nullptr, pc))) {
631SecBuffer createSecBuffer(
void *
ptr,
unsigned long length,
unsigned long bufferType)
633 return SecBuffer{
length, bufferType,
ptr };
638 return createSecBuffer(
buffer.data(),
static_cast<unsigned long>(
buffer.length()), bufferType);
644 case SEC_E_INSUFFICIENT_MEMORY:
645 return QSslSocket::tr(
"Insufficient memory");
646 case SEC_E_INTERNAL_ERROR:
647 return QSslSocket::tr(
"Internal error");
648 case SEC_E_INVALID_HANDLE:
649 return QSslSocket::tr(
"An internal handle was invalid");
650 case SEC_E_INVALID_TOKEN:
651 return QSslSocket::tr(
"An internal token was invalid");
652 case SEC_E_LOGON_DENIED:
655 return QSslSocket::tr(
"Access denied");
656 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
657 return QSslSocket::tr(
"No authority could be contacted for authorization");
658 case SEC_E_NO_CREDENTIALS:
659 return QSslSocket::tr(
"No credentials");
660 case SEC_E_TARGET_UNKNOWN:
661 return QSslSocket::tr(
"The target is unknown or unreachable");
662 case SEC_E_UNSUPPORTED_FUNCTION:
663 return QSslSocket::tr(
"An unsupported function was requested");
664 case SEC_E_WRONG_PRINCIPAL:
666 return QSslSocket::tr(
"The hostname provided does not match the one received from the peer");
668 return QSslSocket::tr(
"No common protocol exists between the client and the server");
669 case SEC_E_ILLEGAL_MESSAGE:
670 return QSslSocket::tr(
"Unexpected or badly-formatted message received");
671 case SEC_E_ENCRYPT_FAILURE:
672 return QSslSocket::tr(
"The data could not be encrypted");
673 case SEC_E_ALGORITHM_MISMATCH:
674 return QSslSocket::tr(
"No cipher suites in common");
675 case SEC_E_UNKNOWN_CREDENTIALS:
677 return QSslSocket::tr(
"The credentials were not recognized / Invalid argument");
678 case SEC_E_MESSAGE_ALTERED:
681 return QSslSocket::tr(
"The message was tampered with, damaged or out of sequence.");
682 case SEC_E_OUT_OF_SEQUENCE:
683 return QSslSocket::tr(
"A message was received out of sequence.");
684 case SEC_E_CONTEXT_EXPIRED:
685 return QSslSocket::tr(
"The TLS/SSL connection has been closed");
687 return QSslSocket::tr(
"Unknown error occurred: %1").arg(status);
693 static bool supported = []() {
706 DWORD protocols = SP_PROT_NONE;
713 case QSsl::DtlsV1_0OrLater:
739 protocols = DWORD(-1);
743 case QSsl::TlsV1_0OrLater:
748 case QSsl::TlsV1_1OrLater:
760 protocols = DWORD(-1);
769DWORD negatedSchannelProtocols(DWORD wantedProtocols)
771 DWORD protocols = SP_PROT_ALL;
772 protocols &= ~wantedProtocols;
785#define MAP_PROTOCOL(sp_protocol, q_protocol) \
786 if (protocol & sp_protocol) { \
787 Q_ASSERT(!(protocol & ~sp_protocol)); \
807bool netscapeWrongCertType(
const QList<QSslCertificateExtension> &extensions,
bool isClient)
809 const auto netscapeIt = std::find_if(
810 extensions.cbegin(), extensions.cend(),
812 return extension.oid() == u
"2.16.840.1.113730.1.1";
814 if (netscapeIt != extensions.cend()) {
815 const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
816 int netscapeCertType = 0;
818 dataStream >> netscapeCertType;
819 if (dataStream.status() != QDataStream::Status::Ok)
821 const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
822 : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
823 if ((netscapeCertType & expectedPeerCertType) == 0)
836bool isCertificateAuthority(
const QList<QSslCertificateExtension> &extensions)
838 auto it = std::find_if(extensions.cbegin(), extensions.cend(),
840 return extension.name() ==
"basicConstraints"_L1;
842 if (
it != extensions.cend()) {
844 return basicConstraints.value(
"ca"_L1,
false).toBool();
854bool matchesContextRequirements(DWORD attributes, DWORD requirements,
858#ifdef QSSLSOCKET_DEBUG
859#define DEBUG_WARN(message) qCWarning(lcTlsBackendSchannel, message)
861#define DEBUG_WARN(message)
864#define CHECK_ATTRIBUTE(attributeName) \
866 const DWORD req##attributeName = isClient ? ISC_REQ_##attributeName : ASC_REQ_##attributeName; \
867 const DWORD ret##attributeName = isClient ? ISC_RET_##attributeName : ASC_RET_##attributeName; \
868 if (!(requirements & req##attributeName) != !(attributes & ret##attributeName)) { \
869 DEBUG_WARN("Missing attribute \"" #attributeName "\""); \
883 const auto reqManualCredValidation = ISC_REQ_MANUAL_CRED_VALIDATION;
884 const auto retManualCredValidation = ISC_RET_MANUAL_CRED_VALIDATION;
885 if (!(requirements & reqManualCredValidation) != !(attributes & retManualCredValidation)) {
886 DEBUG_WARN(
"Missing attribute \"MANUAL_CRED_VALIDATION\"");
892#undef CHECK_ATTRIBUTE
896template<
typename Required,
typename Actual>
897Required const_reinterpret_cast(Actual *
p)
906 if (!nextAllowedProtocols.isEmpty()) {
909 for (
QByteArray proto : nextAllowedProtocols) {
910 if (proto.size() > 255) {
912 <<
"TLS ALPN extension" << proto <<
"is too long and will be ignored.";
914 }
else if (proto.isEmpty()) {
917 protocolString += char(proto.length()) + proto;
919 return protocolString;
925 const quint32 alpnId = SecApplicationProtocolNegotiationExt_ALPN;
926 const quint32 totalSize =
sizeof(alpnId) +
sizeof(namesSize) + namesSize;
939 static const qint64 shrinkCutoff = 1024 * 12;
940 static const qint64 defaultRead = 1024 * 16;
943 const auto toRead = std::min(defaultRead, plainSocket->
bytesAvailable());
945 const auto bufferSize =
buffer.size();
946 buffer.reserve(bufferSize + toRead);
947 buffer.resize(bufferSize + toRead);
948 bytesRead = plainSocket->
read(
buffer.data() + bufferSize, toRead);
949 buffer.resize(bufferSize + bytesRead);
951 if (
buffer.size() < shrinkCutoff &&
buffer.capacity() > defaultRead)
960 Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
961 if (
int(secBuffer.cbBuffer) >=
buffer.size())
964#ifdef QSSLSOCKET_DEBUG
965 qCDebug(lcTlsBackendSchannel,
"We got SECBUFFER_EXTRA, will retain %lu bytes",
969 buffer.resize(secBuffer.cbBuffer);
972qint64 checkIncompleteData(
const SecBuffer &secBuffer)
974 if (secBuffer.BufferType == SECBUFFER_MISSING) {
975#ifdef QSSLSOCKET_DEBUG
976 qCDebug(lcTlsBackendSchannel,
"Need %lu more bytes.", secBuffer.cbBuffer);
978 return secBuffer.cbBuffer;
983DWORD defaultCredsFlag()
994 SecInvalidateHandle(&credentialHandle);
995 SecInvalidateHandle(&contextHandle);
1001 closeCertificateStores();
1002 deallocateContext();
1003 freeCredentialsHandle();
1004 CertFreeCertificateContext(localCertContext);
1018bool TlsCryptographSchannel::sendToken(
void *
token,
unsigned long tokenLength,
bool emitError)
1020 if (tokenLength == 0)
1027 || !plainSocket->
isOpen()) {
1031 const qint64 written = plainSocket->
write(
static_cast<const char *
>(
token), tokenLength);
1032 if (written !=
qint64(tokenLength)) {
1041QString TlsCryptographSchannel::targetName()
const
1048 return verificationPeerName.
isEmpty() ?
q->peerName() : verificationPeerName;
1051ULONG TlsCryptographSchannel::getContextRequirements()
1059 req |= ISC_REQ_ALLOCATE_MEMORY;
1060 req |= ISC_REQ_CONFIDENTIALITY;
1061 req |= ISC_REQ_REPLAY_DETECT;
1062 req |= ISC_REQ_SEQUENCE_DETECT;
1063 req |= ISC_REQ_STREAM;
1066 req |= ISC_REQ_MANUAL_CRED_VALIDATION;
1068 switch (
q->peerVerifyMode()) {
1075 req |= ISC_REQ_MUTUAL_AUTH;
1083bool TlsCryptographSchannel::acquireCredentialsHandle()
1087 const auto &configuration =
q->sslConfiguration();
1089 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1092 DWORD protocols = toSchannelProtocol(configuration.protocol());
1093 if (protocols == DWORD(-1)) {
1095 QSslSocket::tr(
"Invalid protocol chosen"));
1099 const CERT_CHAIN_CONTEXT *chainContext =
nullptr;
1100 auto freeCertChain =
qScopeGuard([&chainContext]() {
1102 CertFreeCertificateChain(chainContext);
1105 DWORD certsCount = 0;
1107 initializeCertificateStores();
1112 if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
1115 if (localCertificateStore !=
nullptr) {
1116 CERT_CHAIN_FIND_BY_ISSUER_PARA findParam;
1117 ZeroMemory(&findParam,
sizeof(findParam));
1118 findParam.cbSize =
sizeof(findParam);
1119 findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH;
1122 chainContext = CertFindChainInStore(localCertificateStore.get(),
1125 CERT_CHAIN_FIND_BY_ISSUER,
1128 if (!chainContext) {
1130 ? QSslSocket::tr(
"The certificate provided cannot be used for a client.")
1131 :
QSslSocket::
tr(
"The certificate provided cannot be used for a server.");
1135 Q_ASSERT(chainContext->cChain == 1);
1136 Q_ASSERT(chainContext->rgpChain[0]);
1137 Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1);
1138 Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]);
1140 localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0]
1147 const QList<QSslCipher> ciphers = configuration.ciphers();
1149 protocols &= ~SP_PROT_TLS1_3;
1151 QList<CRYPTO_SETTINGS> cryptoSettings;
1152 if (!ciphers.isEmpty())
1155 TLS_PARAMETERS tlsParameters = {
1158 negatedSchannelProtocols(protocols),
1159 static_cast<DWORD
>(cryptoSettings.size()),
1160 (cryptoSettings.isEmpty() ?
nullptr : cryptoSettings.data()),
1164 SCH_CREDENTIALS credentials = {
1165 SCH_CREDENTIALS_VERSION,
1173 SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(),
1178 TimeStamp expiration{};
1179 auto status = AcquireCredentialsHandle(
nullptr,
1180 const_cast<wchar_t *
>(UNISP_NAME),
1181 isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND,
1190 if (status != SEC_E_OK) {
1197void TlsCryptographSchannel::deallocateContext()
1199 if (SecIsValidHandle(&contextHandle)) {
1200 DeleteSecurityContext(&contextHandle);
1201 SecInvalidateHandle(&contextHandle);
1205void TlsCryptographSchannel::freeCredentialsHandle()
1207 if (SecIsValidHandle(&credentialHandle)) {
1208 FreeCredentialsHandle(&credentialHandle);
1209 SecInvalidateHandle(&credentialHandle);
1213void TlsCryptographSchannel::closeCertificateStores()
1215 localCertificateStore.reset();
1216 peerCertificateStore.reset();
1217 caCertificateStore.reset();
1220bool TlsCryptographSchannel::createContext()
1225 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1226 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1228 ULONG contextReq = getContextRequirements();
1230 SecBuffer outBuffers[3];
1231 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1233 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1235 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1236 if (outBuffers[
i].pvBuffer)
1237 FreeContextBuffer(outBuffers[
i].pvBuffer);
1240 SecBufferDesc outputBufferDesc{
1242 ARRAYSIZE(outBuffers),
1248 SecBufferDesc alpnBufferDesc;
1249 bool useAlpn =
false;
1252 QByteArray alpnString = createAlpnString(
q->sslConfiguration().allowedNextProtocols());
1253 useAlpn = !alpnString.isEmpty();
1254 SecBuffer alpnBuffers[1];
1255 alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1258 ARRAYSIZE(alpnBuffers),
1263 auto status = InitializeSecurityContext(&credentialHandle,
1265 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1269 useAlpn ? &alpnBufferDesc :
nullptr,
1279 if (status != SEC_I_CONTINUE_NEEDED) {
1281 QSslSocket::tr(
"Error creating SSL context (%1)").
arg(schannelErrorToString(status)));
1285 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1287 schannelState = SchannelState::PerformHandshake;
1291bool TlsCryptographSchannel::acceptContext()
1299 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1300 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1302 ULONG contextReq = getContextRequirements();
1308 readToBuffer(intermediateBuffer, plainSocket);
1309 if (intermediateBuffer.
isEmpty())
1312 SecBuffer inBuffers[2];
1313 inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1318 QByteArray alpnString = createAlpnString(
q->sslConfiguration().allowedNextProtocols());
1319 if (!alpnString.isEmpty()) {
1320 inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1324 inBuffers[1] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1327 SecBufferDesc inputBufferDesc{
1329 ARRAYSIZE(inBuffers),
1333 SecBuffer outBuffers[3];
1334 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1336 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1338 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1339 if (outBuffers[
i].pvBuffer)
1340 FreeContextBuffer(outBuffers[
i].pvBuffer);
1343 SecBufferDesc outputBufferDesc{
1345 ARRAYSIZE(outBuffers),
1350 auto status = AcceptSecurityContext(
1362 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1364 missingData = checkIncompleteData(outBuffers[0]);
1368 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
1372 retainExtraData(intermediateBuffer, inBuffers[1]);
1374 intermediateBuffer.
resize(0);
1377 if (status != SEC_I_CONTINUE_NEEDED) {
1379 QSslSocket::tr(
"Error creating SSL context (%1)").
arg(schannelErrorToString(status)));
1382 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1384 schannelState = SchannelState::PerformHandshake;
1388bool TlsCryptographSchannel::performHandshake()
1395 || !plainSocket->
isOpen()) {
1397 QSslSocket::tr(
"The TLS/SSL connection has been closed"));
1400 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1401 Q_ASSERT(SecIsValidHandle(&contextHandle));
1402 Q_ASSERT(schannelState == SchannelState::PerformHandshake);
1404#ifdef QSSLSOCKET_DEBUG
1405 qCDebug(lcTlsBackendSchannel,
"Bytes available from socket: %lld",
1407 qCDebug(lcTlsBackendSchannel,
"intermediateBuffer size: %d", intermediateBuffer.
size());
1414 readToBuffer(intermediateBuffer, plainSocket);
1415 if (intermediateBuffer.
isEmpty())
1418 SecBuffer outBuffers[3] = {};
1419 const auto freeOutBuffers = [&outBuffers]() {
1420 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1421 if (outBuffers[
i].pvBuffer)
1422 FreeContextBuffer(outBuffers[
i].pvBuffer);
1425 const auto outBuffersGuard =
qScopeGuard(freeOutBuffers);
1431 SECURITY_STATUS status;
1434 SecBuffer inputBuffers[2];
1435 inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1436 inputBuffers[1] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1437 SecBufferDesc inputBufferDesc{
1439 ARRAYSIZE(inputBuffers),
1444 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1446 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1447 SecBufferDesc outputBufferDesc{
1449 ARRAYSIZE(outBuffers),
1453 ULONG contextReq = getContextRequirements();
1455 status = InitializeSecurityContext(
1458 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1470 if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
1474 retainExtraData(intermediateBuffer, inputBuffers[1]);
1475 }
else if (status != SEC_E_INCOMPLETE_MESSAGE) {
1477 intermediateBuffer.
resize(0);
1481 }
while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
1486 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1488 schannelState = SchannelState::VerifyHandshake;
1490 case SEC_I_CONTINUE_NEEDED:
1491 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1495 case SEC_I_INCOMPLETE_CREDENTIALS:
1499 QSslSocket::tr(
"Server did not accept any certificate we could present."));
1501 case SEC_I_CONTEXT_EXPIRED:
1503 if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
1504 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1509 QSslSocket::tr(
"The TLS/SSL connection has been closed"));
1512 case SEC_E_INCOMPLETE_MESSAGE:
1514 missingData = checkIncompleteData(outBuffers[0]);
1516 case SEC_E_ALGORITHM_MISMATCH:
1518 QSslSocket::tr(
"Algorithm mismatch"));
1527 QSslSocket::tr(
"Handshake failed: %1").
arg(schannelErrorToString(status)));
1531bool TlsCryptographSchannel::verifyHandshake()
1535 const auto &configuration =
q->sslConfiguration();
1540#define CHECK_STATUS(status) \
1541 if (status != SEC_E_OK) { \
1542 setErrorAndEmit(d, QAbstractSocket::SslInternalError, \
1543 QSslSocket::tr("Failed to query the TLS context: %1") \
1544 .arg(schannelErrorToString(status))); \
1549 if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
1550 configuration.peerVerifyMode(), isClient)) {
1552 QSslSocket::tr(
"Did not get the required attributes for the connection."));
1557 auto status = QueryContextAttributes(&contextHandle,
1558 SECPKG_ATTR_STREAM_SIZES,
1563 status = QueryContextAttributes(&contextHandle,
1564 SECPKG_ATTR_CIPHER_INFO,
1568 status = QueryContextAttributes(&contextHandle,
1569 SECPKG_ATTR_CONNECTION_INFO,
1574 const auto allowedProtos = configuration.allowedNextProtocols();
1575 if (!allowedProtos.isEmpty()) {
1576 SecPkgContext_ApplicationProtocol alpn;
1577 status = QueryContextAttributes(&contextHandle,
1581 if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
1583 alpn.ProtocolIdSize);
1584 if (!allowedProtos.contains(negotiatedProto)) {
1586 QSslSocket::tr(
"Unwanted protocol was negotiated"));
1589 QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
1592 QTlsBackend::setNegotiatedProtocol(d, {});
1601 CERT_CONTEXT *certificateContext =
nullptr;
1602 auto freeCertificate =
qScopeGuard([&certificateContext]() {
1603 if (certificateContext)
1604 CertFreeCertificateContext(certificateContext);
1606 status = QueryContextAttributes(&contextHandle,
1607 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1608 &certificateContext);
1618 if (status != SEC_E_OK) {
1619#ifdef QSSLSOCKET_DEBUG
1620 qCDebug(lcTlsBackendSchannel) <<
"Couldn't retrieve peer certificate, status:"
1621 << schannelErrorToString(status);
1632 if (certificateContext && !verifyCertContext(certificateContext))
1636#ifdef QSSLSOCKET_DEBUG
1637 qCDebug(lcTlsBackendSchannel) << __func__ <<
"was unsuccessful. Paused:" << d->
isPaused();
1643 schannelState = SchannelState::Done;
1647bool TlsCryptographSchannel::renegotiate()
1651 SecBuffer outBuffers[3];
1652 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1654 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1656 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
1657 if (outBuffers[
i].pvBuffer)
1658 FreeContextBuffer(outBuffers[
i].pvBuffer);
1661 SecBufferDesc outputBufferDesc{
1663 ARRAYSIZE(outBuffers),
1667 ULONG contextReq = getContextRequirements();
1669 SECURITY_STATUS status;
1671 status = InitializeSecurityContext(&credentialHandle,
1673 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1685 status = AcceptSecurityContext(
1697 if (status == SEC_I_CONTINUE_NEEDED) {
1698 schannelState = SchannelState::PerformHandshake;
1699 return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
1700 }
else if (status == SEC_E_OK) {
1701 schannelState = SchannelState::PerformHandshake;
1705 QSslSocket::tr(
"Renegotiation was unsuccessful: %1").
arg(schannelErrorToString(status)));
1713void TlsCryptographSchannel::reset()
1717 closeCertificateStores();
1718 deallocateContext();
1719 freeCredentialsHandle();
1722 connectionInfo = {};
1725 CertFreeCertificateContext(localCertContext);
1726 localCertContext =
nullptr;
1728 contextAttributes = 0;
1729 intermediateBuffer.
clear();
1730 schannelState = SchannelState::InitializeHandshake;
1735 renegotiating =
false;
1744 if (
q->isEncrypted())
1754 if (
q->isEncrypted())
1772 || !plainSocket->
isOpen()) {
1776 if (schannelState != SchannelState::Done) {
1783 if (
q->isEncrypted()) {
1784 qint64 totalBytesWritten = 0;
1786 while ((writeBufferSize =
writeBuffer.size()) > 0) {
1787 const int headerSize = int(streamSizes.cbHeader);
1788 const int trailerSize = int(streamSizes.cbTrailer);
1790 const int size = int(std::min(writeBufferSize,
qint64(streamSizes.cbMaximumMessage)));
1798 SecBuffer inputBuffers[4]{
1799 createSecBuffer(fullMessage.data(),
headerSize, SECBUFFER_STREAM_HEADER),
1800 createSecBuffer(fullMessage.data() +
headerSize,
size, SECBUFFER_DATA),
1801 createSecBuffer(fullMessage.data() +
headerSize +
size, trailerSize, SECBUFFER_STREAM_TRAILER),
1802 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY)
1806 ARRAYSIZE(inputBuffers),
1809 auto status = EncryptMessage(&contextHandle, 0, &
message, 0);
1810 if (status != SEC_E_OK) {
1812 QSslSocket::tr(
"Schannel failed to encrypt data: %1")
1813 .
arg(schannelErrorToString(status)));
1820 fullMessage.resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer + inputBuffers[2].cbBuffer);
1822#ifdef QSSLSOCKET_DEBUG
1824 fullMessage.length());
1834 if (totalBytesWritten > 0) {
1837 if (!emittedBytesWritten) {
1838 emittedBytesWritten =
true;
1839 emit q->bytesWritten(totalBytesWritten);
1840 emittedBytesWritten =
false;
1842 emit q->channelBytesWritten(0, totalBytesWritten);
1847 bool hadIncompleteData =
false;
1849 while (!readBufferMaxSize ||
buffer.size() < readBufferMaxSize) {
1851 && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
1852#ifdef QSSLSOCKET_DEBUG
1853 qCDebug(lcTlsBackendSchannel,
"We're still missing %lld bytes, will check later.",
1860 const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
1861#ifdef QSSLSOCKET_DEBUG
1862 qCDebug(lcTlsBackendSchannel,
"Read %lld encrypted bytes from the socket", bytesRead);
1864 if (intermediateBuffer.
length() == 0 || (hadIncompleteData && bytesRead == 0)) {
1865#ifdef QSSLSOCKET_DEBUG
1867 hadIncompleteData ?
"No new data received, leaving loop!"
1868 :
"Nothing to decrypt, leaving loop!");
1872 hadIncompleteData =
false;
1873#ifdef QSSLSOCKET_DEBUG
1874 qCDebug(lcTlsBackendSchannel,
"Total amount of bytes to decrypt: %d",
1875 intermediateBuffer.
length());
1878 SecBuffer dataBuffer[4]{
1879 createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
1880 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY),
1881 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY),
1882 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY)
1886 ARRAYSIZE(dataBuffer),
1889 auto status = DecryptMessage(&contextHandle, &
message, 0,
nullptr);
1890 if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
1892 if (dataBuffer[1].cbBuffer > 0) {
1896 buffer.append(
static_cast<char *
>(dataBuffer[1].pvBuffer),
1897 dataBuffer[1].cbBuffer);
1898 totalRead += dataBuffer[1].cbBuffer;
1899#ifdef QSSLSOCKET_DEBUG
1900 qCDebug(lcTlsBackendSchannel,
"Decrypted %lu bytes. New read buffer size: %d",
1901 dataBuffer[1].cbBuffer,
buffer.size());
1904 if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
1908 retainExtraData(intermediateBuffer, dataBuffer[3]);
1910 intermediateBuffer.
resize(0);
1914 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1915 missingData = checkIncompleteData(dataBuffer[0]);
1916#ifdef QSSLSOCKET_DEBUG
1917 qCDebug(lcTlsBackendSchannel,
"We didn't have enough data to decrypt anything, will try again!");
1920 hadIncompleteData =
true;
1921 }
else if (status == SEC_E_INVALID_HANDLE) {
1923 qCWarning(lcTlsBackendSchannel,
"The internal SSPI handle is invalid!");
1925 }
else if (status == SEC_E_INVALID_TOKEN) {
1932 }
else if (status == SEC_E_MESSAGE_ALTERED) {
1937 schannelErrorToString(status));
1939 }
else if (status == SEC_E_OUT_OF_SEQUENCE) {
1946 schannelErrorToString(status));
1948 }
else if (status == SEC_I_CONTEXT_EXPIRED) {
1952 }
else if (status == SEC_I_RENEGOTIATE) {
1954#ifdef QSSLSOCKET_DEBUG
1955 qCDebug(lcTlsBackendSchannel,
"The peer wants to renegotiate.");
1957 schannelState = SchannelState::Renegotiate;
1958 renegotiating =
true;
1968 *readyReadEmittedPointer =
true;
1969 emit q->readyRead();
1970 emit q->channelReadyRead(0);
1974void TlsCryptographSchannel::sendShutdown()
1979 DWORD shutdownToken = SCHANNEL_SHUTDOWN;
1980 SecBuffer
buffer = createSecBuffer(&shutdownToken,
sizeof(DWORD), SECBUFFER_TOKEN);
1981 SecBufferDesc
token{
1986 auto status = ApplyControlToken(&contextHandle, &
token);
1988 if (status != SEC_E_OK) {
1989#ifdef QSSLSOCKET_DEBUG
1991 <<
"Failed to apply shutdown control token:" << schannelErrorToString(status);
1996 SecBuffer outBuffers[3];
1997 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1999 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
2001 for (
auto i = 0ull;
i < ARRAYSIZE(outBuffers);
i++) {
2002 if (outBuffers[
i].pvBuffer)
2003 FreeContextBuffer(outBuffers[
i].pvBuffer);
2006 SecBufferDesc outputBufferDesc{
2008 ARRAYSIZE(outBuffers),
2012 ULONG contextReq = getContextRequirements();
2015 status = InitializeSecurityContext(&credentialHandle,
2017 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
2029 status = AcceptSecurityContext(
2041 if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
2042 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer,
false)) {
2048#ifdef QSSLSOCKET_DEBUG
2050 <<
"Failed to initialize shutdown:" << schannelErrorToString(status);
2062 if (SecIsValidHandle(&contextHandle)) {
2092 deallocateContext();
2093 freeCredentialsHandle();
2101 if (!
q->isEncrypted())
2104 const auto sessionProtocol = toQtSslProtocol(connectionInfo.dwProtocol);
2107 for (
const auto& cipher : ciphers) {
2117 if (!
q->isEncrypted())
2119 return toQtSslProtocol(connectionInfo.dwProtocol);
2130 switch (schannelState) {
2131 case SchannelState::InitializeHandshake:
2132 if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
2136 if (!SecIsValidHandle(&credentialHandle))
2138 if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
2142 if (schannelState != SchannelState::PerformHandshake)
2145 case SchannelState::PerformHandshake:
2146 if (!performHandshake()) {
2150 if (schannelState != SchannelState::VerifyHandshake)
2153 case SchannelState::VerifyHandshake:
2156 if (!verifyHandshake()) {
2162 if (schannelState != SchannelState::Done)
2165 case SchannelState::Done:
2167 if (!
q->isEncrypted()) {
2169 emit q->encrypted();
2171 renegotiating =
false;
2179 case SchannelState::Renegotiate:
2180 if (!renegotiate()) {
2198bool TlsCryptographSchannel::checkSslErrors()
2205 const auto &configuration =
q->sslConfiguration();
2208 emit q->sslErrors(sslErrors);
2215 if (doVerifyPeer && doEmitSslError) {
2230void TlsCryptographSchannel::initializeCertificateStores()
2235 const auto &configuration =
q->sslConfiguration();
2237 auto createStoreFromCertificateChain = [](
const QList<QSslCertificate> certChain,
const QSslKey &privateKey) {
2238 const wchar_t *passphrase = L
"";
2243 CRYPT_DATA_BLOB pfxBlob;
2244 pfxBlob.cbData = DWORD(pkcs12.length());
2245 pfxBlob.pbData =
reinterpret_cast<unsigned char *
>(pkcs12.data());
2249 if (!configuration.localCertificateChain().isEmpty()) {
2250 if (configuration.privateKey().isNull()) {
2252 QSslSocket::tr(
"Cannot provide a certificate with no key"));
2255 if (localCertificateStore ==
nullptr) {
2256 localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
2257 configuration.privateKey());
2258 if (localCertificateStore ==
nullptr)
2259 qCWarning(lcTlsBackendSchannel,
"Failed to load certificate chain!");
2263 if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
2264 caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
2269bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
2279 auto tempCertCollection =
QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
2282 CERT_STORE_CREATE_NEW_FLAG,
2284 if (!tempCertCollection) {
2285#ifdef QSSLSOCKET_DEBUG
2286 qCWarning(lcTlsBackendSchannel,
"Failed to create certificate store collection!");
2291 if (rootCertOnDemandLoadingAllowed()) {
2297 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
2298 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L
"ROOT"));
2301#ifdef QSSLSOCKET_DEBUG
2302 qCWarning(lcTlsBackendSchannel,
"Failed to open the system root CA certificate store!");
2305 }
else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
2306#ifdef QSSLSOCKET_DEBUG
2308 "Failed to add the system root CA certificate store to the certificate store "
2314 if (caCertificateStore) {
2315 if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
2316#ifdef QSSLSOCKET_DEBUG
2318 "Failed to add the user's CA certificate store to the certificate store "
2325 if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
2326#ifdef QSSLSOCKET_DEBUG
2328 "Failed to add certificate's origin store to the certificate store collection!");
2333 CERT_CHAIN_PARA parameters;
2334 ZeroMemory(¶meters,
sizeof(parameters));
2335 parameters.cbSize =
sizeof(CERT_CHAIN_PARA);
2336 parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
2337 parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
2338 LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
2339 : szOID_PKIX_KP_CLIENT_AUTH);
2340 parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
2342 QTlsBackend::clearPeerCertificates(d);
2343 const CERT_CHAIN_CONTEXT *chainContext =
nullptr;
2344 auto freeCertChain =
qScopeGuard([&chainContext]() {
2346 CertFreeCertificateChain(chainContext);
2348 BOOL status = CertGetCertificateChain(
nullptr,
2351 tempCertCollection.get(),
2353 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
2357 if (status == FALSE || !chainContext || chainContext->cChain == 0) {
2365 static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
2369 const CERT_CONTEXT *certContext = element->pCertContext;
2376 CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
2378 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
2380 getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
2386 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2396 static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
2397 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2398 | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
2399 | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
2400 if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
2408 DWORD verifyDepth = chain->cElement;
2409 if (
q->peerVerifyDepth() > 0 && DWORD(
q->peerVerifyDepth()) < verifyDepth)
2410 verifyDepth = DWORD(
q->peerVerifyDepth());
2412 const auto &caCertificates =
q->sslConfiguration().caCertificates();
2414 if (!rootCertOnDemandLoadingAllowed()
2415 && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
2423 CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
2424 QSslCertificate certificate = getCertificateFromChainElement(element);
2425 if (!caCertificates.contains(certificate)) {
2434 QList<QSslCertificate> peerCertificateChain;
2435 for (DWORD
i = 0;
i < verifyDepth;
i++) {
2436 CERT_CHAIN_ELEMENT *element = chain->rgpElement[
i];
2437 QSslCertificate certificate = getCertificateFromChainElement(element);
2438 if (certificate.
isNull()) {
2439 const auto &previousCert = !peerCertificateChain.isEmpty() ? peerCertificateChain.last()
2447 const QList<QSslCertificateExtension> extensions = certificate.
extensions();
2449#ifdef QSSLSOCKET_DEBUG
2452 <<
"\nQSslCertificate info:" << certificate
2453 <<
"\nextended error info:" << element->pwszExtendedErrorInfo
2454 <<
"\nerror status:" << element->TrustStatus.dwErrorStatus;
2457 peerCertificateChain.append(certificate);
2458 QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
2468 LONG
result = CertVerifyTimeValidity(
nullptr , element->pCertContext->pCertInfo);
2480 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
2484 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
2491 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
2502 if (netscapeWrongCertType(extensions, isClient))
2503 element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
2505 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
2512 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
2514 const bool isTrustedRoot = caCertificates.contains(certificate);
2515 if (!isTrustedRoot) {
2523 static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
2524 | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
2525 if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
2530 static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
2531 | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2532 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
2533 | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
2534 | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
2535 | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
2536 | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
2537 | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
2538 if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
2545 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2546 auto it = std::find_if(extensions.cbegin(), extensions.cend(),
2548 return extension.name() ==
"basicConstraints"_L1;
2550 if (
it != extensions.cend()) {
2556 if (
i > 0 && !basicConstraints.value(
"ca"_L1,
false).toBool())
2566 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
2574 if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
2579 const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
2580 || certificate.
version() ==
"1";
2583 if (!isRootCertificateAuthority) {
2593 if (!peerCertificateChain.isEmpty())
2594 QTlsBackend::storePeerCertificate(d, peerCertificateChain.constFirst());
2596 const auto &configuration =
q->sslConfiguration();
2604 if (!configuration.peerCertificate().isNull()) {
2609 const QString peerName(verificationPeerName.isEmpty() ?
q->peerName() : verificationPeerName);
2610 if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
2619 }
else if (doVerifyPeer) {
2632bool 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.
bool isValid() const
Returns true if the socket is valid and ready for use; otherwise returns false.
SocketState state() const
Returns the state of the socket.
@ SslInvalidUserDataError
@ SslHandshakeFailedError
SocketError error() const
Returns the type of error that last occurred.
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
bool isOpen() const
Returns true if the device is open; otherwise returns false.
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
bool isEmpty() const noexcept
const T & constFirst() const noexcept
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
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 isNull() const
Returns true if this is a null certificate (i.e., a certificate with no contents); otherwise returns ...
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
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
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...
QSet< QString >::iterator it
QVector3D minimum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW
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()
QList< QSslCertificate >(*)(const QByteArray &pem, int count) X509PemReaderPtr
UNICODE_STRING cbcChainingMode
QList< CRYPTO_SETTINGS > cryptoSettingsForCiphers(const QList< QSslCipher > &ciphers)
bool(*)(QIODevice *device, QSslKey *key, QSslCertificate *cert, QList< QSslCertificate > *caCertificates, const QByteArray &passPhrase) X509Pkcs12ReaderPtr
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
X509PemReaderPtr X509DerReaderPtr
constexpr Initialization Uninitialized
#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
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#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
QSettings settings("MySoft", "Star Runner")
[0]
const char * openSslCipherSuite
const char * encryptionMethod
const char * schannelCipherSuite
QList< QSsl::SslProtocol > protocols
const char * authenticationMethod
const char * keyExchangeMethod