11#include "../shared/qasn1element_p.h"
13#include <QtNetwork/private/qsslcertificate_p.h>
14#include <QtNetwork/private/qsslcipher_p.h>
15#include <QtNetwork/private/qssl_p.h>
17#include <QtNetwork/qsslcertificate.h>
18#include <QtNetwork/qsslcertificateextension.h>
19#include <QtNetwork/qsslsocket.h>
21#include <QtCore/qscopeguard.h>
22#include <QtCore/qoperatingsystemversion.h>
23#include <QtCore/qregularexpression.h>
24#include <QtCore/qdatastream.h>
25#include <QtCore/qmutex.h>
31#if NTDDI_VERSION >= NTDDI_WINBLUE && defined(SECBUFFER_APPLICATION_PROTOCOLS)
33#define SUPPORTS_ALPN 1
37#ifndef SECBUFFER_ALERT
38#define SECBUFFER_ALERT 17
40#ifndef SECPKG_ATTR_APPLICATION_PROTOCOL
41#define SECPKG_ATTR_APPLICATION_PROTOCOL 35
45#ifndef SEC_E_APPLICATION_PROTOCOL_MISMATCH
46#define SEC_E_APPLICATION_PROTOCOL_MISMATCH _HRESULT_TYPEDEF_(0x80090367L
)
50#ifndef SP_PROT_TLS1_SERVER
51#define SP_PROT_TLS1_SERVER 0x00000040
53#ifndef SP_PROT_TLS1_CLIENT
54#define SP_PROT_TLS1_CLIENT 0x00000080
56#ifndef SP_PROT_TLS1_0_SERVER
59#ifndef SP_PROT_TLS1_0_CLIENT
65#ifndef SP_PROT_TLS1_1_SERVER
66#define SP_PROT_TLS1_1_SERVER 0x00000100
68#ifndef SP_PROT_TLS1_1_CLIENT
69#define SP_PROT_TLS1_1_CLIENT 0x00000200
74#ifndef SP_PROT_TLS1_2_SERVER
75#define SP_PROT_TLS1_2_SERVER 0x00000400
77#ifndef SP_PROT_TLS1_2_CLIENT
78#define SP_PROT_TLS1_2_CLIENT 0x00000800
83#ifndef SP_PROT_TLS1_3_SERVER
84#define SP_PROT_TLS1_3_SERVER 0x00001000
86#ifndef SP_PROT_TLS1_3_CLIENT
87#define SP_PROT_TLS1_3_CLIENT 0x00002000
92#ifndef BCRYPT_ECDH_ALGORITHM
93#define BCRYPT_ECDH_ALGORITHM L"ECDH"
95#ifndef BCRYPT_ECDSA_ALGORITHM
96#define BCRYPT_ECDSA_ALGORITHM L"ECDSA"
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
126using namespace Qt::StringLiterals;
132 const QString &passPhrase);
157QT_WARNING_DISABLE_DEPRECATED
159 {
"TLS_AES_256_GCM_SHA384",
"TLS_AES_256_GCM_SHA384",
"",
"",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_3}},
160 {
"TLS_AES_128_GCM_SHA256",
"TLS_AES_128_GCM_SHA256",
"",
"",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_3}},
161 {
"ECDHE-ECDSA-AES256-GCM-SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"ECDH",
"ECDSA",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
162 {
"ECDHE-ECDSA-AES128-GCM-SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"ECDH",
"ECDSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
163 {
"ECDHE-RSA-AES256-GCM-SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"ECDH",
"RSA",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
164 {
"ECDHE-RSA-AES128-GCM-SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"ECDH",
"RSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
165 {
"DHE-RSA-AES256-GCM-SHA384",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"DH",
"RSA",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
166 {
"DHE-RSA-AES128-GCM-SHA256",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"DH",
"RSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
167 {
"ECDHE-ECDSA-AES256-SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"ECDH",
"ECDSA",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
168 {
"ECDHE-ECDSA-AES128-SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"ECDH",
"ECDSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
169 {
"ECDHE-RSA-AES256-SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"ECDH",
"RSA",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
170 {
"ECDHE-RSA-AES128-SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"ECDH",
"RSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
171 {
"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}},
172 {
"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}},
173 {
"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}},
174 {
"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}},
175 {
"AES256-GCM-SHA384",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"RSA",
"RSA",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
176 {
"AES128-GCM-SHA256",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"RSA",
"RSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
177 {
"AES256-SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"RSA",
"RSA",
"AES", 256,
"SHA256", {
QSsl::
TlsV1_2}},
178 {
"AES128-SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"RSA",
"RSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
179 {
"AES256-SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"RSA",
"RSA",
"AES", 256,
"SHA1", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
180 {
"AES128-SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"RSA",
"RSA",
"AES", 128,
"SHA1", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
181 {
"DES-CBC3-SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"RSA",
"RSA",
"3DES", 168,
"SHA1", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
182 {
"NULL-SHA256",
"TLS_RSA_WITH_NULL_SHA256",
"RSA",
"RSA",
"", 0,
"SHA256", {
QSsl::
TlsV1_2}},
183 {
"NULL-SHA",
"TLS_RSA_WITH_NULL_SHA",
"RSA",
"RSA",
"", 0,
"SHA1", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
186 {
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_CHACHA20_POLY1305_SHA256",
"",
"",
"CHACHA20_POLY1305", 0,
"", {
QSsl::
TlsV1_3}},
187 {
"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}},
188 {
"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}},
189 {
"DHE-DSS-AES256-SHA256",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
"DH",
"DSA",
"AES", 256,
"SHA256", {
QSsl::
TlsV1_2}},
190 {
"DHE-DSS-AES128-SHA256",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
"DH",
"DSA",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
191 {
"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}},
192 {
"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}},
193 {
"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}},
194 {
"RC4-SHA",
"TLS_RSA_WITH_RC4_128_SHA",
"RSA",
"RSA",
"RC4", 128,
"SHA1", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
195 {
"RC4-MD5",
"TLS_RSA_WITH_RC4_128_MD5",
"RSA",
"RSA",
"RC4", 128,
"MD5", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
196 {
"DES-CBC-SHA",
"TLS_RSA_WITH_DES_CBC_SHA",
"RSA",
"RSA",
"DES", 56,
"SHA1", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
197 {
"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}},
198 {
"NULL-MD5",
"TLS_RSA_WITH_NULL_MD5",
"RSA",
"RSA",
"", 0,
"MD5", {
QSsl::
TlsV1_2,
QSsl::
TlsV1_1,
QSsl::
TlsV1_0}},
201 {
"PSK-AES256-GCM-SHA384",
"TLS_PSK_WITH_AES_256_GCM_SHA384",
"PSK",
"",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
202 {
"PSK-AES128-GCM-SHA256",
"TLS_PSK_WITH_AES_128_GCM_SHA256",
"PSK",
"",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
203 {
"PSK-AES256-CBC-SHA384",
"TLS_PSK_WITH_AES_256_CBC_SHA384",
"PSK",
"",
"AES", 256,
"SHA384", {
QSsl::
TlsV1_2}},
204 {
"PSK-AES128-CBC-SHA256",
"TLS_PSK_WITH_AES_128_CBC_SHA256",
"PSK",
"",
"AES", 128,
"SHA256", {
QSsl::
TlsV1_2}},
205 {
"PSK-NULL-SHA384",
"TLS_PSK_WITH_NULL_SHA384",
"PSK",
"",
"", 0,
"SHA384", {
QSsl::
TlsV1_2}},
206 {
"PSK-NULL-SHA256",
"TLS_PSK_WITH_NULL_SHA256",
"PSK",
"",
"", 0,
"SHA256", {
QSsl::
TlsV1_2}},
233
234
235
238 static const QList<QSslCipher> defaultCipherList = defaultCiphers();
240 if (defaultCipherList == ciphers) {
245 QList<
const SchannelCipherInfo*> cipherInfo;
247 for (
const auto &cipher : ciphers) {
251 const auto *info = cipherInfoByOpenSslName(cipher.name());
252 if (!cipherInfo.contains(info))
253 cipherInfo.append(info);
256 QList<CRYPTO_SETTINGS> cryptoSettings;
258 const auto assignUnicodeString = [](UNICODE_STRING &unicodeString,
const wchar_t *characters) {
259 unicodeString.Length =
static_cast<USHORT>(wcslen(characters) *
sizeof(WCHAR));
260 unicodeString.MaximumLength = unicodeString.Length +
sizeof(UNICODE_NULL);
261 unicodeString.Buffer =
const_cast<
wchar_t*>(characters);
265 const auto allKeyExchangeAlgorithms = {BCRYPT_RSA_ALGORITHM,
267 BCRYPT_DH_ALGORITHM};
269 for (
const auto &algorithm : allKeyExchangeAlgorithms) {
270 const auto method = QStringView(algorithm);
272 const auto usesMethod = [method](
const SchannelCipherInfo *info) {
273 return QLatin1StringView(info->keyExchangeMethod) == method;
276 const bool exclude = std::none_of(cipherInfo.cbegin(), cipherInfo.cend(), usesMethod);
279 CRYPTO_SETTINGS settings = {};
280 settings.eAlgorithmUsage = TlsParametersCngAlgUsageKeyExchange;
281 assignUnicodeString(settings.strCngAlgId, algorithm);
282 cryptoSettings.append(settings);
287 const auto allAuthenticationAlgorithms = {BCRYPT_RSA_ALGORITHM,
288 BCRYPT_DSA_ALGORITHM,
290 BCRYPT_DH_ALGORITHM};
292 for (
const auto &algorithm : allAuthenticationAlgorithms) {
293 const auto method = QStringView(algorithm);
295 const auto usesMethod = [method](
const SchannelCipherInfo *info) {
296 return QLatin1StringView(info->authenticationMethod) == method;
299 const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
302 CRYPTO_SETTINGS settings = {};
303 settings.eAlgorithmUsage = TlsParametersCngAlgUsageSignature;
304 assignUnicodeString(settings.strCngAlgId, algorithm);
305 cryptoSettings.append(settings);
311 const auto allEncryptionAlgorithms = {BCRYPT_AES_ALGORITHM,
312 BCRYPT_RC4_ALGORITHM,
313 BCRYPT_DES_ALGORITHM,
314 BCRYPT_3DES_ALGORITHM};
316 for (
const auto &algorithm : allEncryptionAlgorithms) {
317 const auto method = QStringView(algorithm);
319 if (method == QLatin1StringView(
"AES")) {
320 bool uses128Bit =
false;
321 bool uses256Bit =
false;
322 bool usesGcm =
false;
323 bool usesCbc =
false;
324 for (
const auto *info : cipherInfo) {
325 if (QLatin1StringView(info->encryptionMethod) == method) {
326 uses128Bit = uses128Bit || (info->encryptionBits == 128);
327 uses256Bit = uses256Bit || (info->encryptionBits == 256);
329 QLatin1StringView(info->schannelCipherSuite).contains(
"_GCM_"_L1);
331 QLatin1StringView(info->schannelCipherSuite).contains(
"_CBC_"_L1);
335 CRYPTO_SETTINGS settings = {};
336 settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
337 assignUnicodeString(settings.strCngAlgId, algorithm);
339 if (usesGcm && !usesCbc) {
340 settings.cChainingModes = 1;
341 settings.rgstrChainingModes = &cbcChainingMode;
342 }
else if (!usesGcm && usesCbc) {
343 settings.cChainingModes = 1;
344 settings.rgstrChainingModes = &gcmChainingMode;
347 if (!uses128Bit && uses256Bit) {
348 settings.dwMinBitLength = 256;
349 cryptoSettings.append(settings);
350 }
else if (uses128Bit && !uses256Bit) {
351 settings.dwMaxBitLength = 128;
352 cryptoSettings.append(settings);
353 }
else if (!uses128Bit && !uses256Bit) {
354 cryptoSettings.append(settings);
357 const auto usesMethod = [method](
const SchannelCipherInfo *info) {
358 return QLatin1StringView(info->encryptionMethod) == method;
361 const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
364 CRYPTO_SETTINGS settings = {};
365 settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
366 assignUnicodeString(settings.strCngAlgId, algorithm);
367 cryptoSettings.append(settings);
373 const auto allHashAlgorithms = {BCRYPT_MD5_ALGORITHM,
374 BCRYPT_SHA1_ALGORITHM,
375 BCRYPT_SHA256_ALGORITHM,
376 BCRYPT_SHA384_ALGORITHM};
378 for (
const auto &algorithm : allHashAlgorithms) {
379 const auto method = QStringView(algorithm);
381 const auto usesMethod = [method](
const SchannelCipherInfo *info) {
382 return QLatin1StringView(info->hashMethod) == method;
385 const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
388 CRYPTO_SETTINGS settings = {};
389 settings.eAlgorithmUsage = TlsParametersCngAlgUsageDigest;
390 assignUnicodeString(settings.strCngAlgId, algorithm);
391 cryptoSettings.append(settings);
395 return cryptoSettings;
400 QList<QSslCipher> ciphers;
402 for (
const auto &cipher : schannelCipherInfo) {
403 if (QLatin1StringView(cipher.schannelCipherSuite) == schannelSuiteName) {
404 for (
const auto &protocol : cipher.protocols) {
406QT_WARNING_DISABLE_DEPRECATED
407 const QString protocolName = (
408 protocol == QSsl::TlsV1_0 ? QStringLiteral(
"TLSv1.0") :
409 protocol == QSsl::TlsV1_1 ? QStringLiteral(
"TLSv1.1") :
410 protocol == QSsl::TlsV1_2 ? QStringLiteral(
"TLSv1.2") :
411 protocol == QSsl::TlsV1_3 ? QStringLiteral(
"TLSv1.3") :
415 ciphers.append(QTlsBackend::createCiphersuite(QLatin1StringView(cipher.openSslCipherSuite),
416 QLatin1StringView(cipher.keyExchangeMethod),
417 QLatin1StringView(cipher.encryptionMethod),
418 QLatin1StringView(cipher.authenticationMethod),
419 cipher.encryptionBits,
420 protocol, protocolName));
430 ULONG contextFunctionsCount = {};
431 PCRYPT_CONTEXT_FUNCTIONS contextFunctions = {};
433 const auto status = BCryptEnumContextFunctions(CRYPT_LOCAL, L"SSL", NCRYPT_SCHANNEL_INTERFACE,
434 &contextFunctionsCount, &contextFunctions);
435 if (!NT_SUCCESS(status)) {
436 qCWarning(lcTlsBackendSchannel,
"Failed to enumerate ciphers");
440 const bool supportsV13 = supportsTls13();
442 QList<QSslCipher> ciphers;
444 for (ULONG index = 0; index < contextFunctions->cFunctions; ++index) {
445 const auto suiteName = QStringView(contextFunctions->rgpszFunctions[index]);
447 const QList<QSslCipher> allCiphers = ciphersByName(suiteName);
449 for (
const auto &cipher : allCiphers) {
450 if (!supportsV13 && (cipher.protocol() == QSsl::TlsV1_3))
453 ciphers.append(cipher);
457 BCryptFreeBuffer(contextFunctions);
464 return std::any_of(ciphers.cbegin(), ciphers.cend(),
465 [](
const QSslCipher &cipher) {
return cipher.protocol() == QSsl::TlsV1_3; });
470bool QSchannelBackend::s_loadedCiphersAndCerts =
false;
473long QSchannelBackend::tlsLibraryVersionNumber()
const
475 const auto os = QOperatingSystemVersion::current();
476 return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
479QString QSchannelBackend::tlsLibraryVersionString()
const
481 const auto os = QOperatingSystemVersion::current();
482 return "Secure Channel, %1 %2.%3.%4"_L1
484 QString::number(os.majorVersion()),
485 QString::number(os.minorVersion()),
486 QString::number(os.microVersion()));
489long QSchannelBackend::tlsLibraryBuildVersionNumber()
const
491 return NTDDI_VERSION;
494QString QSchannelBackend::tlsLibraryBuildVersionString()
const
496 return "Secure Channel (NTDDI: 0x%1)"_L1
497 .arg(QString::number(NTDDI_VERSION, 16).toUpper());
500void QSchannelBackend::ensureInitialized()
const
502 ensureInitializedImplementation();
505void QSchannelBackend::ensureInitializedImplementation()
507 const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
508 if (s_loadedCiphersAndCerts)
510 s_loadedCiphersAndCerts =
true;
512 setDefaultCaCertificates(systemCaCertificatesImplementation());
514 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(
true);
516 resetDefaultCiphers();
519void QSchannelBackend::resetDefaultCiphers()
521 setDefaultSupportedCiphers(QTlsPrivate::defaultCiphers());
522 setDefaultCiphers(QTlsPrivate::defaultCiphers());
525QString QSchannelBackend::backendName()
const
527 return builtinBackendNames[nameIndexSchannel];
530QList<QSsl::SslProtocol> QSchannelBackend::supportedProtocols()
const
532 QList<QSsl::SslProtocol> protocols;
534 protocols << QSsl::AnyProtocol;
535 protocols << QSsl::SecureProtocols;
537QT_WARNING_DISABLE_DEPRECATED
538 protocols << QSsl::TlsV1_0;
539 protocols << QSsl::TlsV1_0OrLater;
540 protocols << QSsl::TlsV1_1;
541 protocols << QSsl::TlsV1_1OrLater;
543 protocols << QSsl::TlsV1_2;
544 protocols << QSsl::TlsV1_2OrLater;
546 if (supportsTls13()) {
547 protocols << QSsl::TlsV1_3;
548 protocols << QSsl::TlsV1_3OrLater;
554QList<QSsl::SupportedFeature> QSchannelBackend::supportedFeatures()
const
556 QList<QSsl::SupportedFeature> features;
559 features << QSsl::SupportedFeature::ClientSideAlpn;
560 features << QSsl::SupportedFeature::ServerSideAlpn;
566QList<QSsl::ImplementedClass> QSchannelBackend::implementedClasses()
const
568 QList<QSsl::ImplementedClass> classes;
570 classes << QSsl::ImplementedClass::Socket;
571 classes << QSsl::ImplementedClass::Certificate;
572 classes << QSsl::ImplementedClass::Key;
577QTlsPrivate::TlsKey *QSchannelBackend::createKey()
const
582QTlsPrivate::X509Certificate *QSchannelBackend::createCertificate()
const
587QList<QSslCertificate> QSchannelBackend::systemCaCertificates()
const
589 return systemCaCertificatesImplementation();
592QTlsPrivate::TlsCryptograph *QSchannelBackend::createTlsCryptograph()
const
597QList<QSslCertificate> QSchannelBackend::systemCaCertificatesImplementation()
601 QList<QSslCertificate> systemCerts;
604 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
605 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
608 PCCERT_CONTEXT pc =
nullptr;
609 while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
610 CERT_FIND_ANY,
nullptr, pc))) {
611 systemCerts.append(QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(pc));
617QTlsPrivate::X509PemReaderPtr QSchannelBackend::X509PemReader()
const
619 return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
622QTlsPrivate::X509DerReaderPtr QSchannelBackend::X509DerReader()
const
624 return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
627QTlsPrivate::X509Pkcs12ReaderPtr QSchannelBackend::X509Pkcs12Reader()
const
629 return QTlsPrivate::X509CertificateSchannel::importPkcs12;
634SecBuffer createSecBuffer(
void *ptr,
unsigned long length,
unsigned long bufferType)
636 return SecBuffer{ length, bufferType, ptr };
639SecBuffer createSecBuffer(QByteArray &buffer,
unsigned long bufferType)
641 return createSecBuffer(buffer.data(),
static_cast<
unsigned long>(buffer.length()), bufferType);
644QString schannelErrorToString(qint32 status)
647 case SEC_E_INSUFFICIENT_MEMORY:
648 return QSslSocket::tr(
"Insufficient memory");
649 case SEC_E_INTERNAL_ERROR:
650 return QSslSocket::tr(
"Internal error");
651 case SEC_E_INVALID_HANDLE:
652 return QSslSocket::tr(
"An internal handle was invalid");
653 case SEC_E_INVALID_TOKEN:
654 return QSslSocket::tr(
"An internal token was invalid");
655 case SEC_E_LOGON_DENIED:
658 return QSslSocket::tr(
"Access denied");
659 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
660 return QSslSocket::tr(
"No authority could be contacted for authorization");
661 case SEC_E_NO_CREDENTIALS:
662 return QSslSocket::tr(
"No credentials");
663 case SEC_E_TARGET_UNKNOWN:
664 return QSslSocket::tr(
"The target is unknown or unreachable");
665 case SEC_E_UNSUPPORTED_FUNCTION:
666 return QSslSocket::tr(
"An unsupported function was requested");
667 case SEC_E_WRONG_PRINCIPAL:
669 return QSslSocket::tr(
"The hostname provided does not match the one received from the peer");
671 return QSslSocket::tr(
"No common protocol exists between the client and the server");
672 case SEC_E_ILLEGAL_MESSAGE:
673 return QSslSocket::tr(
"Unexpected or badly-formatted message received");
674 case SEC_E_ENCRYPT_FAILURE:
675 return QSslSocket::tr(
"The data could not be encrypted");
676 case SEC_E_DECRYPT_FAILURE:
677 return QSslSocket::tr(
"The data could not be decrypted");
678 case SEC_E_ALGORITHM_MISMATCH:
679 return QSslSocket::tr(
"No cipher suites in common");
680 case SEC_E_UNKNOWN_CREDENTIALS:
682 return QSslSocket::tr(
"The credentials were not recognized / Invalid argument");
683 case SEC_E_MESSAGE_ALTERED:
686 return QSslSocket::tr(
"The message was tampered with, damaged or out of sequence.");
687 case SEC_E_OUT_OF_SEQUENCE:
688 return QSslSocket::tr(
"A message was received out of sequence.");
689 case SEC_E_CONTEXT_EXPIRED:
690 return QSslSocket::tr(
"The TLS/SSL connection has been closed");
692 return QSslSocket::tr(
"Unknown error occurred: %1").arg(status);
698 static bool supported = []() {
699 const auto current = QOperatingSystemVersion::current();
702 QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221);
703 return current >= minimum;
709DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
711 DWORD protocols = SP_PROT_NONE;
713 case QSsl::UnknownProtocol:
716QT_WARNING_DISABLE_DEPRECATED
718 case QSsl::DtlsV1_0OrLater:
721 case QSsl::DtlsV1_2OrLater:
723 case QSsl::AnyProtocol:
729QT_WARNING_DISABLE_DEPRECATED
744 protocols = DWORD(-1);
747QT_WARNING_DISABLE_DEPRECATED
748 case QSsl::TlsV1_0OrLater:
753 case QSsl::TlsV1_1OrLater:
757 case QSsl::SecureProtocols:
758 case QSsl::TlsV1_2OrLater:
761 case QSsl::TlsV1_3OrLater:
764 else if (protocol == QSsl::TlsV1_3OrLater)
765 protocols = DWORD(-1);
774DWORD negatedSchannelProtocols(DWORD wantedProtocols)
776 DWORD protocols = SP_PROT_ALL;
777 protocols &= ~wantedProtocols;
782
783
784
785
786
787
788QSsl::SslProtocol toQtSslProtocol(DWORD protocol)
790#define MAP_PROTOCOL(sp_protocol, q_protocol)
791 if (protocol & sp_protocol) {
792 Q_ASSERT(!(protocol & ~sp_protocol));
797QT_WARNING_DISABLE_DEPRECATED
805 return QSsl::UnknownProtocol;
809
810
811
812bool netscapeWrongCertType(
const QList<QSslCertificateExtension> &extensions,
bool isClient,
bool isLeaf)
814 const auto netscapeIt = std::find_if(
815 extensions.cbegin(), extensions.cend(),
816 [](
const QSslCertificateExtension &extension) {
817 return extension.oid() == u"2.16.840.1.113730.1.1";
819 if (netscapeIt != extensions.cend()) {
820 const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
821 int netscapeCertType = 0;
822 QDataStream dataStream(netscapeCertTypeByte);
823 dataStream >> netscapeCertType;
824 if (dataStream.status() != QDataStream::Status::Ok)
826 const int expectedPeerCertType = [&]() {
828 return isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
829 : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
831 return NETSCAPE_SSL_CA_CERT_TYPE;
833 if ((netscapeCertType & expectedPeerCertType) == 0)
840
841
842
843
844
845
846bool isCertificateAuthority(
const QList<QSslCertificateExtension> &extensions)
848 auto it = std::find_if(extensions.cbegin(), extensions.cend(),
849 [](
const QSslCertificateExtension &extension) {
850 return extension.name() ==
"basicConstraints"_L1;
852 if (it != extensions.cend()) {
853 QVariantMap basicConstraints = it->value().toMap();
854 return basicConstraints.value(
"ca"_L1,
false).toBool();
860
861
862
863
864bool matchesContextRequirements(DWORD attributes, DWORD requirements,
865 QSslSocket::PeerVerifyMode verifyMode,
868#ifdef QSSLSOCKET_DEBUG
869#define DEBUG_WARN(message) qCWarning(lcTlsBackendSchannel, message)
871#define DEBUG_WARN(message)
874#define CHECK_ATTRIBUTE(attributeName)
876 const DWORD req##attributeName = isClient ? ISC_REQ_##attributeName : ASC_REQ_##attributeName;
877 const DWORD ret##attributeName = isClient ? ISC_RET_##attributeName : ASC_RET_##attributeName;
878 if (!(requirements & req##attributeName) != !(attributes & ret##attributeName)) {
879 DEBUG_WARN("Missing attribute \"" #attributeName "\"");
888 if (verifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
893 const auto reqManualCredValidation = ISC_REQ_MANUAL_CRED_VALIDATION;
894 const auto retManualCredValidation = ISC_RET_MANUAL_CRED_VALIDATION;
895 if (!(requirements & reqManualCredValidation) != !(attributes & retManualCredValidation)) {
896 DEBUG_WARN(
"Missing attribute \"MANUAL_CRED_VALIDATION\"");
902#undef CHECK_ATTRIBUTE
906template<
typename Required,
typename Actual>
907Required const_reinterpret_cast(Actual *p)
913QByteArray createAlpnString(
const QByteArrayList &nextAllowedProtocols)
915 QByteArray alpnString;
916 if (!nextAllowedProtocols.isEmpty()) {
917 const QByteArray names = [&nextAllowedProtocols]() {
918 QByteArray protocolString;
919 for (QByteArray proto : nextAllowedProtocols) {
920 if (proto.size() > 255) {
921 qCWarning(lcTlsBackendSchannel)
922 <<
"TLS ALPN extension" << proto <<
"is too long and will be ignored.";
924 }
else if (proto.isEmpty()) {
927 protocolString +=
char(proto.length()) + proto;
929 return protocolString;
934 const quint16 namesSize = names.size();
935 const quint32 alpnId = SecApplicationProtocolNegotiationExt_ALPN;
936 const quint32 totalSize =
sizeof(alpnId) +
sizeof(namesSize) + namesSize;
937 alpnString = QByteArray::fromRawData(
reinterpret_cast<
const char *>(&totalSize),
sizeof(totalSize))
938 + QByteArray::fromRawData(
reinterpret_cast<
const char *>(&alpnId),
sizeof(alpnId))
939 + QByteArray::fromRawData(
reinterpret_cast<
const char *>(&namesSize),
sizeof(namesSize))
946qint64 readToBuffer(QByteArray &buffer, QTcpSocket *plainSocket)
948 Q_ASSERT(plainSocket);
949 static const qint64 shrinkCutoff = 1024 * 12;
950 static const qint64 defaultRead = 1024 * 16;
951 qint64 bytesRead = 0;
953 const auto toRead =
std::min(defaultRead, plainSocket->bytesAvailable());
955 const auto bufferSize = buffer.size();
956 buffer.reserve(bufferSize + toRead);
957 buffer.resize(bufferSize + toRead);
958 bytesRead = plainSocket->read(buffer.data() + bufferSize, toRead);
959 buffer.resize(bufferSize + bytesRead);
961 if (buffer.size() < shrinkCutoff && buffer.capacity() > defaultRead)
962 buffer.shrink_to_fit();
968void retainExtraData(QByteArray &buffer,
const SecBuffer &secBuffer)
970 Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
971 if (
int(secBuffer.cbBuffer) >= buffer.size())
974#ifdef QSSLSOCKET_DEBUG
975 qCDebug(lcTlsBackendSchannel,
"We got SECBUFFER_EXTRA, will retain %lu bytes",
978 std::move(buffer.end() - secBuffer.cbBuffer, buffer.end(), buffer.begin());
979 buffer.resize(secBuffer.cbBuffer);
982qint64 checkIncompleteData(
const SecBuffer &secBuffer)
984 if (secBuffer.BufferType == SECBUFFER_MISSING) {
985#ifdef QSSLSOCKET_DEBUG
986 qCDebug(lcTlsBackendSchannel,
"Need %lu more bytes.", secBuffer.cbBuffer);
988 return secBuffer.cbBuffer;
993DWORD defaultCredsFlag()
995 return qEnvironmentVariableIsSet(
"QT_SCH_DEFAULT_CREDS") ? 0 : SCH_CRED_NO_DEFAULT_CREDS;
1004 SecInvalidateHandle(&credentialHandle);
1005 SecInvalidateHandle(&contextHandle);
1006 QSchannelBackend::ensureInitializedImplementation();
1011 closeCertificateStores();
1012 deallocateContext();
1013 freeCredentialsHandle();
1029 if (tokenLength == 0)
1033 auto *plainSocket = d->plainTcpSocket();
1034 Q_ASSERT(plainSocket);
1035 if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
1036 || !plainSocket->isOpen()) {
1040 const qint64 written = plainSocket->write(
static_cast<
const char *>(token), tokenLength);
1041 if (written != qint64(tokenLength)) {
1044 setErrorAndEmit(d, plainSocket->error(), plainSocket->errorString());
1056 const auto verificationPeerName = d->verificationName();
1057 return verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
1065 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
1068 req |= ISC_REQ_ALLOCATE_MEMORY;
1069 req |= ISC_REQ_CONFIDENTIALITY;
1070 req |= ISC_REQ_REPLAY_DETECT;
1071 req |= ISC_REQ_SEQUENCE_DETECT;
1072 req |= ISC_REQ_STREAM;
1075 req |= ISC_REQ_MANUAL_CRED_VALIDATION;
1077 switch (q->peerVerifyMode()) {
1078 case QSslSocket::PeerVerifyMode::VerifyNone:
1080 case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
1081 case QSslSocket::PeerVerifyMode::QueryPeer:
1083 case QSslSocket::PeerVerifyMode::VerifyPeer:
1084 req |= ISC_REQ_MUTUAL_AUTH;
1096 const auto &configuration = q->sslConfiguration();
1098 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1100 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
1101 DWORD protocols = toSchannelProtocol(configuration.protocol());
1102 if (protocols == DWORD(-1)) {
1103 setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
1104 QSslSocket::tr(
"Invalid protocol chosen"));
1109 initializeCertificateStores();
1114 if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
1117 PCCERT_CONTEXT localCertificate = localCertificateCtxt.get();
1118 const DWORD certsCount = localCertificate ? 1 : 0;
1120 const QList<QSslCipher> ciphers = configuration.ciphers();
1121 if (!ciphers.isEmpty() && !containsTls13Cipher(ciphers))
1124 QList<CRYPTO_SETTINGS> cryptoSettings;
1125 if (!ciphers.isEmpty())
1126 cryptoSettings = cryptoSettingsForCiphers(ciphers);
1128 TLS_PARAMETERS tlsParameters = {
1131 negatedSchannelProtocols(protocols),
1132 static_cast<DWORD>(cryptoSettings.size()),
1133 (cryptoSettings.isEmpty() ?
nullptr : cryptoSettings.data()),
1137 SCH_CREDENTIALS credentials = {
1138 SCH_CREDENTIALS_VERSION,
1146 SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(),
1151 TimeStamp expiration{};
1152 auto status = AcquireCredentialsHandle(
nullptr,
1153 const_cast<
wchar_t *>(UNISP_NAME),
1154 isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND,
1163#ifdef QT_WIN_SERVER_2016_COMPAT
1164 if (status == SEC_E_UNKNOWN_CREDENTIALS) {
1165 if (!ciphers.isEmpty()) {
1166 qCWarning(lcTlsBackendSchannel,
1167 "Cipher suite restrictions are not supported by the "
1168 "Windows Server 2016 compatibility fallback");
1169 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
1173 SCHANNEL_CRED credentialsV4 = { SCHANNEL_CRED_VERSION,
1185 SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
1186 | defaultCredsFlag(),
1189 status = AcquireCredentialsHandle(
nullptr,
1190 const_cast<
wchar_t *>(UNISP_NAME),
1191 isClient ? SECPKG_CRED_OUTBOUND
1192 : SECPKG_CRED_INBOUND,
1203 if (status != SEC_E_OK) {
1204 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
1212 if (SecIsValidHandle(&contextHandle)) {
1213 DeleteSecurityContext(&contextHandle);
1214 SecInvalidateHandle(&contextHandle);
1220 if (SecIsValidHandle(&credentialHandle)) {
1221 FreeCredentialsHandle(&credentialHandle);
1222 SecInvalidateHandle(&credentialHandle);
1228 localCertificateCtxt.reset();
1229 localCertificateStore.reset();
1230 peerCertificateStore.reset();
1231 caCertificateStore.reset();
1239 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1240 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1241 Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode);
1242 ULONG contextReq = getContextRequirements();
1244 SecBuffer outBuffers[3];
1245 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1247 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1248 auto freeBuffers = qScopeGuard([&outBuffers]() {
1249 for (
auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1250 if (outBuffers[i].pvBuffer)
1251 FreeContextBuffer(outBuffers[i].pvBuffer);
1254 SecBufferDesc outputBufferDesc{
1256 ARRAYSIZE(outBuffers),
1262 SecBufferDesc alpnBufferDesc;
1263 bool useAlpn =
false;
1265 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
1266 QByteArray alpnString = createAlpnString(q->sslConfiguration().allowedNextProtocols());
1267 useAlpn = !alpnString.isEmpty();
1268 SecBuffer alpnBuffers[1];
1269 alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1272 ARRAYSIZE(alpnBuffers),
1277 const QString encodedTargetName = QUrl::fromUserInput(targetName()).host(QUrl::EncodeUnicode);
1278 auto status = InitializeSecurityContext(&credentialHandle,
1280 const_reinterpret_cast<SEC_WCHAR *>(encodedTargetName.utf16()),
1284 useAlpn ? &alpnBufferDesc :
nullptr,
1294 if (status != SEC_I_CONTINUE_NEEDED) {
1295 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1296 QSslSocket::tr(
"Error creating SSL context (%1)").arg(schannelErrorToString(status)));
1300 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1302 schannelState = SchannelState::PerformHandshake;
1311 auto *plainSocket = d->plainTcpSocket();
1312 Q_ASSERT(plainSocket);
1314 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1315 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1316 Q_ASSERT(d->tlsMode() == QSslSocket::SslServerMode);
1317 ULONG contextReq = getContextRequirements();
1319 if (missingData > plainSocket->bytesAvailable())
1323 readToBuffer(intermediateBuffer, plainSocket);
1324 if (intermediateBuffer.isEmpty())
1327 SecBuffer inBuffers[2];
1328 inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1331 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
1333 QByteArray alpnString = createAlpnString(q->sslConfiguration().allowedNextProtocols());
1334 if (!alpnString.isEmpty()) {
1335 inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1339 inBuffers[1] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1342 SecBufferDesc inputBufferDesc{
1344 ARRAYSIZE(inBuffers),
1348 SecBuffer outBuffers[3];
1349 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1351 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1352 auto freeBuffers = qScopeGuard([&outBuffers]() {
1353 for (
auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1354 if (outBuffers[i].pvBuffer)
1355 FreeContextBuffer(outBuffers[i].pvBuffer);
1358 SecBufferDesc outputBufferDesc{
1360 ARRAYSIZE(outBuffers),
1365 auto status = AcceptSecurityContext(
1377 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1379 missingData = checkIncompleteData(outBuffers[0]);
1383 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
1387 retainExtraData(intermediateBuffer, inBuffers[1]);
1389 intermediateBuffer.resize(0);
1392 if (status != SEC_I_CONTINUE_NEEDED) {
1393 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1394 QSslSocket::tr(
"Error creating SSL context (%1)").arg(schannelErrorToString(status)));
1397 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1399 schannelState = SchannelState::PerformHandshake;
1406 auto *plainSocket = d->plainTcpSocket();
1407 Q_ASSERT(plainSocket);
1409 if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
1410 || !plainSocket->isOpen()) {
1411 setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
1412 QSslSocket::tr(
"The TLS/SSL connection has been closed"));
1415 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1416 Q_ASSERT(SecIsValidHandle(&contextHandle));
1417 Q_ASSERT(schannelState == SchannelState::PerformHandshake);
1419#ifdef QSSLSOCKET_DEBUG
1420 qCDebug(lcTlsBackendSchannel,
"Bytes available from socket: %lld",
1421 plainSocket->bytesAvailable());
1422 qCDebug(lcTlsBackendSchannel,
"intermediateBuffer size: %d", intermediateBuffer.size());
1425 if (missingData > plainSocket->bytesAvailable())
1429 readToBuffer(intermediateBuffer, plainSocket);
1430 if (intermediateBuffer.isEmpty())
1433 SecBuffer outBuffers[3] = {};
1434 const auto freeOutBuffers = [&outBuffers]() {
1435 for (
auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1436 if (outBuffers[i].pvBuffer)
1437 FreeContextBuffer(outBuffers[i].pvBuffer);
1440 const auto outBuffersGuard = qScopeGuard(freeOutBuffers);
1446 SECURITY_STATUS status;
1449 SecBuffer inputBuffers[2];
1450 inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1451 inputBuffers[1] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1452 SecBufferDesc inputBufferDesc{
1454 ARRAYSIZE(inputBuffers),
1459 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1461 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1462 SecBufferDesc outputBufferDesc{
1464 ARRAYSIZE(outBuffers),
1468 ULONG contextReq = getContextRequirements();
1470 status = InitializeSecurityContext(
1473 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1485 if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
1489 retainExtraData(intermediateBuffer, inputBuffers[1]);
1490 }
else if (status != SEC_E_INCOMPLETE_MESSAGE) {
1492 intermediateBuffer.resize(0);
1496 }
while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
1501 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1503 schannelState = SchannelState::VerifyHandshake;
1505 case SEC_I_CONTINUE_NEEDED:
1506 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1510 case SEC_I_INCOMPLETE_CREDENTIALS:
1513 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1514 QSslSocket::tr(
"Server did not accept any certificate we could present."));
1516 case SEC_I_CONTEXT_EXPIRED:
1518 if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
1519 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1523 setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
1524 QSslSocket::tr(
"The TLS/SSL connection has been closed"));
1527 case SEC_E_INCOMPLETE_MESSAGE:
1529 missingData = checkIncompleteData(outBuffers[0]);
1531 case SEC_E_ALGORITHM_MISMATCH:
1532 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1533 QSslSocket::tr(
"Algorithm mismatch"));
1541 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1542 QSslSocket::tr(
"Handshake failed: %1").arg(schannelErrorToString(status)));
1550 const auto &configuration = q->sslConfiguration();
1554 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
1555#define CHECK_STATUS(status)
1556 if (status != SEC_E_OK) {
1557 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1558 QSslSocket::tr("Failed to query the TLS context: %1")
1559 .arg(schannelErrorToString(status)));
1564 if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
1565 configuration.peerVerifyMode(), isClient)) {
1566 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1567 QSslSocket::tr(
"Did not get the required attributes for the connection."));
1572 auto status = QueryContextAttributes(&contextHandle,
1573 SECPKG_ATTR_STREAM_SIZES,
1578 status = QueryContextAttributes(&contextHandle,
1579 SECPKG_ATTR_CIPHER_INFO,
1583 status = QueryContextAttributes(&contextHandle,
1584 SECPKG_ATTR_CONNECTION_INFO,
1589 const auto allowedProtos = configuration.allowedNextProtocols();
1590 if (!allowedProtos.isEmpty()) {
1591 SecPkgContext_ApplicationProtocol alpn;
1592 status = QueryContextAttributes(&contextHandle,
1593 SECPKG_ATTR_APPLICATION_PROTOCOL,
1595 CHECK_STATUS(status);
1596 if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
1597 QByteArray negotiatedProto = QByteArray((
const char *)alpn.ProtocolId,
1598 alpn.ProtocolIdSize);
1599 if (!allowedProtos.contains(negotiatedProto)) {
1600 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1601 QSslSocket::tr(
"Unwanted protocol was negotiated"));
1604 QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
1605 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
1607 QTlsBackend::setNegotiatedProtocol(d, {});
1608 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationUnsupported);
1616 CERT_CONTEXT *certificateContext =
nullptr;
1617 auto freeCertificate = qScopeGuard([&certificateContext]() {
1618 if (certificateContext)
1619 CertFreeCertificateContext(certificateContext);
1621 status = QueryContextAttributes(&contextHandle,
1622 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1623 &certificateContext);
1630 if ((!isClient && configuration.peerVerifyMode() == QSslSocket::PeerVerifyMode::VerifyPeer)
1631 || (isClient && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::VerifyNone
1632 && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::QueryPeer)) {
1633 if (status != SEC_E_OK) {
1634#ifdef QSSLSOCKET_DEBUG
1635 qCDebug(lcTlsBackendSchannel) <<
"Couldn't retrieve peer certificate, status:"
1636 << schannelErrorToString(status);
1638 const QSslError error{ QSslError::NoPeerCertificate };
1640 emit q->peerVerifyError(error);
1641 if (q->state() != QAbstractSocket::ConnectedState)
1647 if (certificateContext && !verifyCertContext(certificateContext))
1650 if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState) {
1651#ifdef QSSLSOCKET_DEBUG
1652 qCDebug(lcTlsBackendSchannel) <<
__func__ <<
"was unsuccessful. Paused:" << d->isPaused();
1655 return d->isPaused() && q->state() == QAbstractSocket::ConnectedState;
1658 schannelState = SchannelState::Done;
1666 SecBuffer outBuffers[3];
1667 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
1669 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
1670 auto freeBuffers = qScopeGuard([&outBuffers]() {
1671 for (
auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1672 if (outBuffers[i].pvBuffer)
1673 FreeContextBuffer(outBuffers[i].pvBuffer);
1676 SecBufferDesc outputBufferDesc{
1678 ARRAYSIZE(outBuffers),
1682 ULONG contextReq = getContextRequirements();
1684 SECURITY_STATUS status;
1685 if (d->tlsMode() == QSslSocket::SslClientMode) {
1686 status = InitializeSecurityContext(&credentialHandle,
1688 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
1700 status = AcceptSecurityContext(
1712 if (status == SEC_I_CONTINUE_NEEDED) {
1713 schannelState = SchannelState::PerformHandshake;
1714 return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
1715 }
else if (status == SEC_E_OK) {
1716 schannelState = SchannelState::PerformHandshake;
1719 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1720 QSslSocket::tr(
"Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
1725
1726
1727
1732 closeCertificateStores();
1733 deallocateContext();
1734 freeCredentialsHandle();
1737 connectionInfo = {};
1740 contextAttributes = 0;
1741 intermediateBuffer.clear();
1742 schannelState = SchannelState::InitializeHandshake;
1745 d->setEncrypted(
false);
1747 renegotiating =
false;
1756 if (q->isEncrypted())
1766 if (q->isEncrypted())
1774 MessageBufferResult result;
1775 QByteArray &fullMessage = result.messageBuffer;
1778 auto &writeBuffer = d->tlsWriteBuffer();
1780 auto allocateMessage = [&fullMessage](qsizetype size) -> QSpan<
char> {
1781 auto targetSize = fullMessage.size() + size;
1782 if (fullMessage.capacity() < targetSize) {
1783 qsizetype newSize = fullMessage.capacity() * 2;
1784 if (newSize < targetSize)
1785 newSize = targetSize;
1786 fullMessage.reserve(newSize);
1788 fullMessage.resizeForOverwrite(targetSize);
1789 return QSpan(fullMessage).subspan(fullMessage.size() - size);
1792 const int headerSize =
int(streamSizes.cbHeader);
1793 const int trailerSize =
int(streamSizes.cbTrailer);
1794 constexpr qsizetype MessageBufferThreshold = 128 * 1024;
1796 qint64 writeBufferSize = 0;
1797 while ((writeBufferSize = writeBuffer.size()) > 0
1798 && fullMessage.size() < MessageBufferThreshold) {
1800 const int bodySize =
int(
std::min(writeBufferSize, qint64(streamSizes.cbMaximumMessage)));
1801 const qsizetype messageSize = headerSize + bodySize + trailerSize;
1802 QSpan buffer = allocateMessage(messageSize);
1803 char *header = buffer.data();
1804 char *body = header + headerSize;
1805 char *trailer = body + bodySize;
1808 qint64 copied = writeBuffer.peek(body, bodySize);
1809 Q_ASSERT(copied == bodySize);
1812 SecBuffer inputBuffers[] = {
1813 createSecBuffer(header, headerSize, SECBUFFER_STREAM_HEADER),
1814 createSecBuffer(body, bodySize, SECBUFFER_DATA),
1815 createSecBuffer(trailer, trailerSize, SECBUFFER_STREAM_TRAILER),
1816 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY)
1818 SecBufferDesc message = {
1820 ARRAYSIZE(inputBuffers),
1824 if (
auto status = EncryptMessage(&contextHandle, 0, &message, 0); status != SEC_E_OK) {
1825 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1826 QSslSocket::tr(
"Schannel failed to encrypt data: %1")
1827 .arg(schannelErrorToString(status)));
1828 result.messageBuffer.chop(messageSize);
1832 writeBuffer.free(bodySize);
1835 auto finalSize = qsizetype(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer
1836 + inputBuffers[2].cbBuffer);
1837 fullMessage.chop(messageSize - finalSize);
1847 auto *plainSocket = d->plainTcpSocket();
1848 Q_ASSERT(plainSocket);
1850 if (d->tlsMode() == QSslSocket::UnencryptedMode)
1854 if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
1855 || !plainSocket->isOpen()) {
1859 if (schannelState != SchannelState::Done) {
1864 auto &buffer = d->tlsBuffer();
1865 if (q->isEncrypted()) {
1866 qint64 totalBytesWritten = 0;
1867 while (d->tlsWriteBuffer().size() > 0) {
1868 MessageBufferResult r = getNextEncryptedMessage();
1869 if (r.messageBuffer.isEmpty() && !r.ok)
1871 QByteArray fullMessage =
std::move(r.messageBuffer);
1872 const qint64 bytesWritten = plainSocket->write(fullMessage);
1873 if (!r.ok && bytesWritten < 0)
1875#ifdef QSSLSOCKET_DEBUG
1876 qCDebug(lcTlsBackendSchannel,
"Wrote %lld of total %d bytes", bytesWritten,
1877 fullMessage.size());
1879 if (bytesWritten >= 0) {
1880 totalBytesWritten += bytesWritten;
1882 setErrorAndEmit(d, plainSocket->error(), plainSocket->errorString());
1887 if (totalBytesWritten > 0) {
1889 bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
1890 if (!emittedBytesWritten) {
1891 emittedBytesWritten =
true;
1892 emit q->bytesWritten(totalBytesWritten);
1893 emittedBytesWritten =
false;
1895 emit q->channelBytesWritten(0, totalBytesWritten);
1900 bool hadIncompleteData =
false;
1901 const auto readBufferMaxSize = d->maxReadBufferSize();
1902 while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
1903 if (missingData > plainSocket->bytesAvailable()
1904 && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
1905#ifdef QSSLSOCKET_DEBUG
1906 qCDebug(lcTlsBackendSchannel,
"We're still missing %lld bytes, will check later.",
1913 const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
1914#ifdef QSSLSOCKET_DEBUG
1915 qCDebug(lcTlsBackendSchannel,
"Read %lld encrypted bytes from the socket", bytesRead);
1917 if (intermediateBuffer.length() == 0 || (hadIncompleteData && bytesRead == 0)) {
1918#ifdef QSSLSOCKET_DEBUG
1919 qCDebug(lcTlsBackendSchannel,
1920 hadIncompleteData ?
"No new data received, leaving loop!"
1921 :
"Nothing to decrypt, leaving loop!");
1925 hadIncompleteData =
false;
1926#ifdef QSSLSOCKET_DEBUG
1927 qCDebug(lcTlsBackendSchannel,
"Total amount of bytes to decrypt: %d",
1928 intermediateBuffer.length());
1931 SecBuffer dataBuffer[4]{
1932 createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
1933 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY),
1934 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY),
1935 createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY)
1937 SecBufferDesc message{
1939 ARRAYSIZE(dataBuffer),
1942 auto status = DecryptMessage(&contextHandle, &message, 0,
nullptr);
1943 if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
1945 if (dataBuffer[1].cbBuffer > 0) {
1949 buffer.append(
static_cast<
char *>(dataBuffer[1].pvBuffer),
1950 dataBuffer[1].cbBuffer);
1951 totalRead += dataBuffer[1].cbBuffer;
1952#ifdef QSSLSOCKET_DEBUG
1953 qCDebug(lcTlsBackendSchannel,
"Decrypted %lu bytes. New read buffer size: %d",
1954 dataBuffer[1].cbBuffer, buffer.size());
1957 if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
1961 retainExtraData(intermediateBuffer, dataBuffer[3]);
1963 intermediateBuffer.resize(0);
1967 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1968 missingData = checkIncompleteData(dataBuffer[0]);
1969#ifdef QSSLSOCKET_DEBUG
1970 qCDebug(lcTlsBackendSchannel,
"We didn't have enough data to decrypt anything, will try again!");
1973 hadIncompleteData =
true;
1974 }
else if (status == SEC_E_INVALID_HANDLE) {
1976 qCWarning(lcTlsBackendSchannel,
"The internal SSPI handle is invalid!");
1978 }
else if (status == SEC_E_INVALID_TOKEN) {
1983 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
1985 }
else if (status == SEC_E_MESSAGE_ALTERED) {
1989 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1990 schannelErrorToString(status));
1992 }
else if (status == SEC_E_OUT_OF_SEQUENCE) {
1998 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1999 schannelErrorToString(status));
2001 }
else if (status == SEC_E_DECRYPT_FAILURE) {
2006 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
2008 }
else if (status == SEC_I_CONTEXT_EXPIRED) {
2012 }
else if (status == SEC_I_RENEGOTIATE) {
2014#ifdef QSSLSOCKET_DEBUG
2015 qCDebug(lcTlsBackendSchannel,
"The peer wants to renegotiate.");
2017 schannelState = SchannelState::Renegotiate;
2018 renegotiating =
true;
2027 if (
bool *readyReadEmittedPointer = d->readyReadPointer())
2028 *readyReadEmittedPointer =
true;
2029 emit q->readyRead();
2030 emit q->channelReadyRead(0);
2038 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
2039 DWORD shutdownToken = SCHANNEL_SHUTDOWN;
2040 SecBuffer buffer = createSecBuffer(&shutdownToken,
sizeof(DWORD), SECBUFFER_TOKEN);
2041 SecBufferDesc token{
2046 auto status = ApplyControlToken(&contextHandle, &token);
2048 if (status != SEC_E_OK) {
2049#ifdef QSSLSOCKET_DEBUG
2050 qCDebug(lcTlsBackendSchannel)
2051 <<
"Failed to apply shutdown control token:" << schannelErrorToString(status);
2056 SecBuffer outBuffers[3];
2057 outBuffers[0] = createSecBuffer(
nullptr, 0, SECBUFFER_TOKEN);
2059 outBuffers[2] = createSecBuffer(
nullptr, 0, SECBUFFER_EMPTY);
2060 auto freeBuffers = qScopeGuard([&outBuffers]() {
2061 for (
auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
2062 if (outBuffers[i].pvBuffer)
2063 FreeContextBuffer(outBuffers[i].pvBuffer);
2066 SecBufferDesc outputBufferDesc{
2068 ARRAYSIZE(outBuffers),
2072 ULONG contextReq = getContextRequirements();
2075 status = InitializeSecurityContext(&credentialHandle,
2077 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()),
2089 status = AcceptSecurityContext(
2101 if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
2102 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer,
false)) {
2108#ifdef QSSLSOCKET_DEBUG
2109 qCDebug(lcTlsBackendSchannel)
2110 <<
"Failed to initialize shutdown:" << schannelErrorToString(status);
2119 auto *plainSocket = d->plainTcpSocket();
2120 Q_ASSERT(plainSocket);
2122 if (SecIsValidHandle(&contextHandle)) {
2125 if (plainSocket->state() != QAbstractSocket::UnconnectedState && q->isEncrypted()) {
2131 plainSocket->disconnectFromHost();
2137 auto *plainSocket = d->plainTcpSocket();
2138 Q_ASSERT(plainSocket);
2139 d->setEncrypted(
false);
2144 qint64 tempMax = d->maxReadBufferSize();
2145 d->setMaxReadBufferSize(0);
2147 d->setMaxReadBufferSize(tempMax);
2152 deallocateContext();
2153 freeCredentialsHandle();
2161 if (!q->isEncrypted())
2164 const auto sessionProtocol = toQtSslProtocol(connectionInfo.dwProtocol);
2166 const auto ciphers = ciphersByName(QStringView(cipherInfo.szCipherSuite));
2167 for (
const auto& cipher : ciphers) {
2168 if (cipher.protocol() == sessionProtocol)
2177 if (!q->isEncrypted())
2178 return QSsl::SslProtocol::UnknownProtocol;
2179 return toQtSslProtocol(connectionInfo.dwProtocol);
2186 auto *plainSocket = d->plainTcpSocket();
2187 Q_ASSERT(plainSocket);
2189 const bool isServer = d->tlsMode() == QSslSocket::SslServerMode;
2190 switch (schannelState) {
2191 case SchannelState::InitializeHandshake:
2192 if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
2196 if (!SecIsValidHandle(&credentialHandle))
2198 if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
2202 if (schannelState != SchannelState::PerformHandshake)
2205 case SchannelState::PerformHandshake:
2206 if (!performHandshake()) {
2210 if (schannelState != SchannelState::VerifyHandshake)
2213 case SchannelState::VerifyHandshake:
2216 if (!verifyHandshake()) {
2222 if (schannelState != SchannelState::Done)
2225 case SchannelState::Done:
2227 if (!q->isEncrypted()) {
2228 d->setEncrypted(
true);
2229 emit q->encrypted();
2231 renegotiating =
false;
2232 if (d->isPendingClose()) {
2233 d->setPendingClose(
false);
2239 case SchannelState::Renegotiate:
2240 if (!renegotiate()) {
2243 }
else if (intermediateBuffer.size() || plainSocket->bytesAvailable()) {
2256
2257
2260 if (sslErrors.isEmpty())
2265 const auto &configuration = q->sslConfiguration();
2266 auto *plainSocket = d->plainTcpSocket();
2268 emit q->sslErrors(sslErrors);
2270 const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
2271 || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
2272 && d->tlsMode() == QSslSocket::SslClientMode);
2273 const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
2275 if (doVerifyPeer && doEmitSslError) {
2276 if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
2277 QSslSocketPrivate::pauseSocketNotifiers(q);
2280 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
2281 sslErrors.constFirst().errorString());
2282 plainSocket->disconnectFromHost();
2291 const QSslKey &privateKey,
2292 QStringView certName)
2294 QAsn1Element elem = _q_PKCS12_key(privateKey);
2296 QDataStream stream(&buffer, QDataStream::WriteOnly);
2298 NCRYPT_PROV_HANDLE provider = 0;
2299 SECURITY_STATUS status = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0);
2300 if (status != SEC_E_OK) {
2301 qCWarning(lcTlsBackendSchannel())
2302 <<
"Failed to open ncrypt storage provider:" << schannelErrorToString(status);
2305 const auto freeProvider = qScopeGuard([provider]() { NCryptFreeObject(provider); });
2307 QSpan<
const QChar> nameSpan(certName);
2308 NCryptBuffer nbuffer{ ULONG(nameSpan.size_bytes() +
sizeof(
char16_t)),
2309 NCRYPTBUFFER_PKCS_KEY_NAME,
2310 const_reinterpret_cast<
void *>(nameSpan.data()) };
2311 NCryptBufferDesc bufferDesc{ NCRYPTBUFFER_VERSION, 1, &nbuffer };
2312 auto *bufferDescPtr = nameSpan.isEmpty() ?
nullptr : &bufferDesc;
2313 NCRYPT_KEY_HANDLE ncryptKey = 0;
2314 status = NCryptImportKey(provider, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, bufferDescPtr, &ncryptKey,
2315 PBYTE(buffer.data()), buffer.size(), 0);
2316 if (status != SEC_E_OK) {
2317 qCWarning(lcTlsBackendSchannel())
2318 <<
"Failed to import private key:" << schannelErrorToString(status);
2321 const auto freeKey = qScopeGuard([ncryptKey]() { NCryptFreeObject(ncryptKey); });
2325 CRYPT_DATA_BLOB keyBlob = {
sizeof(ncryptKey), PBYTE(&ncryptKey) };
2327 CertSetCertificateContextProperty(context, CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, &keyBlob);
2329 auto error = GetLastError();
2330 if (lcTlsBackendSchannel().isWarningEnabled())
2331 qErrnoWarning(
int(error),
"Failed to set ncrypt handle property.");
2335 CRYPT_KEY_PROV_INFO provInfo{
2336 const_reinterpret_cast<LPWSTR>(certName.constData()),
2337 const_cast<LPWSTR>(MS_KEY_STORAGE_PROVIDER),
2339 CERT_SET_KEY_PROV_HANDLE_PROP_ID | CERT_SET_KEY_CONTEXT_PROP_ID,
2344 ok = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2345 CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, &provInfo);
2347 auto error = GetLastError();
2348 if (lcTlsBackendSchannel().isWarningEnabled())
2349 qErrnoWarning(
int(error),
"Failed to set key provider info property.");
2359 const auto &configuration = q->sslConfiguration();
2361 auto createStoreFromCertificateChain = [](
const QList<QSslCertificate> certChain,
const QSslKey &privateKey) {
2362 const wchar_t *passphrase = L"";
2364 QByteArray pkcs12 = _q_makePkcs12(certChain,
2366 QString::fromWCharArray(passphrase, 0));
2367 CRYPT_DATA_BLOB pfxBlob;
2368 pfxBlob.cbData = DWORD(pkcs12.length());
2369 pfxBlob.pbData =
reinterpret_cast<
unsigned char *>(pkcs12.data());
2372 constexpr DWORD flags = PKCS12_ALWAYS_CNG_KSP | PKCS12_NO_PERSIST_KEY;
2373 return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, flags));
2376 if (!configuration.localCertificateChain().isEmpty()) {
2377 if (configuration.privateKey().isNull()) {
2378 setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
2379 QSslSocket::tr(
"Cannot provide a certificate with no key"));
2382 if (localCertificateStore ==
nullptr) {
2383 localCertificateStore =
2384 createStoreFromCertificateChain(configuration.localCertificateChain(), {});
2385 if (localCertificateStore) {
2386 const CERT_CONTEXT *certificateContext = CertFindCertificateInStore(
2387 localCertificateStore.get(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
2388 CERT_FIND_ANY,
nullptr,
nullptr);
2389 if (certificateContext) {
2391 localCertificateCtxt.reset(certificateContext);
2393 BOOL mustFree = FALSE;
2394 NCRYPT_KEY_HANDLE testKey = 0;
2395 BOOL ok = CryptAcquireCertificatePrivateKey(
2396 certificateContext, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG,
nullptr,
2397 &testKey, &keySpec, &mustFree);
2399 NCryptFreeObject(testKey);
2401 const auto cn = configuration.localCertificate()
2402 .subjectInfo(QSslCertificate::CommonName);
2403 attachPrivateKeyToCertificate(certificateContext,
2404 configuration.privateKey(),
2405 cn.isEmpty() ? QStringView{} : cn.front());
2409 qCWarning(lcTlsBackendSchannel,
"Failed to load certificate chain!");
2414 if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
2415 caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
2422 Q_ASSERT(certContext);
2426 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
2430 auto tempCertCollection =
QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
2433 CERT_STORE_CREATE_NEW_FLAG,
2435 if (!tempCertCollection) {
2436#ifdef QSSLSOCKET_DEBUG
2437 qCWarning(lcTlsBackendSchannel,
"Failed to create certificate store collection!");
2442 if (rootCertOnDemandLoadingAllowed()) {
2448 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
2449 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
2452#ifdef QSSLSOCKET_DEBUG
2453 qCWarning(lcTlsBackendSchannel,
"Failed to open the system root CA certificate store!");
2456 }
else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
2457#ifdef QSSLSOCKET_DEBUG
2458 qCWarning(lcTlsBackendSchannel,
2459 "Failed to add the system root CA certificate store to the certificate store "
2465 if (caCertificateStore) {
2466 if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
2467#ifdef QSSLSOCKET_DEBUG
2468 qCWarning(lcTlsBackendSchannel,
2469 "Failed to add the user's CA certificate store to the certificate store "
2476 if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
2477#ifdef QSSLSOCKET_DEBUG
2478 qCWarning(lcTlsBackendSchannel,
2479 "Failed to add certificate's origin store to the certificate store collection!");
2484 CERT_CHAIN_PARA parameters;
2485 ZeroMemory(¶meters,
sizeof(parameters));
2486 parameters.cbSize =
sizeof(CERT_CHAIN_PARA);
2487 parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
2488 parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
2489 LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
2490 : szOID_PKIX_KP_CLIENT_AUTH);
2491 parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
2493 QTlsBackend::clearPeerCertificates(d);
2494 const CERT_CHAIN_CONTEXT *chainContext =
nullptr;
2495 auto freeCertChain = qScopeGuard([&chainContext]() {
2497 CertFreeCertificateChain(chainContext);
2499 BOOL status = CertGetCertificateChain(
nullptr,
2502 tempCertCollection.get(),
2504 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
2508 if (status == FALSE || !chainContext || chainContext->cChain == 0) {
2509 QSslError error(QSslError::UnableToVerifyFirstCertificate);
2511 emit q->peerVerifyError(error);
2512 return q->state() == QAbstractSocket::ConnectedState;
2516 static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
2518 return QSslCertificate();
2520 const CERT_CONTEXT *certContext = element->pCertContext;
2521 return QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(certContext);
2527 CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
2529 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
2530 auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate,
2531 getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
2533 emit q->peerVerifyError(error);
2534 if (q->state() != QAbstractSocket::ConnectedState)
2537 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2541 auto error = QSslError(QSslError::PathLengthExceeded);
2543 emit q->peerVerifyError(error);
2544 if (q->state() != QAbstractSocket::ConnectedState)
2547 static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
2548 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2549 | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
2550 | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
2551 if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
2552 auto error = QSslError(QSslError::SslError::UnspecifiedError);
2554 emit q->peerVerifyError(error);
2555 if (q->state() != QAbstractSocket::ConnectedState)
2559 DWORD verifyDepth = chain->cElement;
2560 if (q->peerVerifyDepth() > 0 && DWORD(q->peerVerifyDepth()) < verifyDepth)
2561 verifyDepth = DWORD(q->peerVerifyDepth());
2563 const auto &caCertificates = q->sslConfiguration().caCertificates();
2565 if (!rootCertOnDemandLoadingAllowed()
2566 && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
2567 && (q->peerVerifyMode() == QSslSocket::VerifyPeer
2568 || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
2574 CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
2575 QSslCertificate certificate = getCertificateFromChainElement(element);
2576 if (!caCertificates.contains(certificate)) {
2577 auto error = QSslError(QSslError::CertificateUntrusted, certificate);
2579 emit q->peerVerifyError(error);
2580 if (q->state() != QAbstractSocket::ConnectedState)
2585 QList<QSslCertificate> peerCertificateChain;
2586 for (DWORD i = 0; i < verifyDepth; i++) {
2587 CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
2588 QSslCertificate certificate = getCertificateFromChainElement(element);
2589 if (certificate.isNull()) {
2590 const auto &previousCert = !peerCertificateChain.isEmpty() ? peerCertificateChain.last()
2591 : QSslCertificate();
2592 auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate, previousCert);
2594 emit q->peerVerifyError(error);
2595 if (previousCert.isNull() || q->state() != QAbstractSocket::ConnectedState)
2598 const QList<QSslCertificateExtension> extensions = certificate.extensions();
2600#ifdef QSSLSOCKET_DEBUG
2601 qCDebug(lcTlsBackendSchannel) <<
"issuer:" << certificate.issuerDisplayName()
2602 <<
"\nsubject:" << certificate.subjectDisplayName()
2603 <<
"\nQSslCertificate info:" << certificate
2604 <<
"\nextended error info:" << element->pwszExtendedErrorInfo
2605 <<
"\nerror status:" << element->TrustStatus.dwErrorStatus;
2608 peerCertificateChain.append(certificate);
2609 QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
2611 if (certificate.isBlacklisted()) {
2612 const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
2614 emit q->peerVerifyError(error);
2615 if (q->state() != QAbstractSocket::ConnectedState)
2619 LONG result = CertVerifyTimeValidity(
nullptr , element->pCertContext->pCertInfo);
2621 auto error = QSslError(result == -1 ? QSslError::CertificateNotYetValid
2622 : QSslError::CertificateExpired,
2625 emit q->peerVerifyError(error);
2626 if (q->state() != QAbstractSocket::ConnectedState)
2631 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
2633 Q_ASSERT(!sslErrors.isEmpty());
2635 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
2636 auto error = QSslError(QSslError::CertificateRevoked, certificate);
2638 emit q->peerVerifyError(error);
2639 if (q->state() != QAbstractSocket::ConnectedState)
2642 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
2643 auto error = QSslError(QSslError::CertificateSignatureFailed, certificate);
2645 emit q->peerVerifyError(error);
2646 if (q->state() != QAbstractSocket::ConnectedState)
2653 if (netscapeWrongCertType(extensions, isClient, i == 0))
2654 element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
2656 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
2657 auto error = QSslError(QSslError::InvalidPurpose, certificate);
2659 emit q->peerVerifyError(error);
2660 if (q->state() != QAbstractSocket::ConnectedState)
2663 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
2665 const bool isTrustedRoot = caCertificates.contains(certificate);
2666 if (!isTrustedRoot) {
2667 auto error = QSslError(QSslError::CertificateUntrusted, certificate);
2669 emit q->peerVerifyError(error);
2670 if (q->state() != QAbstractSocket::ConnectedState)
2674 static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
2675 | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
2676 if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
2681 static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
2682 | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2683 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
2684 | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
2685 | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
2686 | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
2687 | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
2688 | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
2689 if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
2690 auto error = QSslError(QSslError::UnspecifiedError, certificate);
2692 emit q->peerVerifyError(error);
2693 if (q->state() != QAbstractSocket::ConnectedState)
2696 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2697 auto it = std::find_if(extensions.cbegin(), extensions.cend(),
2698 [](
const QSslCertificateExtension &extension) {
2699 return extension.name() ==
"basicConstraints"_L1;
2701 if (it != extensions.cend()) {
2705 QVariantMap basicConstraints = it->value().toMap();
2707 if (i > 0 && !basicConstraints.value(
"ca"_L1,
false).toBool())
2708 error = QSslError(QSslError::InvalidPurpose, certificate);
2710 error = QSslError(QSslError::PathLengthExceeded, certificate);
2712 emit q->peerVerifyError(error);
2713 if (q->state() != QAbstractSocket::ConnectedState)
2717 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
2718 auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
2720 emit q->peerVerifyError(error);
2721 if (q->state() != QAbstractSocket::ConnectedState)
2725 if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
2730 const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
2731 || certificate.version() ==
"1";
2734 if (!isRootCertificateAuthority) {
2735 auto error = QSslError(QSslError::SelfSignedCertificate, certificate);
2737 emit q->peerVerifyError(error);
2738 if (q->state() != QAbstractSocket::ConnectedState)
2744 if (!peerCertificateChain.isEmpty())
2745 QTlsBackend::storePeerCertificate(d, peerCertificateChain.constFirst());
2747 const auto &configuration = q->sslConfiguration();
2749 const bool doVerifyPeer = q->peerVerifyMode() == QSslSocket::VerifyPeer
2750 || (q->peerVerifyMode() == QSslSocket::AutoVerifyPeer
2751 && d->tlsMode() == QSslSocket::SslClientMode);
2755 if (!configuration.peerCertificate().isNull()) {
2758 if (d->tlsMode() == QSslSocket::SslClientMode) {
2759 const auto verificationPeerName = d->verificationName();
2760 const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
2761 if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
2763 const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
2765 emit q->peerVerifyError(error);
2766 if (q->state() != QAbstractSocket::ConnectedState)
2770 }
else if (doVerifyPeer) {
2773 const QSslError error(QSslError::NoPeerCertificate);
2775 emit q->peerVerifyError(error);
2776 if (q->state() != QAbstractSocket::ConnectedState)
2786 return d->isRootsOnDemandAllowed() && QSslSocketPrivate::rootCertOnDemandLoadingSupported();
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
Q_DISABLE_COPY_MOVE(X509CertificateSchannel)
Combined button and popup list for selecting options.
Namespace containing onternal types that TLS backends implement.
QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED std::array< SchannelCipherInfo, 44 > schannelCipherInfo
QList< QSslCipher > defaultCiphers()
UNICODE_STRING cbcChainingMode
static void attachPrivateKeyToCertificate(PCCERT_CONTEXT context, const QSslKey &privateKey, QStringView certName)
QList< CRYPTO_SETTINGS > cryptoSettingsForCiphers(const QList< QSslCipher > &ciphers)
bool containsTls13Cipher(const QList< QSslCipher > &ciphers)
UNICODE_STRING gcmChainingMode
QList< QSslCipher > ciphersByName(QStringView schannelSuiteName)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
#define SP_PROT_TLS1_0_SERVER
#define SP_PROT_TLS1_1_SERVER
#define SP_PROT_TLS1_2_SERVER
#define BCRYPT_ECDSA_ALGORITHM
#define SP_PROT_TLS1_3_SERVER
#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 SP_PROT_TLS1_1_CLIENT
#define SP_PROT_TLS1_SERVER
QAsn1Element _q_PKCS12_key(const QSslKey &key)
#define BCRYPT_ECDH_ALGORITHM
#define SP_PROT_TLS1_3_CLIENT
#define SEC_E_APPLICATION_PROTOCOL_MISMATCH
#define SP_PROT_TLS1_CLIENT
#define SP_PROT_TLS1_0_CLIENT
#define SP_PROT_TLS1_2_CLIENT
std::unique_ptr< void, QHCertStoreDeleter > QHCertStorePointer
const char * authenticationMethod
const char * schannelCipherSuite
QList< QSsl::SslProtocol > protocols
const char * encryptionMethod
const char * openSslCipherSuite
const char * keyExchangeMethod