Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtls_schannel.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:cryptography
4
5// #define QSSLSOCKET_DEBUG
6
11#include "../shared/qasn1element_p.h"
12
13#include <QtNetwork/private/qsslcertificate_p.h>
14#include <QtNetwork/private/qsslcipher_p.h>
15#include <QtNetwork/private/qssl_p.h>
16
17#include <QtNetwork/qsslcertificate.h>
18#include <QtNetwork/qsslcertificateextension.h>
19#include <QtNetwork/qsslsocket.h>
20
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>
26
27#define SECURITY_WIN32
28#include <security.h>
29#include <schnlsp.h>
30
31#if NTDDI_VERSION >= NTDDI_WINBLUE && defined(SECBUFFER_APPLICATION_PROTOCOLS)
32// ALPN = Application Layer Protocol Negotiation
33#define SUPPORTS_ALPN 1
34#endif
35
36// Not defined in MinGW
37#ifndef SECBUFFER_ALERT
38#define SECBUFFER_ALERT 17
39#endif
40#ifndef SECPKG_ATTR_APPLICATION_PROTOCOL
41#define SECPKG_ATTR_APPLICATION_PROTOCOL 35
42#endif
43
44// Another missing MinGW define
45#ifndef SEC_E_APPLICATION_PROTOCOL_MISMATCH
46#define SEC_E_APPLICATION_PROTOCOL_MISMATCH _HRESULT_TYPEDEF_(0x80090367L)
47#endif
48
49// Also not defined in MinGW.......
50#ifndef SP_PROT_TLS1_SERVER
51#define SP_PROT_TLS1_SERVER 0x00000040
52#endif
53#ifndef SP_PROT_TLS1_CLIENT
54#define SP_PROT_TLS1_CLIENT 0x00000080
55#endif
56#ifndef SP_PROT_TLS1_0_SERVER
57#define SP_PROT_TLS1_0_SERVER SP_PROT_TLS1_SERVER
58#endif
59#ifndef SP_PROT_TLS1_0_CLIENT
60#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
61#endif
62#ifndef SP_PROT_TLS1_0
64#endif
65#ifndef SP_PROT_TLS1_1_SERVER
66#define SP_PROT_TLS1_1_SERVER 0x00000100
67#endif
68#ifndef SP_PROT_TLS1_1_CLIENT
69#define SP_PROT_TLS1_1_CLIENT 0x00000200
70#endif
71#ifndef SP_PROT_TLS1_1
73#endif
74#ifndef SP_PROT_TLS1_2_SERVER
75#define SP_PROT_TLS1_2_SERVER 0x00000400
76#endif
77#ifndef SP_PROT_TLS1_2_CLIENT
78#define SP_PROT_TLS1_2_CLIENT 0x00000800
79#endif
80#ifndef SP_PROT_TLS1_2
82#endif
83#ifndef SP_PROT_TLS1_3_SERVER
84#define SP_PROT_TLS1_3_SERVER 0x00001000
85#endif
86#ifndef SP_PROT_TLS1_3_CLIENT
87#define SP_PROT_TLS1_3_CLIENT 0x00002000
88#endif
89#ifndef SP_PROT_TLS1_3
91#endif
92#ifndef BCRYPT_ECDH_ALGORITHM
93#define BCRYPT_ECDH_ALGORITHM L"ECDH"
94#endif
95#ifndef BCRYPT_ECDSA_ALGORITHM
96#define BCRYPT_ECDSA_ALGORITHM L"ECDSA"
97#endif
98
99/*
100 @future!:
101
102 - Transmitting intermediate certificates
103 - Look for a way to avoid putting intermediate certificates in the certificate store
104 - No documentation on how to send the chain
105 - A stackoverflow question on this from 3 years ago implies schannel only sends intermediate
106 certificates if it's "in the system or user certificate store".
107 - https://stackoverflow.com/q/30156584/2493610
108 - This can be done by users, but we shouldn't add any and all local intermediate
109 certs to the stores automatically.
110 - PSK support
111 - Was added in Windows 10 (it seems), documentation at time of writing is sparse/non-existent.
112 - Specifically about how to supply credentials when they're requested.
113 - Or how to recognize that they're requested in the first place.
114 - Skip certificate verification.
115 - Check if "PSK-only" is still required to do PSK _at all_ (all-around bad solution).
116 - Check if SEC_I_INCOMPLETE_CREDENTIALS is still returned for both "missing certificate" and
117 "missing PSK" when calling InitializeSecurityContext in "performHandshake".
118
119 Low priority:
120 - Possibly make RAII wrappers for SecBuffer (which I commonly create QScopeGuards for)
121
122*/
123
125
126using namespace Qt::StringLiterals;
127
128Q_LOGGING_CATEGORY(lcTlsBackendSchannel, "qt.tlsbackend.schannel");
129
130// Defined in qsslsocket_qt.cpp.
131extern QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
132 const QString &passPhrase);
133extern QAsn1Element _q_PKCS12_key(const QSslKey &key);
134
135namespace {
136bool supportsTls13();
137}
138
139namespace QTlsPrivate {
140
142
153
154// The list of supported ciphers according to
155// https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022
156QT_WARNING_PUSH
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}},
184
185 // the following cipher suites are not enabled by default in schannel provider
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}},
199
200 // PSK cipher suites
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}},
207}};
208QT_WARNING_POP
209
210const SchannelCipherInfo *cipherInfoByOpenSslName(const QString &name)
211{
212 for (const auto &cipherInfo : schannelCipherInfo) {
214 return &cipherInfo;
215 }
216
217 return nullptr;
218}
219
225
231
232/**
233 Determines which algorithms are not used by the requested ciphers to build
234 up a black list that can be passed to SCH_CREDENTIALS.
235 */
236QList<CRYPTO_SETTINGS> cryptoSettingsForCiphers(const QList<QSslCipher> &ciphers)
237{
238 static const QList<QSslCipher> defaultCipherList = defaultCiphers();
239
240 if (defaultCipherList == ciphers) {
241 // the ciphers have not been restricted for this session, so no black listing needed
242 return {};
243 }
244
245 QList<const SchannelCipherInfo*> cipherInfo;
246
247 for (const auto &cipher : ciphers) {
248 if (cipher.isNull())
249 continue;
250
251 const auto *info = cipherInfoByOpenSslName(cipher.name());
252 if (!cipherInfo.contains(info))
253 cipherInfo.append(info);
254 }
255
256 QList<CRYPTO_SETTINGS> cryptoSettings;
257
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);
262 };
263
264 // black list of key exchange algorithms
265 const auto allKeyExchangeAlgorithms = {BCRYPT_RSA_ALGORITHM,
267 BCRYPT_DH_ALGORITHM};
268
269 for (const auto &algorithm : allKeyExchangeAlgorithms) {
270 const auto method = QStringView(algorithm);
271
272 const auto usesMethod = [method](const SchannelCipherInfo *info) {
273 return QLatin1StringView(info->keyExchangeMethod) == method;
274 };
275
276 const bool exclude = std::none_of(cipherInfo.cbegin(), cipherInfo.cend(), usesMethod);
277
278 if (exclude) {
279 CRYPTO_SETTINGS settings = {};
280 settings.eAlgorithmUsage = TlsParametersCngAlgUsageKeyExchange;
281 assignUnicodeString(settings.strCngAlgId, algorithm);
282 cryptoSettings.append(settings);
283 }
284 }
285
286 // black list of authentication algorithms
287 const auto allAuthenticationAlgorithms = {BCRYPT_RSA_ALGORITHM,
288 BCRYPT_DSA_ALGORITHM,
290 BCRYPT_DH_ALGORITHM};
291
292 for (const auto &algorithm : allAuthenticationAlgorithms) {
293 const auto method = QStringView(algorithm);
294
295 const auto usesMethod = [method](const SchannelCipherInfo *info) {
296 return QLatin1StringView(info->authenticationMethod) == method;
297 };
298
299 const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
300
301 if (exclude) {
302 CRYPTO_SETTINGS settings = {};
303 settings.eAlgorithmUsage = TlsParametersCngAlgUsageSignature;
304 assignUnicodeString(settings.strCngAlgId, algorithm);
305 cryptoSettings.append(settings);
306 }
307 }
308
309
310 // black list of encryption algorithms
311 const auto allEncryptionAlgorithms = {BCRYPT_AES_ALGORITHM,
312 BCRYPT_RC4_ALGORITHM,
313 BCRYPT_DES_ALGORITHM,
314 BCRYPT_3DES_ALGORITHM};
315
316 for (const auto &algorithm : allEncryptionAlgorithms) {
317 const auto method = QStringView(algorithm);
318
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);
328 usesGcm = usesGcm ||
329 QLatin1StringView(info->schannelCipherSuite).contains("_GCM_"_L1);
330 usesCbc = usesCbc ||
331 QLatin1StringView(info->schannelCipherSuite).contains("_CBC_"_L1);
332 }
333 }
334
335 CRYPTO_SETTINGS settings = {};
336 settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
337 assignUnicodeString(settings.strCngAlgId, algorithm);
338
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;
345 }
346
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);
355 }
356 } else {
357 const auto usesMethod = [method](const SchannelCipherInfo *info) {
358 return QLatin1StringView(info->encryptionMethod) == method;
359 };
360
361 const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
362
363 if (exclude) {
364 CRYPTO_SETTINGS settings = {};
365 settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
366 assignUnicodeString(settings.strCngAlgId, algorithm);
367 cryptoSettings.append(settings);
368 }
369 }
370 }
371
372 // black list of hash algorithms
373 const auto allHashAlgorithms = {BCRYPT_MD5_ALGORITHM,
374 BCRYPT_SHA1_ALGORITHM,
375 BCRYPT_SHA256_ALGORITHM,
376 BCRYPT_SHA384_ALGORITHM};
377
378 for (const auto &algorithm : allHashAlgorithms) {
379 const auto method = QStringView(algorithm);
380
381 const auto usesMethod = [method](const SchannelCipherInfo *info) {
382 return QLatin1StringView(info->hashMethod) == method;
383 };
384
385 const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
386
387 if (exclude) {
388 CRYPTO_SETTINGS settings = {};
389 settings.eAlgorithmUsage = TlsParametersCngAlgUsageDigest;
390 assignUnicodeString(settings.strCngAlgId, algorithm);
391 cryptoSettings.append(settings);
392 }
393 }
394
395 return cryptoSettings;
396}
397
398QList<QSslCipher> ciphersByName(QStringView schannelSuiteName)
399{
400 QList<QSslCipher> ciphers;
401
402 for (const auto &cipher : schannelCipherInfo) {
403 if (QLatin1StringView(cipher.schannelCipherSuite) == schannelSuiteName) {
404 for (const auto &protocol : cipher.protocols) {
405QT_WARNING_PUSH
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") :
412 QString());
413QT_WARNING_POP
414
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));
421 }
422 }
423 }
424
425 return ciphers;
426}
427
429{
430 ULONG contextFunctionsCount = {};
431 PCRYPT_CONTEXT_FUNCTIONS contextFunctions = {};
432
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");
437 return {};
438 }
439
440 const bool supportsV13 = supportsTls13();
441
442 QList<QSslCipher> ciphers;
443
444 for (ULONG index = 0; index < contextFunctions->cFunctions; ++index) {
445 const auto suiteName = QStringView(contextFunctions->rgpszFunctions[index]);
446
447 const QList<QSslCipher> allCiphers = ciphersByName(suiteName);
448
449 for (const auto &cipher : allCiphers) {
450 if (!supportsV13 && (cipher.protocol() == QSsl::TlsV1_3))
451 continue;
452
453 ciphers.append(cipher);
454 }
455 }
456
457 BCryptFreeBuffer(contextFunctions);
458
459 return ciphers;
460}
461
462bool containsTls13Cipher(const QList<QSslCipher> &ciphers)
463{
464 return std::any_of(ciphers.cbegin(), ciphers.cend(),
465 [](const QSslCipher &cipher) { return cipher.protocol() == QSsl::TlsV1_3; });
466}
467
468} // namespace QTlsPrivate
469
470bool QSchannelBackend::s_loadedCiphersAndCerts = false;
472
473long QSchannelBackend::tlsLibraryVersionNumber() const
474{
475 const auto os = QOperatingSystemVersion::current();
476 return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
477}
478
479QString QSchannelBackend::tlsLibraryVersionString() const
480{
481 const auto os = QOperatingSystemVersion::current();
482 return "Secure Channel, %1 %2.%3.%4"_L1
483 .arg(os.name(),
484 QString::number(os.majorVersion()),
485 QString::number(os.minorVersion()),
486 QString::number(os.microVersion()));
487}
488
489long QSchannelBackend::tlsLibraryBuildVersionNumber() const
490{
491 return NTDDI_VERSION;
492}
493
494QString QSchannelBackend::tlsLibraryBuildVersionString() const
495{
496 return "Secure Channel (NTDDI: 0x%1)"_L1
497 .arg(QString::number(NTDDI_VERSION, 16).toUpper());
498}
499
500void QSchannelBackend::ensureInitialized() const
501{
502 ensureInitializedImplementation();
503}
504
505void QSchannelBackend::ensureInitializedImplementation()
506{
507 const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
508 if (s_loadedCiphersAndCerts)
509 return;
510 s_loadedCiphersAndCerts = true;
511
512 setDefaultCaCertificates(systemCaCertificatesImplementation());
513 // setDefaultCaCertificates sets it to false, re-enable it:
514 QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
515
516 resetDefaultCiphers();
517}
518
519void QSchannelBackend::resetDefaultCiphers()
520{
521 setDefaultSupportedCiphers(QTlsPrivate::defaultCiphers());
522 setDefaultCiphers(QTlsPrivate::defaultCiphers());
523}
524
525QString QSchannelBackend::backendName() const
526{
527 return builtinBackendNames[nameIndexSchannel];
528}
529
530QList<QSsl::SslProtocol> QSchannelBackend::supportedProtocols() const
531{
532 QList<QSsl::SslProtocol> protocols;
533
534 protocols << QSsl::AnyProtocol;
535 protocols << QSsl::SecureProtocols;
536QT_WARNING_PUSH
537QT_WARNING_DISABLE_DEPRECATED
538 protocols << QSsl::TlsV1_0;
539 protocols << QSsl::TlsV1_0OrLater;
540 protocols << QSsl::TlsV1_1;
541 protocols << QSsl::TlsV1_1OrLater;
542QT_WARNING_POP
543 protocols << QSsl::TlsV1_2;
544 protocols << QSsl::TlsV1_2OrLater;
545
546 if (supportsTls13()) {
547 protocols << QSsl::TlsV1_3;
548 protocols << QSsl::TlsV1_3OrLater;
549 }
550
551 return protocols;
552}
553
554QList<QSsl::SupportedFeature> QSchannelBackend::supportedFeatures() const
555{
556 QList<QSsl::SupportedFeature> features;
557
558#ifdef SUPPORTS_ALPN
559 features << QSsl::SupportedFeature::ClientSideAlpn;
560 features << QSsl::SupportedFeature::ServerSideAlpn;
561#endif
562
563 return features;
564}
565
566QList<QSsl::ImplementedClass> QSchannelBackend::implementedClasses() const
567{
568 QList<QSsl::ImplementedClass> classes;
569
570 classes << QSsl::ImplementedClass::Socket;
571 classes << QSsl::ImplementedClass::Certificate;
572 classes << QSsl::ImplementedClass::Key;
573
574 return classes;
575}
576
577QTlsPrivate::TlsKey *QSchannelBackend::createKey() const
578{
579 return new QTlsPrivate::TlsKeySchannel;
580}
581
582QTlsPrivate::X509Certificate *QSchannelBackend::createCertificate() const
583{
585}
586
587QList<QSslCertificate> QSchannelBackend::systemCaCertificates() const
588{
589 return systemCaCertificatesImplementation();
590}
591
592QTlsPrivate::TlsCryptograph *QSchannelBackend::createTlsCryptograph() const
593{
595}
596
597QList<QSslCertificate> QSchannelBackend::systemCaCertificatesImplementation()
598{
599 // Similar to non-Darwin version found in qtlsbackend_openssl.cpp,
600 // QTlsPrivate::systemCaCertificates function.
601 QList<QSslCertificate> systemCerts;
602
603 auto hSystemStore = QHCertStorePointer(
604 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
605 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
606
607 if (hSystemStore) {
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));
612 }
613 }
614 return systemCerts;
615}
616
617QTlsPrivate::X509PemReaderPtr QSchannelBackend::X509PemReader() const
618{
619 return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
620}
621
622QTlsPrivate::X509DerReaderPtr QSchannelBackend::X509DerReader() const
623{
624 return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
625}
626
627QTlsPrivate::X509Pkcs12ReaderPtr QSchannelBackend::X509Pkcs12Reader() const
628{
629 return QTlsPrivate::X509CertificateSchannel::importPkcs12;
630}
631
632namespace {
633
634SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
635{
636 return SecBuffer{ length, bufferType, ptr };
637}
638
639SecBuffer createSecBuffer(QByteArray &buffer, unsigned long bufferType)
640{
641 return createSecBuffer(buffer.data(), static_cast<unsigned long>(buffer.length()), bufferType);
642}
643
644QString schannelErrorToString(qint32 status)
645{
646 switch (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:
656 // According to the link below we get this error when Schannel receives TLS1_ALERT_ACCESS_DENIED
657 // https://docs.microsoft.com/en-us/windows/desktop/secauthn/schannel-error-codes-for-tls-and-ssl-alerts
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:
668 // SNI error
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:
681 // This can mean "invalid argument" in some cases...
682 return QSslSocket::tr("The credentials were not recognized / Invalid argument");
683 case SEC_E_MESSAGE_ALTERED:
684 // According to the Internet it also triggers for messages that are out of order.
685 // https://microsoft.public.platformsdk.security.narkive.com/4JAvlMvD/help-please-schannel-security-contexts-and-decryptmessage
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");
691 default:
692 return QSslSocket::tr("Unknown error occurred: %1").arg(status);
693 }
694}
695
696bool supportsTls13()
697{
698 static bool supported = []() {
699 const auto current = QOperatingSystemVersion::current();
700 // 20221 just happens to be the preview version I run on my laptop where I tested TLS 1.3.
701 const auto minimum =
702 QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221);
703 return current >= minimum;
704 }();
705
706 return supported;
707}
708
709DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
710{
711 DWORD protocols = SP_PROT_NONE;
712 switch (protocol) {
713 case QSsl::UnknownProtocol:
714 return DWORD(-1);
715QT_WARNING_PUSH
716QT_WARNING_DISABLE_DEPRECATED
717 case QSsl::DtlsV1_0:
718 case QSsl::DtlsV1_0OrLater:
719QT_WARNING_POP
720 case QSsl::DtlsV1_2:
721 case QSsl::DtlsV1_2OrLater:
722 return DWORD(-1); // Not supported at the moment (@future)
723 case QSsl::AnyProtocol:
725 if (supportsTls13())
726 protocols |= SP_PROT_TLS1_3;
727 break;
728QT_WARNING_PUSH
729QT_WARNING_DISABLE_DEPRECATED
730 case QSsl::TlsV1_0:
731 protocols = SP_PROT_TLS1_0;
732 break;
733 case QSsl::TlsV1_1:
734 protocols = SP_PROT_TLS1_1;
735 break;
736QT_WARNING_POP
737 case QSsl::TlsV1_2:
738 protocols = SP_PROT_TLS1_2;
739 break;
740 case QSsl::TlsV1_3:
741 if (supportsTls13())
742 protocols = SP_PROT_TLS1_3;
743 else
744 protocols = DWORD(-1);
745 break;
746QT_WARNING_PUSH
747QT_WARNING_DISABLE_DEPRECATED
748 case QSsl::TlsV1_0OrLater:
749 // For the "OrLater" protocols we fall through from one to the next, adding all of them
750 // in ascending order
751 protocols = SP_PROT_TLS1_0;
752 Q_FALLTHROUGH();
753 case QSsl::TlsV1_1OrLater:
754 protocols |= SP_PROT_TLS1_1;
755 Q_FALLTHROUGH();
756QT_WARNING_POP
757 case QSsl::SecureProtocols: // TLS v1.2 and later is currently considered secure
758 case QSsl::TlsV1_2OrLater:
759 protocols |= SP_PROT_TLS1_2;
760 Q_FALLTHROUGH();
761 case QSsl::TlsV1_3OrLater:
762 if (supportsTls13())
763 protocols |= SP_PROT_TLS1_3;
764 else if (protocol == QSsl::TlsV1_3OrLater)
765 protocols = DWORD(-1); // if TlsV1_3OrLater was specifically chosen we should fail
766 break;
767 }
768 return protocols;
769}
770
771// In the new API that descended down upon us we are not asked which protocols we want
772// but rather which protocols we don't want. So now we have this function to disable
773// anything that is not enabled.
774DWORD negatedSchannelProtocols(DWORD wantedProtocols)
775{
776 DWORD protocols = SP_PROT_ALL; // all protocols
777 protocols &= ~wantedProtocols; // minus the one(s) we want
778 return protocols;
779}
780
781/*!
782 \internal
783 Used when converting the established session's \a protocol back to
784 Qt's own SslProtocol type.
785
786 Only one protocol should be passed in at a time.
787*/
788QSsl::SslProtocol toQtSslProtocol(DWORD protocol)
789{
790#define MAP_PROTOCOL(sp_protocol, q_protocol)
791 if (protocol & sp_protocol) {
792 Q_ASSERT(!(protocol & ~sp_protocol));
793 return q_protocol;
794 }
795
796QT_WARNING_PUSH
797QT_WARNING_DISABLE_DEPRECATED
798 MAP_PROTOCOL(SP_PROT_TLS1_0, QSsl::TlsV1_0)
799 MAP_PROTOCOL(SP_PROT_TLS1_1, QSsl::TlsV1_1)
800QT_WARNING_POP
801 MAP_PROTOCOL(SP_PROT_TLS1_2, QSsl::TlsV1_2)
802 MAP_PROTOCOL(SP_PROT_TLS1_3, QSsl::TlsV1_3)
803#undef MAP_PROTOCOL
804 Q_UNREACHABLE();
805 return QSsl::UnknownProtocol;
806}
807
808/*!
809 \internal
810 Used by verifyCertContext to check if a client cert is used by a server or vice versa.
811*/
812bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bool isClient, bool isLeaf)
813{
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";
818 });
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)
825 return true;
826 const int expectedPeerCertType = [&]() {
827 if (isLeaf) {
828 return isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
829 : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
830 }
831 return NETSCAPE_SSL_CA_CERT_TYPE;
832 }();
833 if ((netscapeCertType & expectedPeerCertType) == 0)
834 return true;
835 }
836 return false;
837}
838
839/*!
840 \internal
841 Used by verifyCertContext to check the basicConstraints certificate
842 extension to see if the certificate is a certificate authority.
843 Returns false if the certificate does not have the basicConstraints
844 extension or if it is not a certificate authority.
845*/
846bool isCertificateAuthority(const QList<QSslCertificateExtension> &extensions)
847{
848 auto it = std::find_if(extensions.cbegin(), extensions.cend(),
849 [](const QSslCertificateExtension &extension) {
850 return extension.name() == "basicConstraints"_L1;
851 });
852 if (it != extensions.cend()) {
853 QVariantMap basicConstraints = it->value().toMap();
854 return basicConstraints.value("ca"_L1, false).toBool();
855 }
856 return false;
857}
858
859/*!
860 \internal
861 Returns true if the attributes we requested from the context/handshake have
862 been given.
863*/
864bool matchesContextRequirements(DWORD attributes, DWORD requirements,
865 QSslSocket::PeerVerifyMode verifyMode,
866 bool isClient)
867{
868#ifdef QSSLSOCKET_DEBUG
869#define DEBUG_WARN(message) qCWarning(lcTlsBackendSchannel, message)
870#else
871#define DEBUG_WARN(message)
872#endif
873
874#define CHECK_ATTRIBUTE(attributeName)
875 do {
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 "\"");
880 return false;
881 }
882 } while (false)
883
884 CHECK_ATTRIBUTE(CONFIDENTIALITY);
885 CHECK_ATTRIBUTE(REPLAY_DETECT);
886 CHECK_ATTRIBUTE(SEQUENCE_DETECT);
887 CHECK_ATTRIBUTE(STREAM);
888 if (verifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
889 CHECK_ATTRIBUTE(MUTUAL_AUTH);
890
891 // This one is manual because there is no server / ASC_ version
892 if (isClient) {
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\"");
897 return false;
898 }
899 }
900
901 return true;
902#undef CHECK_ATTRIBUTE
903#undef DEBUG_WARN
904}
905
906template<typename Required, typename Actual>
907Required const_reinterpret_cast(Actual *p)
908{
909 return Required(p);
910}
911
912#ifdef SUPPORTS_ALPN
913QByteArray createAlpnString(const QByteArrayList &nextAllowedProtocols)
914{
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.";
923 continue;
924 } else if (proto.isEmpty()) {
925 continue;
926 }
927 protocolString += char(proto.length()) + proto;
928 }
929 return protocolString;
930 }();
931 if (names.isEmpty())
932 return alpnString;
933
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))
940 + names;
941 }
942 return alpnString;
943}
944#endif // SUPPORTS_ALPN
945
946qint64 readToBuffer(QByteArray &buffer, QTcpSocket *plainSocket)
947{
948 Q_ASSERT(plainSocket);
949 static const qint64 shrinkCutoff = 1024 * 12;
950 static const qint64 defaultRead = 1024 * 16;
951 qint64 bytesRead = 0;
952
953 const auto toRead = std::min(defaultRead, plainSocket->bytesAvailable());
954 if (toRead > 0) {
955 const auto bufferSize = buffer.size();
956 buffer.reserve(bufferSize + toRead); // avoid growth strategy kicking in
957 buffer.resize(bufferSize + toRead);
958 bytesRead = plainSocket->read(buffer.data() + bufferSize, toRead);
959 buffer.resize(bufferSize + bytesRead);
960 // In case of excessive memory usage we shrink:
961 if (buffer.size() < shrinkCutoff && buffer.capacity() > defaultRead)
962 buffer.shrink_to_fit();
963 }
964
965 return bytesRead;
966}
967
968void retainExtraData(QByteArray &buffer, const SecBuffer &secBuffer)
969{
970 Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
971 if (int(secBuffer.cbBuffer) >= buffer.size())
972 return;
973
974#ifdef QSSLSOCKET_DEBUG
975 qCDebug(lcTlsBackendSchannel, "We got SECBUFFER_EXTRA, will retain %lu bytes",
976 secBuffer.cbBuffer);
977#endif
978 std::move(buffer.end() - secBuffer.cbBuffer, buffer.end(), buffer.begin());
979 buffer.resize(secBuffer.cbBuffer);
980}
981
982qint64 checkIncompleteData(const SecBuffer &secBuffer)
983{
984 if (secBuffer.BufferType == SECBUFFER_MISSING) {
985#ifdef QSSLSOCKET_DEBUG
986 qCDebug(lcTlsBackendSchannel, "Need %lu more bytes.", secBuffer.cbBuffer);
987#endif
988 return secBuffer.cbBuffer;
989}
990 return 0;
991}
992
993DWORD defaultCredsFlag()
994{
995 return qEnvironmentVariableIsSet("QT_SCH_DEFAULT_CREDS") ? 0 : SCH_CRED_NO_DEFAULT_CREDS;
996}
997} // anonymous namespace
998
999
1000namespace QTlsPrivate {
1001
1002TlsCryptographSchannel::TlsCryptographSchannel()
1003{
1004 SecInvalidateHandle(&credentialHandle);
1005 SecInvalidateHandle(&contextHandle);
1006 QSchannelBackend::ensureInitializedImplementation();
1007}
1008
1010{
1011 closeCertificateStores();
1012 deallocateContext();
1013 freeCredentialsHandle();
1014}
1015
1016void TlsCryptographSchannel::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
1017{
1018 Q_ASSERT(qObj);
1019 Q_ASSERT(dObj);
1020
1021 q = qObj;
1022 d = dObj;
1023
1024 reset();
1025}
1026
1027bool TlsCryptographSchannel::sendToken(void *token, unsigned long tokenLength, bool emitError)
1028{
1029 if (tokenLength == 0)
1030 return true;
1031
1032 Q_ASSERT(d);
1033 auto *plainSocket = d->plainTcpSocket();
1034 Q_ASSERT(plainSocket);
1035 if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
1036 || !plainSocket->isOpen()) {
1037 return false;
1038 }
1039
1040 const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
1041 if (written != qint64(tokenLength)) {
1042 // Failed to write/buffer everything or an error occurred
1043 if (emitError)
1044 setErrorAndEmit(d, plainSocket->error(), plainSocket->errorString());
1045 return false;
1046 }
1047 return true;
1048}
1049
1050QString TlsCryptographSchannel::targetName() const
1051{
1052 // Used for SNI extension
1053 Q_ASSERT(q);
1054 Q_ASSERT(d);
1055
1056 const auto verificationPeerName = d->verificationName();
1057 return verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
1058}
1059
1060ULONG TlsCryptographSchannel::getContextRequirements()
1061{
1062 Q_ASSERT(d);
1063 Q_ASSERT(q);
1064
1065 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
1066 ULONG req = 0;
1067
1068 req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
1069 req |= ISC_REQ_CONFIDENTIALITY; // Encrypt messages
1070 req |= ISC_REQ_REPLAY_DETECT; // Detect replayed messages
1071 req |= ISC_REQ_SEQUENCE_DETECT; // Detect out of sequence messages
1072 req |= ISC_REQ_STREAM; // Support a stream-oriented connection
1073
1074 if (isClient) {
1075 req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
1076 } else {
1077 switch (q->peerVerifyMode()) {
1078 case QSslSocket::PeerVerifyMode::VerifyNone:
1079 // There doesn't seem to be a way to ask for an optional client cert :-(
1080 case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
1081 case QSslSocket::PeerVerifyMode::QueryPeer:
1082 break;
1083 case QSslSocket::PeerVerifyMode::VerifyPeer:
1084 req |= ISC_REQ_MUTUAL_AUTH;
1085 break;
1086 }
1087 }
1088
1089 return req;
1090}
1091
1092bool TlsCryptographSchannel::acquireCredentialsHandle()
1093{
1094 Q_ASSERT(d);
1095 Q_ASSERT(q);
1096 const auto &configuration = q->sslConfiguration();
1097
1098 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1099
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"));
1105 return false;
1106 }
1107
1108 DWORD certsCount = 0;
1109 // Set up our certificate stores before trying to use one...
1110 initializeCertificateStores();
1111
1112 // Check if user has specified a certificate chain but it could not be loaded.
1113 // This happens if there was something wrong with the certificate chain or there was no private
1114 // key.
1115 if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
1116 return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
1117
1118 PCCERT_CONTEXT localCertificate = nullptr;
1119 if (localCertificateStore != nullptr) {
1120 certsCount = 1;
1121 localCertificate = static_cast<PCCERT_CONTEXT>(configuration.localCertificate().handle());
1122 Q_ASSERT(localCertificate);
1123 }
1124
1125 const QList<QSslCipher> ciphers = configuration.ciphers();
1126 if (!ciphers.isEmpty() && !containsTls13Cipher(ciphers))
1127 protocols &= ~SP_PROT_TLS1_3;
1128
1129 QList<CRYPTO_SETTINGS> cryptoSettings;
1130 if (!ciphers.isEmpty())
1131 cryptoSettings = cryptoSettingsForCiphers(ciphers);
1132
1133 TLS_PARAMETERS tlsParameters = {
1134 0,
1135 nullptr,
1136 negatedSchannelProtocols(protocols), // what protocols to disable
1137 static_cast<DWORD>(cryptoSettings.size()),
1138 (cryptoSettings.isEmpty() ? nullptr : cryptoSettings.data()),
1139 0
1140 };
1141
1142 SCH_CREDENTIALS credentials = {
1143 SCH_CREDENTIALS_VERSION,
1144 0,
1145 certsCount,
1146 &localCertificate,
1147 nullptr,
1148 0,
1149 nullptr,
1150 0,
1151 SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(),
1152 1,
1153 &tlsParameters
1154 };
1155
1156 TimeStamp expiration{};
1157 auto status = AcquireCredentialsHandle(nullptr, // pszPrincipal (unused)
1158 const_cast<wchar_t *>(UNISP_NAME), // pszPackage
1159 isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND, // fCredentialUse
1160 nullptr, // pvLogonID (unused)
1161 &credentials, // pAuthData
1162 nullptr, // pGetKeyFn (unused)
1163 nullptr, // pvGetKeyArgument (unused)
1164 &credentialHandle, // phCredential
1165 &expiration // ptsExpir
1166 );
1167
1168#ifdef QT_WIN_SERVER_2016_COMPAT
1169 if (status == SEC_E_UNKNOWN_CREDENTIALS) {
1170 if (!ciphers.isEmpty()) {
1171 qCWarning(lcTlsBackendSchannel,
1172 "Cipher suite restrictions are not supported by the "
1173 "Windows Server 2016 compatibility fallback");
1174 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
1175 return false;
1176 }
1177
1178 SCHANNEL_CRED credentialsV4 = { SCHANNEL_CRED_VERSION,
1179 certsCount,
1180 &localCertificate,
1181 nullptr,
1182 0,
1183 nullptr,
1184 0,
1185 nullptr,
1186 protocols,
1187 0,
1188 0,
1189 0,
1190 SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
1191 | defaultCredsFlag(),
1192 0 };
1193
1194 status = AcquireCredentialsHandle(nullptr, // pszPrincipal (unused)
1195 const_cast<wchar_t *>(UNISP_NAME), // pszPackage
1196 isClient ? SECPKG_CRED_OUTBOUND
1197 : SECPKG_CRED_INBOUND, // fCredentialUse
1198 nullptr, // pvLogonID (unused)
1199 &credentialsV4, // pAuthData
1200 nullptr, // pGetKeyFn (unused)
1201 nullptr, // pvGetKeyArgument (unused)
1202 &credentialHandle, // phCredential
1203 &expiration // ptsExpir
1204 );
1205 }
1206#endif
1207
1208 if (status != SEC_E_OK) {
1209 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
1210 return false;
1211 }
1212 return true;
1213}
1214
1215void TlsCryptographSchannel::deallocateContext()
1216{
1217 if (SecIsValidHandle(&contextHandle)) {
1218 DeleteSecurityContext(&contextHandle);
1219 SecInvalidateHandle(&contextHandle);
1220 }
1221}
1222
1223void TlsCryptographSchannel::freeCredentialsHandle()
1224{
1225 if (SecIsValidHandle(&credentialHandle)) {
1226 FreeCredentialsHandle(&credentialHandle);
1227 SecInvalidateHandle(&credentialHandle);
1228 }
1229}
1230
1231void TlsCryptographSchannel::closeCertificateStores()
1232{
1233 localCertificateStore.reset();
1234 peerCertificateStore.reset();
1235 caCertificateStore.reset();
1236}
1237
1238bool TlsCryptographSchannel::createContext()
1239{
1240 Q_ASSERT(q);
1241 Q_ASSERT(d);
1242
1243 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1244 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1245 Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode);
1246 ULONG contextReq = getContextRequirements();
1247
1248 SecBuffer outBuffers[3];
1249 outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
1250 outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
1251 outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1252 auto freeBuffers = qScopeGuard([&outBuffers]() {
1253 for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1254 if (outBuffers[i].pvBuffer)
1255 FreeContextBuffer(outBuffers[i].pvBuffer);
1256 }
1257 });
1258 SecBufferDesc outputBufferDesc{
1259 SECBUFFER_VERSION,
1260 ARRAYSIZE(outBuffers),
1261 outBuffers
1262 };
1263
1264 TimeStamp expiry;
1265
1266 SecBufferDesc alpnBufferDesc;
1267 bool useAlpn = false;
1268#ifdef SUPPORTS_ALPN
1269 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
1270 QByteArray alpnString = createAlpnString(q->sslConfiguration().allowedNextProtocols());
1271 useAlpn = !alpnString.isEmpty();
1272 SecBuffer alpnBuffers[1];
1273 alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1274 alpnBufferDesc = {
1275 SECBUFFER_VERSION,
1276 ARRAYSIZE(alpnBuffers),
1277 alpnBuffers
1278 };
1279#endif
1280
1281 const QString encodedTargetName = QUrl::fromUserInput(targetName()).host(QUrl::EncodeUnicode);
1282 auto status = InitializeSecurityContext(&credentialHandle, // phCredential
1283 nullptr, // phContext
1284 const_reinterpret_cast<SEC_WCHAR *>(encodedTargetName.utf16()), // pszTargetName
1285 contextReq, // fContextReq
1286 0, // Reserved1
1287 0, // TargetDataRep (unused)
1288 useAlpn ? &alpnBufferDesc : nullptr, // pInput
1289 0, // Reserved2
1290 &contextHandle, // phNewContext
1291 &outputBufferDesc, // pOutput
1292 &contextAttributes, // pfContextAttr
1293 &expiry // ptsExpiry
1294 );
1295
1296 // This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
1297 // should be the only non-error return-code here.
1298 if (status != SEC_I_CONTINUE_NEEDED) {
1299 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1300 QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
1301 return false;
1302 }
1303
1304 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1305 return false;
1306 schannelState = SchannelState::PerformHandshake;
1307 return true;
1308}
1309
1310bool TlsCryptographSchannel::acceptContext()
1311{
1312 Q_ASSERT(d);
1313 Q_ASSERT(q);
1314
1315 auto *plainSocket = d->plainTcpSocket();
1316 Q_ASSERT(plainSocket);
1317
1318 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1319 Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
1320 Q_ASSERT(d->tlsMode() == QSslSocket::SslServerMode);
1321 ULONG contextReq = getContextRequirements();
1322
1323 if (missingData > plainSocket->bytesAvailable())
1324 return true;
1325
1326 missingData = 0;
1327 readToBuffer(intermediateBuffer, plainSocket);
1328 if (intermediateBuffer.isEmpty())
1329 return true; // definitely need more data..
1330
1331 SecBuffer inBuffers[2];
1332 inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1333
1334#ifdef SUPPORTS_ALPN
1335 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
1336 // The string must be alive when we call AcceptSecurityContext
1337 QByteArray alpnString = createAlpnString(q->sslConfiguration().allowedNextProtocols());
1338 if (!alpnString.isEmpty()) {
1339 inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
1340 } else
1341#endif
1342 {
1343 inBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1344 }
1345
1346 SecBufferDesc inputBufferDesc{
1347 SECBUFFER_VERSION,
1348 ARRAYSIZE(inBuffers),
1349 inBuffers
1350 };
1351
1352 SecBuffer outBuffers[3];
1353 outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
1354 outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
1355 outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1356 auto freeBuffers = qScopeGuard([&outBuffers]() {
1357 for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1358 if (outBuffers[i].pvBuffer)
1359 FreeContextBuffer(outBuffers[i].pvBuffer);
1360 }
1361 });
1362 SecBufferDesc outputBufferDesc{
1363 SECBUFFER_VERSION,
1364 ARRAYSIZE(outBuffers),
1365 outBuffers
1366 };
1367
1368 TimeStamp expiry;
1369 auto status = AcceptSecurityContext(
1370 &credentialHandle, // phCredential
1371 nullptr, // phContext
1372 &inputBufferDesc, // pInput
1373 contextReq, // fContextReq
1374 0, // TargetDataRep (unused)
1375 &contextHandle, // phNewContext
1376 &outputBufferDesc, // pOutput
1377 &contextAttributes, // pfContextAttr
1378 &expiry // ptsTimeStamp
1379 );
1380
1381 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1382 // Need more data
1383 missingData = checkIncompleteData(outBuffers[0]);
1384 return true;
1385 }
1386
1387 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
1388 // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
1389 // inBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need to
1390 // be stored.
1391 retainExtraData(intermediateBuffer, inBuffers[1]);
1392 } else { /* No 'extra' data, message not incomplete */
1393 intermediateBuffer.resize(0);
1394 }
1395
1396 if (status != SEC_I_CONTINUE_NEEDED) {
1397 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1398 QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
1399 return false;
1400 }
1401 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1402 return false;
1403 schannelState = SchannelState::PerformHandshake;
1404 return true;
1405}
1406
1407bool TlsCryptographSchannel::performHandshake()
1408{
1409 Q_ASSERT(d);
1410 auto *plainSocket = d->plainTcpSocket();
1411 Q_ASSERT(plainSocket);
1412
1413 if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
1414 || !plainSocket->isOpen()) {
1415 setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
1416 QSslSocket::tr("The TLS/SSL connection has been closed"));
1417 return false;
1418 }
1419 Q_ASSERT(SecIsValidHandle(&credentialHandle));
1420 Q_ASSERT(SecIsValidHandle(&contextHandle));
1421 Q_ASSERT(schannelState == SchannelState::PerformHandshake);
1422
1423#ifdef QSSLSOCKET_DEBUG
1424 qCDebug(lcTlsBackendSchannel, "Bytes available from socket: %lld",
1425 plainSocket->bytesAvailable());
1426 qCDebug(lcTlsBackendSchannel, "intermediateBuffer size: %d", intermediateBuffer.size());
1427#endif
1428
1429 if (missingData > plainSocket->bytesAvailable())
1430 return true;
1431
1432 missingData = 0;
1433 readToBuffer(intermediateBuffer, plainSocket);
1434 if (intermediateBuffer.isEmpty())
1435 return true; // no data, will fail
1436
1437 SecBuffer outBuffers[3] = {};
1438 const auto freeOutBuffers = [&outBuffers]() {
1439 for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1440 if (outBuffers[i].pvBuffer)
1441 FreeContextBuffer(outBuffers[i].pvBuffer);
1442 }
1443 };
1444 const auto outBuffersGuard = qScopeGuard(freeOutBuffers);
1445 // For this call to InitializeSecurityContext we may need to call it twice.
1446 // In some cases us not having a certificate isn't actually an error, but just a request.
1447 // With Schannel, to ignore this warning, we need to call InitializeSecurityContext again
1448 // when we get SEC_I_INCOMPLETE_CREDENTIALS! As far as I can tell it's not documented anywhere.
1449 // https://stackoverflow.com/a/47479968/2493610
1450 SECURITY_STATUS status;
1451 short attempts = 2;
1452 do {
1453 SecBuffer inputBuffers[2];
1454 inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
1455 inputBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1456 SecBufferDesc inputBufferDesc{
1457 SECBUFFER_VERSION,
1458 ARRAYSIZE(inputBuffers),
1459 inputBuffers
1460 };
1461
1462 freeOutBuffers(); // free buffers from any previous attempt
1463 outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
1464 outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
1465 outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1466 SecBufferDesc outputBufferDesc{
1467 SECBUFFER_VERSION,
1468 ARRAYSIZE(outBuffers),
1469 outBuffers
1470 };
1471
1472 ULONG contextReq = getContextRequirements();
1473 TimeStamp expiry;
1474 status = InitializeSecurityContext(
1475 &credentialHandle, // phCredential
1476 &contextHandle, // phContext
1477 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
1478 contextReq, // fContextReq
1479 0, // Reserved1
1480 0, // TargetDataRep (unused)
1481 &inputBufferDesc, // pInput
1482 0, // Reserved2
1483 nullptr, // phNewContext (we already have one)
1484 &outputBufferDesc, // pOutput
1485 &contextAttributes, // pfContextAttr
1486 &expiry // ptsExpiry
1487 );
1488
1489 if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
1490 // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
1491 // inputBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need
1492 // to be stored.
1493 retainExtraData(intermediateBuffer, inputBuffers[1]);
1494 } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
1495 // Clear the buffer if we weren't asked for more data
1496 intermediateBuffer.resize(0);
1497 }
1498
1499 --attempts;
1500 } while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
1501
1502 switch (status) {
1503 case SEC_E_OK:
1504 // Need to transmit a final token in the handshake if 'cbBuffer' is non-zero.
1505 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1506 return false;
1507 schannelState = SchannelState::VerifyHandshake;
1508 return true;
1509 case SEC_I_CONTINUE_NEEDED:
1510 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1511 return false;
1512 // Must call InitializeSecurityContext again later (done through continueHandshake)
1513 return true;
1514 case SEC_I_INCOMPLETE_CREDENTIALS:
1515 // Schannel takes care of picking certificate to send (other than the one we can specify),
1516 // so if we get here then that means we don't have a certificate the server accepts.
1517 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1518 QSslSocket::tr("Server did not accept any certificate we could present."));
1519 return false;
1520 case SEC_I_CONTEXT_EXPIRED:
1521 // "The message sender has finished using the connection and has initiated a shutdown."
1522 if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
1523 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1524 return false;
1525 }
1526 if (!shutdown) { // we did not initiate this
1527 setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
1528 QSslSocket::tr("The TLS/SSL connection has been closed"));
1529 }
1530 return true;
1531 case SEC_E_INCOMPLETE_MESSAGE:
1532 // Simply incomplete, wait for more data
1533 missingData = checkIncompleteData(outBuffers[0]);
1534 return true;
1535 case SEC_E_ALGORITHM_MISMATCH:
1536 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1537 QSslSocket::tr("Algorithm mismatch"));
1538 shutdown = true; // skip sending the "Shutdown" alert
1539 return false;
1540 }
1541
1542 // Note: We can get here if the connection is using TLS 1.2 and the server certificate uses
1543 // MD5, which is not allowed in Schannel. This causes an "invalid token" error during handshake.
1544 // (If you came here investigating an error: md5 is insecure, update your certificate)
1545 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1546 QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
1547 return false;
1548}
1549
1550bool TlsCryptographSchannel::verifyHandshake()
1551{
1552 Q_ASSERT(d);
1553 Q_ASSERT(q);
1554 const auto &configuration = q->sslConfiguration();
1555
1556 sslErrors.clear();
1557
1558 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
1559#define CHECK_STATUS(status)
1560 if (status != SEC_E_OK) {
1561 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1562 QSslSocket::tr("Failed to query the TLS context: %1")
1563 .arg(schannelErrorToString(status)));
1564 return false;
1565 }
1566
1567 // Everything is set up, now make sure there's nothing wrong and query some attributes...
1568 if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
1569 configuration.peerVerifyMode(), isClient)) {
1570 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1571 QSslSocket::tr("Did not get the required attributes for the connection."));
1572 return false;
1573 }
1574
1575 // Get stream sizes (to know the max size of a message and the size of the header and trailer)
1576 auto status = QueryContextAttributes(&contextHandle,
1577 SECPKG_ATTR_STREAM_SIZES,
1578 &streamSizes);
1579 CHECK_STATUS(status);
1580
1581 // Get session cipher info
1582 status = QueryContextAttributes(&contextHandle,
1583 SECPKG_ATTR_CIPHER_INFO,
1584 &cipherInfo);
1585 CHECK_STATUS(status);
1586
1587 status = QueryContextAttributes(&contextHandle,
1588 SECPKG_ATTR_CONNECTION_INFO,
1589 &connectionInfo);
1590 CHECK_STATUS(status);
1591
1592#ifdef SUPPORTS_ALPN
1593 const auto allowedProtos = configuration.allowedNextProtocols();
1594 if (!allowedProtos.isEmpty()) {
1595 SecPkgContext_ApplicationProtocol alpn;
1596 status = QueryContextAttributes(&contextHandle,
1597 SECPKG_ATTR_APPLICATION_PROTOCOL,
1598 &alpn);
1599 CHECK_STATUS(status);
1600 if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
1601 QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
1602 alpn.ProtocolIdSize);
1603 if (!allowedProtos.contains(negotiatedProto)) {
1604 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1605 QSslSocket::tr("Unwanted protocol was negotiated"));
1606 return false;
1607 }
1608 QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
1609 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
1610 } else {
1611 QTlsBackend::setNegotiatedProtocol(d, {});
1612 QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationUnsupported);
1613 }
1614 }
1615#endif // supports ALPN
1616
1617#undef CHECK_STATUS
1618
1619 // Verify certificate
1620 CERT_CONTEXT *certificateContext = nullptr;
1621 auto freeCertificate = qScopeGuard([&certificateContext]() {
1622 if (certificateContext)
1623 CertFreeCertificateContext(certificateContext);
1624 });
1625 status = QueryContextAttributes(&contextHandle,
1626 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1627 &certificateContext);
1628
1629 // QueryPeer can (currently) not work in Schannel since Schannel itself doesn't have a way to
1630 // ask for a certificate and then still be OK if it's not received.
1631 // To work around this we don't request a certificate at all for QueryPeer.
1632 // For servers AutoVerifyPeer is supposed to be treated the same as QueryPeer.
1633 // This means that servers using Schannel will only request client certificate for "VerifyPeer".
1634 if ((!isClient && configuration.peerVerifyMode() == QSslSocket::PeerVerifyMode::VerifyPeer)
1635 || (isClient && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::VerifyNone
1636 && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::QueryPeer)) {
1637 if (status != SEC_E_OK) {
1638#ifdef QSSLSOCKET_DEBUG
1639 qCDebug(lcTlsBackendSchannel) << "Couldn't retrieve peer certificate, status:"
1640 << schannelErrorToString(status);
1641#endif
1642 const QSslError error{ QSslError::NoPeerCertificate };
1643 sslErrors += error;
1644 emit q->peerVerifyError(error);
1645 if (q->state() != QAbstractSocket::ConnectedState)
1646 return false;
1647 }
1648 }
1649
1650 // verifyCertContext returns false if the user disconnected while it was checking errors.
1651 if (certificateContext && !verifyCertContext(certificateContext))
1652 return false;
1653
1654 if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState) {
1655#ifdef QSSLSOCKET_DEBUG
1656 qCDebug(lcTlsBackendSchannel) << __func__ << "was unsuccessful. Paused:" << d->isPaused();
1657#endif
1658 // If we're paused then checkSslErrors returned false, but it's not an error
1659 return d->isPaused() && q->state() == QAbstractSocket::ConnectedState;
1660 }
1661
1662 schannelState = SchannelState::Done;
1663 return true;
1664}
1665
1666bool TlsCryptographSchannel::renegotiate()
1667{
1668 Q_ASSERT(d);
1669
1670 SecBuffer outBuffers[3];
1671 outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
1672 outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
1673 outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1674 auto freeBuffers = qScopeGuard([&outBuffers]() {
1675 for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1676 if (outBuffers[i].pvBuffer)
1677 FreeContextBuffer(outBuffers[i].pvBuffer);
1678 }
1679 });
1680 SecBufferDesc outputBufferDesc{
1681 SECBUFFER_VERSION,
1682 ARRAYSIZE(outBuffers),
1683 outBuffers
1684 };
1685
1686 ULONG contextReq = getContextRequirements();
1687 TimeStamp expiry;
1688 SECURITY_STATUS status;
1689 if (d->tlsMode() == QSslSocket::SslClientMode) {
1690 status = InitializeSecurityContext(&credentialHandle, // phCredential
1691 &contextHandle, // phContext
1692 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
1693 contextReq, // fContextReq
1694 0, // Reserved1
1695 0, // TargetDataRep (unused)
1696 nullptr, // pInput (nullptr for renegotiate)
1697 0, // Reserved2
1698 nullptr, // phNewContext (we already have one)
1699 &outputBufferDesc, // pOutput
1700 &contextAttributes, // pfContextAttr
1701 &expiry // ptsExpiry
1702 );
1703 } else {
1704 status = AcceptSecurityContext(
1705 &credentialHandle, // phCredential
1706 &contextHandle, // phContext
1707 nullptr, // pInput
1708 contextReq, // fContextReq
1709 0, // TargetDataRep (unused)
1710 nullptr, // phNewContext
1711 &outputBufferDesc, // pOutput
1712 &contextAttributes, // pfContextAttr,
1713 &expiry // ptsTimeStamp
1714 );
1715 }
1716 if (status == SEC_I_CONTINUE_NEEDED) {
1717 schannelState = SchannelState::PerformHandshake;
1718 return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
1719 } else if (status == SEC_E_OK) {
1720 schannelState = SchannelState::PerformHandshake;
1721 return true;
1722 }
1723 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
1724 QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
1725 return false;
1726}
1727
1728/*!
1729 \internal
1730 reset the state in preparation for reuse of socket
1731*/
1732void TlsCryptographSchannel::reset()
1733{
1734 Q_ASSERT(d);
1735
1736 closeCertificateStores(); // certificate stores could've changed
1737 deallocateContext();
1738 freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
1739
1740 cipherInfo = {};
1741 connectionInfo = {};
1742 streamSizes = {};
1743
1744 contextAttributes = 0;
1745 intermediateBuffer.clear();
1746 schannelState = SchannelState::InitializeHandshake;
1747
1748
1749 d->setEncrypted(false);
1750 shutdown = false;
1751 renegotiating = false;
1752
1753 missingData = 0;
1754}
1755
1757{
1758 Q_ASSERT(q);
1759
1760 if (q->isEncrypted())
1761 return; // let's not mess up the connection...
1762 reset();
1764}
1765
1767{
1768 Q_ASSERT(q);
1769
1770 if (q->isEncrypted())
1771 return; // let's not mess up the connection...
1772 reset();
1774}
1775
1776auto TlsCryptographSchannel::getNextEncryptedMessage() -> MessageBufferResult
1777{
1778 MessageBufferResult result;
1779 QByteArray &fullMessage = result.messageBuffer;
1780
1781 Q_ASSERT(d);
1782 auto &writeBuffer = d->tlsWriteBuffer();
1783
1784 auto allocateMessage = [&fullMessage](qsizetype size) -> QSpan<char> {
1785 auto targetSize = fullMessage.size() + size;
1786 if (fullMessage.capacity() < targetSize) {
1787 qsizetype newSize = fullMessage.capacity() * 2;
1788 if (newSize < targetSize)
1789 newSize = targetSize;
1790 fullMessage.reserve(newSize);
1791 }
1792 fullMessage.resizeForOverwrite(targetSize);
1793 return QSpan(fullMessage).subspan(fullMessage.size() - size);
1794 };
1795
1796 const int headerSize = int(streamSizes.cbHeader);
1797 const int trailerSize = int(streamSizes.cbTrailer);
1798 constexpr qsizetype MessageBufferThreshold = 128 * 1024;
1799
1800 qint64 writeBufferSize = 0;
1801 while ((writeBufferSize = writeBuffer.size()) > 0
1802 && fullMessage.size() < MessageBufferThreshold) {
1803 // Try to read 'cbMaximumMessage' bytes from buffer before encrypting.
1804 const int bodySize = int(std::min(writeBufferSize, qint64(streamSizes.cbMaximumMessage)));
1805 const qsizetype messageSize = headerSize + bodySize + trailerSize;
1806 QSpan buffer = allocateMessage(messageSize);
1807 char *header = buffer.data();
1808 char *body = header + headerSize;
1809 char *trailer = body + bodySize;
1810 {
1811 // Use peek() here instead of read() so we don't lose data if encryption fails.
1812 qint64 copied = writeBuffer.peek(body, bodySize);
1813 Q_ASSERT(copied == bodySize);
1814 }
1815
1816 SecBuffer inputBuffers[] = {
1817 createSecBuffer(header, headerSize, SECBUFFER_STREAM_HEADER),
1818 createSecBuffer(body, bodySize, SECBUFFER_DATA),
1819 createSecBuffer(trailer, trailerSize, SECBUFFER_STREAM_TRAILER),
1820 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
1821 };
1822 SecBufferDesc message = {
1823 SECBUFFER_VERSION,
1824 ARRAYSIZE(inputBuffers),
1825 inputBuffers
1826 };
1827
1828 if (auto status = EncryptMessage(&contextHandle, 0, &message, 0); status != SEC_E_OK) {
1829 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1830 QSslSocket::tr("Schannel failed to encrypt data: %1")
1831 .arg(schannelErrorToString(status)));
1832 result.messageBuffer.chop(messageSize);
1833 return result;
1834 }
1835 // Data was encrypted successfully, so we free() what we peek()ed earlier
1836 writeBuffer.free(bodySize);
1837
1838 // The trailer's size is not final, so resize fullMessage to not send trailing junk
1839 auto finalSize = qsizetype(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer
1840 + inputBuffers[2].cbBuffer);
1841 fullMessage.chop(messageSize - finalSize);
1842 }
1843 result.ok = true;
1844 return result;
1845}
1846
1848{
1849 Q_ASSERT(q);
1850 Q_ASSERT(d);
1851 auto *plainSocket = d->plainTcpSocket();
1852 Q_ASSERT(plainSocket);
1853
1854 if (d->tlsMode() == QSslSocket::UnencryptedMode)
1855 return; // This function should not have been called
1856
1857 // Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
1858 if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
1859 || !plainSocket->isOpen()) {
1860 return;
1861 }
1862
1863 if (schannelState != SchannelState::Done) {
1865 return;
1866 }
1867
1868 auto &buffer = d->tlsBuffer();
1869 if (q->isEncrypted()) { // encrypt data in writeBuffer and write it to plainSocket
1870 qint64 totalBytesWritten = 0;
1871 while (d->tlsWriteBuffer().size() > 0) {
1872 MessageBufferResult r = getNextEncryptedMessage();
1873 if (r.messageBuffer.isEmpty() && !r.ok)
1874 return;
1875 QByteArray fullMessage = std::move(r.messageBuffer);
1876 const qint64 bytesWritten = plainSocket->write(fullMessage);
1877 if (!r.ok && bytesWritten < 0)
1878 break; // We might have to emit bytesWritten, so break instead of return
1879#ifdef QSSLSOCKET_DEBUG
1880 qCDebug(lcTlsBackendSchannel, "Wrote %lld of total %d bytes", bytesWritten,
1881 fullMessage.size());
1882#endif
1883 if (bytesWritten >= 0) {
1884 totalBytesWritten += bytesWritten;
1885 } else {
1886 setErrorAndEmit(d, plainSocket->error(), plainSocket->errorString());
1887 return;
1888 }
1889 }
1890
1891 if (totalBytesWritten > 0) {
1892 // Don't emit bytesWritten() recursively.
1893 bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
1894 if (!emittedBytesWritten) {
1895 emittedBytesWritten = true;
1896 emit q->bytesWritten(totalBytesWritten);
1897 emittedBytesWritten = false;
1898 }
1899 emit q->channelBytesWritten(0, totalBytesWritten);
1900 }
1901 }
1902
1903 int totalRead = 0;
1904 bool hadIncompleteData = false;
1905 const auto readBufferMaxSize = d->maxReadBufferSize();
1906 while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
1907 if (missingData > plainSocket->bytesAvailable()
1908 && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
1909#ifdef QSSLSOCKET_DEBUG
1910 qCDebug(lcTlsBackendSchannel, "We're still missing %lld bytes, will check later.",
1911 missingData);
1912#endif
1913 break;
1914 }
1915
1916 missingData = 0;
1917 const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
1918#ifdef QSSLSOCKET_DEBUG
1919 qCDebug(lcTlsBackendSchannel, "Read %lld encrypted bytes from the socket", bytesRead);
1920#endif
1921 if (intermediateBuffer.length() == 0 || (hadIncompleteData && bytesRead == 0)) {
1922#ifdef QSSLSOCKET_DEBUG
1923 qCDebug(lcTlsBackendSchannel,
1924 hadIncompleteData ? "No new data received, leaving loop!"
1925 : "Nothing to decrypt, leaving loop!");
1926#endif
1927 break;
1928 }
1929 hadIncompleteData = false;
1930#ifdef QSSLSOCKET_DEBUG
1931 qCDebug(lcTlsBackendSchannel, "Total amount of bytes to decrypt: %d",
1932 intermediateBuffer.length());
1933#endif
1934
1935 SecBuffer dataBuffer[4]{
1936 createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
1937 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
1938 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
1939 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
1940 };
1941 SecBufferDesc message{
1942 SECBUFFER_VERSION,
1943 ARRAYSIZE(dataBuffer),
1944 dataBuffer
1945 };
1946 auto status = DecryptMessage(&contextHandle, &message, 0, nullptr);
1947 if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
1948 // There can still be 0 output even if it succeeds, this is fine
1949 if (dataBuffer[1].cbBuffer > 0) {
1950 // It is always decrypted in-place.
1951 // But [0] is the STREAM_HEADER, [1] is the DATA and [2] is the STREAM_TRAILER.
1952 // The pointers in all of those still point into 'intermediateBuffer'.
1953 buffer.append(static_cast<char *>(dataBuffer[1].pvBuffer),
1954 dataBuffer[1].cbBuffer);
1955 totalRead += dataBuffer[1].cbBuffer;
1956#ifdef QSSLSOCKET_DEBUG
1957 qCDebug(lcTlsBackendSchannel, "Decrypted %lu bytes. New read buffer size: %d",
1958 dataBuffer[1].cbBuffer, buffer.size());
1959#endif
1960 }
1961 if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
1962 // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
1963 // dataBuffer[3].cbBuffer indicates the amount of bytes _NOT_ processed,
1964 // the rest need to be stored.
1965 retainExtraData(intermediateBuffer, dataBuffer[3]);
1966 } else {
1967 intermediateBuffer.resize(0);
1968 }
1969 }
1970
1971 if (status == SEC_E_INCOMPLETE_MESSAGE) {
1972 missingData = checkIncompleteData(dataBuffer[0]);
1973#ifdef QSSLSOCKET_DEBUG
1974 qCDebug(lcTlsBackendSchannel, "We didn't have enough data to decrypt anything, will try again!");
1975#endif
1976 // We try again, but if we don't get any more data then we leave
1977 hadIncompleteData = true;
1978 } else if (status == SEC_E_INVALID_HANDLE) {
1979 // I don't think this should happen, if it does we're done...
1980 qCWarning(lcTlsBackendSchannel, "The internal SSPI handle is invalid!");
1981 Q_UNREACHABLE();
1982 } else if (status == SEC_E_INVALID_TOKEN) {
1983 // Supposedly we have an invalid token, it's under-documented what
1984 // this means, so to be safe we disconnect.
1985 shutdown = true;
1987 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
1988 break;
1989 } else if (status == SEC_E_MESSAGE_ALTERED) {
1990 // The message has been altered, disconnect now.
1991 shutdown = true; // skips sending the shutdown alert
1993 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
1994 schannelErrorToString(status));
1995 break;
1996 } else if (status == SEC_E_OUT_OF_SEQUENCE) {
1997 // @todo: I don't know if this one is actually "fatal"..
1998 // This path might never be hit as it seems this is for connection-oriented connections,
1999 // while SEC_E_MESSAGE_ALTERED is for stream-oriented ones (what we use).
2000 shutdown = true; // skips sending the shutdown alert
2002 setErrorAndEmit(d, QAbstractSocket::SslInternalError,
2003 schannelErrorToString(status));
2004 break;
2005 } else if (status == SEC_E_DECRYPT_FAILURE) {
2006 // It's not documented as a possible return value for DecryptMessage,
2007 // but we see that this may happen - supposed to be a bug in Schannel (with TLS 1.3?)
2008 shutdown = true; // skips sending the shutdown alert
2010 setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
2011 break;
2012 } else if (status == SEC_I_CONTEXT_EXPIRED) {
2013 // 'remote' has initiated a shutdown
2015 break;
2016 } else if (status == SEC_I_RENEGOTIATE) {
2017 // 'remote' wants to renegotiate
2018#ifdef QSSLSOCKET_DEBUG
2019 qCDebug(lcTlsBackendSchannel, "The peer wants to renegotiate.");
2020#endif
2021 schannelState = SchannelState::Renegotiate;
2022 renegotiating = true;
2023
2024 // We need to call 'continueHandshake' or else there's no guarantee it ever gets called
2026 break;
2027 }
2028 }
2029
2030 if (totalRead) {
2031 if (bool *readyReadEmittedPointer = d->readyReadPointer())
2032 *readyReadEmittedPointer = true;
2033 emit q->readyRead();
2034 emit q->channelReadyRead(0);
2035 }
2036}
2037
2038void TlsCryptographSchannel::sendShutdown()
2039{
2040 Q_ASSERT(d);
2041
2042 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
2043 DWORD shutdownToken = SCHANNEL_SHUTDOWN;
2044 SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(DWORD), SECBUFFER_TOKEN);
2045 SecBufferDesc token{
2046 SECBUFFER_VERSION,
2047 1,
2048 &buffer
2049 };
2050 auto status = ApplyControlToken(&contextHandle, &token);
2051
2052 if (status != SEC_E_OK) {
2053#ifdef QSSLSOCKET_DEBUG
2054 qCDebug(lcTlsBackendSchannel)
2055 << "Failed to apply shutdown control token:" << schannelErrorToString(status);
2056#endif
2057 return;
2058 }
2059
2060 SecBuffer outBuffers[3];
2061 outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
2062 outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
2063 outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
2064 auto freeBuffers = qScopeGuard([&outBuffers]() {
2065 for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
2066 if (outBuffers[i].pvBuffer)
2067 FreeContextBuffer(outBuffers[i].pvBuffer);
2068 }
2069 });
2070 SecBufferDesc outputBufferDesc{
2071 SECBUFFER_VERSION,
2072 ARRAYSIZE(outBuffers),
2073 outBuffers
2074 };
2075
2076 ULONG contextReq = getContextRequirements();
2077 TimeStamp expiry;
2078 if (isClient) {
2079 status = InitializeSecurityContext(&credentialHandle, // phCredential
2080 &contextHandle, // phContext
2081 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
2082 contextReq, // fContextReq
2083 0, // Reserved1
2084 0, // TargetDataRep (unused)
2085 nullptr, // pInput
2086 0, // Reserved2
2087 nullptr, // phNewContext (we already have one)
2088 &outputBufferDesc, // pOutput
2089 &contextAttributes, // pfContextAttr
2090 &expiry // ptsExpiry
2091 );
2092 } else {
2093 status = AcceptSecurityContext(
2094 &credentialHandle, // phCredential
2095 &contextHandle, // phContext
2096 nullptr, // pInput
2097 contextReq, // fContextReq
2098 0, // TargetDataRep (unused)
2099 nullptr, // phNewContext
2100 &outputBufferDesc, // pOutput
2101 &contextAttributes, // pfContextAttr,
2102 &expiry // ptsTimeStamp
2103 );
2104 }
2105 if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
2106 if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, false)) {
2107 // We failed to send the shutdown message, but it's not that important since we're
2108 // shutting down anyway.
2109 return;
2110 }
2111 } else {
2112#ifdef QSSLSOCKET_DEBUG
2113 qCDebug(lcTlsBackendSchannel)
2114 << "Failed to initialize shutdown:" << schannelErrorToString(status);
2115#endif
2116 }
2117}
2118
2120{
2121 Q_ASSERT(q);
2122 Q_ASSERT(d);
2123 auto *plainSocket = d->plainTcpSocket();
2124 Q_ASSERT(plainSocket);
2125
2126 if (SecIsValidHandle(&contextHandle)) {
2127 if (!shutdown) {
2128 shutdown = true;
2129 if (plainSocket->state() != QAbstractSocket::UnconnectedState && q->isEncrypted()) {
2130 sendShutdown();
2131 transmit();
2132 }
2133 }
2134 }
2135 plainSocket->disconnectFromHost();
2136}
2137
2139{
2140 Q_ASSERT(d);
2141 auto *plainSocket = d->plainTcpSocket();
2142 Q_ASSERT(plainSocket);
2143 d->setEncrypted(false);
2144
2145 shutdown = true;
2146 if (plainSocket->bytesAvailable() > 0 || hasUndecryptedData()) {
2147 // Read as much as possible because this is likely our last chance
2148 qint64 tempMax = d->maxReadBufferSize();
2149 d->setMaxReadBufferSize(0); // Unlimited
2150 transmit();
2151 d->setMaxReadBufferSize(tempMax);
2152 // Since there were bytes still available we don't want to deallocate
2153 // our context yet. It will happen later, when the socket is re-used or
2154 // destroyed.
2155 } else {
2156 deallocateContext();
2157 freeCredentialsHandle();
2158 }
2159}
2160
2162{
2163 Q_ASSERT(q);
2164
2165 if (!q->isEncrypted())
2166 return {};
2167
2168 const auto sessionProtocol = toQtSslProtocol(connectionInfo.dwProtocol);
2169
2170 const auto ciphers = ciphersByName(QStringView(cipherInfo.szCipherSuite));
2171 for (const auto& cipher : ciphers) {
2172 if (cipher.protocol() == sessionProtocol)
2173 return cipher;
2174 }
2175
2176 return {};
2177}
2178
2180{
2181 if (!q->isEncrypted())
2182 return QSsl::SslProtocol::UnknownProtocol;
2183 return toQtSslProtocol(connectionInfo.dwProtocol);
2184}
2185
2187{
2188 Q_ASSERT(q);
2189 Q_ASSERT(d);
2190 auto *plainSocket = d->plainTcpSocket();
2191 Q_ASSERT(plainSocket);
2192
2193 const bool isServer = d->tlsMode() == QSslSocket::SslServerMode;
2194 switch (schannelState) {
2195 case SchannelState::InitializeHandshake:
2196 if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
2198 return;
2199 }
2200 if (!SecIsValidHandle(&credentialHandle)) // Needed to support tst_QSslSocket::setEmptyKey
2201 return;
2202 if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
2204 return;
2205 }
2206 if (schannelState != SchannelState::PerformHandshake)
2207 break;
2208 Q_FALLTHROUGH();
2209 case SchannelState::PerformHandshake:
2210 if (!performHandshake()) {
2212 return;
2213 }
2214 if (schannelState != SchannelState::VerifyHandshake)
2215 break;
2216 Q_FALLTHROUGH();
2217 case SchannelState::VerifyHandshake:
2218 // if we're in shutdown or renegotiating then we might not need to verify
2219 // (since we already did)
2220 if (!verifyHandshake()) {
2221 shutdown = true; // Skip sending shutdown alert
2222 q->abort(); // We don't want to send buffered data
2224 return;
2225 }
2226 if (schannelState != SchannelState::Done)
2227 break;
2228 Q_FALLTHROUGH();
2229 case SchannelState::Done:
2230 // connectionEncrypted is already true if we come here from a renegotiation
2231 if (!q->isEncrypted()) {
2232 d->setEncrypted(true); // all is done
2233 emit q->encrypted();
2234 }
2235 renegotiating = false;
2236 if (d->isPendingClose()) {
2237 d->setPendingClose(false);
2239 } else {
2240 transmit();
2241 }
2242 break;
2243 case SchannelState::Renegotiate:
2244 if (!renegotiate()) {
2246 return;
2247 } else if (intermediateBuffer.size() || plainSocket->bytesAvailable()) {
2249 }
2250 break;
2251 }
2252}
2253
2255{
2256 return sslErrors;
2257}
2258
2259/*
2260 Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
2261*/
2262bool TlsCryptographSchannel::checkSslErrors()
2263{
2264 if (sslErrors.isEmpty())
2265 return true;
2266
2267 Q_ASSERT(q);
2268 Q_ASSERT(d);
2269 const auto &configuration = q->sslConfiguration();
2270 auto *plainSocket = d->plainTcpSocket();
2271
2272 emit q->sslErrors(sslErrors);
2273
2274 const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
2275 || (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
2276 && d->tlsMode() == QSslSocket::SslClientMode);
2277 const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
2278 // check whether we need to emit an SSL handshake error
2279 if (doVerifyPeer && doEmitSslError) {
2280 if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
2281 QSslSocketPrivate::pauseSocketNotifiers(q);
2282 d->setPaused(true);
2283 } else {
2284 setErrorAndEmit(d, QAbstractSocket::SslHandshakeFailedError,
2285 sslErrors.constFirst().errorString());
2286 plainSocket->disconnectFromHost();
2287 }
2288 return false;
2289 }
2290
2291 return true;
2292}
2293
2294static void attachPrivateKeyToCertificate(const QSslCertificate &certificate,
2295 const QSslKey &privateKey)
2296{
2297 QAsn1Element elem = _q_PKCS12_key(privateKey);
2298 QByteArray buffer;
2299 QDataStream stream(&buffer, QDataStream::WriteOnly);
2300 elem.write(stream);
2301 NCRYPT_PROV_HANDLE provider = 0;
2302 SECURITY_STATUS status = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0);
2303 if (status != SEC_E_OK) {
2304 qCWarning(lcTlsBackendSchannel())
2305 << "Failed to open ncrypt storage provider:" << schannelErrorToString(status);
2306 return;
2307 }
2308 const auto freeProvider = qScopeGuard([provider]() { NCryptFreeObject(provider); });
2309
2310 const QString certName = [certificate]() {
2311 if (auto cn = certificate.subjectInfo(QSslCertificate::CommonName); !cn.isEmpty())
2312 return cn.front();
2313 return QString();
2314 }();
2315 QSpan<const QChar> nameSpan(certName);
2316 NCryptBuffer nbuffer{ ULONG(nameSpan.size_bytes() + sizeof(char16_t)),
2317 NCRYPTBUFFER_PKCS_KEY_NAME,
2318 const_reinterpret_cast<void *>(nameSpan.data()) };
2319 NCryptBufferDesc bufferDesc{ NCRYPTBUFFER_VERSION, 1, &nbuffer };
2320 auto *bufferDescPtr = nameSpan.isEmpty() ? nullptr : &bufferDesc;
2321 NCRYPT_KEY_HANDLE ncryptKey = 0;
2322 status = NCryptImportKey(provider, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, bufferDescPtr, &ncryptKey,
2323 PBYTE(buffer.data()), buffer.size(), 0);
2324 if (status != SEC_E_OK) {
2325 qCWarning(lcTlsBackendSchannel())
2326 << "Failed to import private key:" << schannelErrorToString(status);
2327 return;
2328 }
2329 const auto freeKey = qScopeGuard([ncryptKey]() { NCryptFreeObject(ncryptKey); });
2330
2331 CERT_CONTEXT *context = PCERT_CONTEXT(certificate.handle());
2332 Q_ASSERT(context);
2333
2334 CRYPT_DATA_BLOB keyBlob = { sizeof(ncryptKey), PBYTE(&ncryptKey) };
2335 BOOL ok =
2336 CertSetCertificateContextProperty(context, CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, &keyBlob);
2337 if (!ok) {
2338 auto error = GetLastError();
2339 if (lcTlsBackendSchannel().isWarningEnabled())
2340 qErrnoWarning(int(error), "Failed to set ncrypt handle property.");
2341 return;
2342 }
2343
2344 CRYPT_KEY_PROV_INFO provInfo{
2345 const_reinterpret_cast<LPWSTR>(certName.constData()),
2346 const_cast<LPWSTR>(MS_KEY_STORAGE_PROVIDER),
2347 0,
2348 CERT_SET_KEY_PROV_HANDLE_PROP_ID | CERT_SET_KEY_CONTEXT_PROP_ID,
2349 0,
2350 nullptr,
2351 0,
2352 };
2353 ok = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2354 CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, &provInfo);
2355 if (!ok) {
2356 auto error = GetLastError();
2357 if (lcTlsBackendSchannel().isWarningEnabled())
2358 qErrnoWarning(int(error), "Failed to set key provider info property.");
2359 return;
2360 }
2361}
2362
2363void TlsCryptographSchannel::initializeCertificateStores()
2364{
2365 //// helper function which turns a chain into a certificate store
2366 Q_ASSERT(d);
2367 Q_ASSERT(q);
2368 const auto &configuration = q->sslConfiguration();
2369
2370 auto createStoreFromCertificateChain = [](const QList<QSslCertificate> certChain, const QSslKey &privateKey) {
2371 const wchar_t *passphrase = L"";
2372 // Need to embed the private key in the certificate
2373 QByteArray pkcs12 = _q_makePkcs12(certChain,
2374 privateKey,
2375 QString::fromWCharArray(passphrase, 0));
2376 CRYPT_DATA_BLOB pfxBlob;
2377 pfxBlob.cbData = DWORD(pkcs12.length());
2378 pfxBlob.pbData = reinterpret_cast<unsigned char *>(pkcs12.data());
2379 // ALWAYS_CNG to import using "Cryptography API: Next Generation (CNG)"
2380 // NO_PERSIST_KEY to request not persisting anything imported to disk
2381 constexpr DWORD flags = PKCS12_ALWAYS_CNG_KSP | PKCS12_NO_PERSIST_KEY;
2382 return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, flags));
2383 };
2384
2385 if (!configuration.localCertificateChain().isEmpty()) {
2386 if (configuration.privateKey().isNull()) {
2387 setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
2388 QSslSocket::tr("Cannot provide a certificate with no key"));
2389 return;
2390 }
2391 if (localCertificateStore == nullptr) {
2392 localCertificateStore =
2393 createStoreFromCertificateChain(configuration.localCertificateChain(), {});
2394 if (localCertificateStore) {
2395 const CERT_CONTEXT *certificateContext = CertFindCertificateInStore(
2396 localCertificateStore.get(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
2397 CERT_FIND_ANY, nullptr, nullptr);
2398 if (certificateContext) {
2399 auto *backend = QTlsBackend::backend<X509CertificateSchannel>(
2400 configuration.localCertificate());
2401 backend->certificateContext.reset(
2402 CertDuplicateCertificateContext(certificateContext));
2403
2404 DWORD keySpec = 0;
2405 BOOL mustFree = FALSE;
2406 NCRYPT_KEY_HANDLE testKey = 0;
2407 BOOL ok = CryptAcquireCertificatePrivateKey(
2408 certificateContext, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, nullptr,
2409 &testKey, &keySpec, &mustFree);
2410 if (mustFree)
2411 NCryptFreeObject(testKey);
2412 if (!ok) {
2413 attachPrivateKeyToCertificate(configuration.localCertificate(),
2414 configuration.privateKey());
2415 }
2416 }
2417 } else {
2418 qCWarning(lcTlsBackendSchannel, "Failed to load certificate chain!");
2419 }
2420 }
2421 }
2422
2423 if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
2424 caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
2425 {}); // No private key for the CA certs
2426 }
2427}
2428
2429bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
2430{
2431 Q_ASSERT(certContext);
2432 Q_ASSERT(q);
2433 Q_ASSERT(d);
2434
2435 const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
2436
2437 // Create a collection of stores so we can pass in multiple stores as additional locations to
2438 // search for the certificate chain
2439 auto tempCertCollection = QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
2440 X509_ASN_ENCODING,
2441 0,
2442 CERT_STORE_CREATE_NEW_FLAG,
2443 nullptr));
2444 if (!tempCertCollection) {
2445#ifdef QSSLSOCKET_DEBUG
2446 qCWarning(lcTlsBackendSchannel, "Failed to create certificate store collection!");
2447#endif
2448 return false;
2449 }
2450
2451 if (rootCertOnDemandLoadingAllowed()) {
2452 // @future(maybe): following the OpenSSL backend these certificates should be added into
2453 // the Ca list, not just included during verification.
2454 // That being said, it's not trivial to add the root certificates (if and only if they
2455 // came from the system root store). And I don't see this mentioned in our documentation.
2456 auto rootStore = QHCertStorePointer(
2457 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
2458 CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
2459
2460 if (!rootStore) {
2461#ifdef QSSLSOCKET_DEBUG
2462 qCWarning(lcTlsBackendSchannel, "Failed to open the system root CA certificate store!");
2463#endif
2464 return false;
2465 } else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
2466#ifdef QSSLSOCKET_DEBUG
2467 qCWarning(lcTlsBackendSchannel,
2468 "Failed to add the system root CA certificate store to the certificate store "
2469 "collection!");
2470#endif
2471 return false;
2472 }
2473 }
2474 if (caCertificateStore) {
2475 if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
2476#ifdef QSSLSOCKET_DEBUG
2477 qCWarning(lcTlsBackendSchannel,
2478 "Failed to add the user's CA certificate store to the certificate store "
2479 "collection!");
2480#endif
2481 return false;
2482 }
2483 }
2484
2485 if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
2486#ifdef QSSLSOCKET_DEBUG
2487 qCWarning(lcTlsBackendSchannel,
2488 "Failed to add certificate's origin store to the certificate store collection!");
2489#endif
2490 return false;
2491 }
2492
2493 CERT_CHAIN_PARA parameters;
2494 ZeroMemory(&parameters, sizeof(parameters));
2495 parameters.cbSize = sizeof(CERT_CHAIN_PARA);
2496 parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
2497 parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
2498 LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
2499 : szOID_PKIX_KP_CLIENT_AUTH);
2500 parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
2501
2502 QTlsBackend::clearPeerCertificates(d);
2503 const CERT_CHAIN_CONTEXT *chainContext = nullptr;
2504 auto freeCertChain = qScopeGuard([&chainContext]() {
2505 if (chainContext)
2506 CertFreeCertificateChain(chainContext);
2507 });
2508 BOOL status = CertGetCertificateChain(nullptr, // hChainEngine, default
2509 certContext, // pCertContext
2510 nullptr, // pTime, 'now'
2511 tempCertCollection.get(), // hAdditionalStore, additional cert store
2512 &parameters, // pChainPara
2513 CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, // dwFlags
2514 nullptr, // reserved
2515 &chainContext // ppChainContext
2516 );
2517 if (status == FALSE || !chainContext || chainContext->cChain == 0) {
2518 QSslError error(QSslError::UnableToVerifyFirstCertificate);
2519 sslErrors += error;
2520 emit q->peerVerifyError(error);
2521 return q->state() == QAbstractSocket::ConnectedState;
2522 }
2523
2524 // Helper-function to get a QSslCertificate given a CERT_CHAIN_ELEMENT
2525 static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
2526 if (!element)
2527 return QSslCertificate();
2528
2529 const CERT_CONTEXT *certContext = element->pCertContext;
2530 return QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(certContext);
2531 };
2532
2533 // Pick a chain to use as the certificate chain, if multiple are available:
2534 // According to https://docs.microsoft.com/en-gb/windows/desktop/api/wincrypt/ns-wincrypt-_cert_chain_context
2535 // this seems to be the best way to get a trusted chain.
2536 CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
2537
2538 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
2539 auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate,
2540 getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
2541 sslErrors += error;
2542 emit q->peerVerifyError(error);
2543 if (q->state() != QAbstractSocket::ConnectedState)
2544 return false;
2545 }
2546 if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2547 // @Note: This is actually one of two errors:
2548 // "either the certificate cannot be used to issue other certificates, or the chain path length has been exceeded."
2549 // But here we are checking the chain's status, so we assume the "issuing" error cannot occur here.
2550 auto error = QSslError(QSslError::PathLengthExceeded);
2551 sslErrors += error;
2552 emit q->peerVerifyError(error);
2553 if (q->state() != QAbstractSocket::ConnectedState)
2554 return false;
2555 }
2556 static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
2557 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2558 | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
2559 | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
2560 if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
2561 auto error = QSslError(QSslError::SslError::UnspecifiedError);
2562 sslErrors += error;
2563 emit q->peerVerifyError(error);
2564 if (q->state() != QAbstractSocket::ConnectedState)
2565 return false;
2566 }
2567
2568 DWORD verifyDepth = chain->cElement;
2569 if (q->peerVerifyDepth() > 0 && DWORD(q->peerVerifyDepth()) < verifyDepth)
2570 verifyDepth = DWORD(q->peerVerifyDepth());
2571
2572 const auto &caCertificates = q->sslConfiguration().caCertificates();
2573
2574 if (!rootCertOnDemandLoadingAllowed()
2575 && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
2576 && (q->peerVerifyMode() == QSslSocket::VerifyPeer
2577 || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
2578 // When verifying a peer Windows "helpfully" builds a chain that
2579 // may include roots from the system store. But we don't want that if
2580 // the user has set their own CA certificates.
2581 // Since Windows claims this is not a partial chain the root is included
2582 // and we have to check that it is one of our configured CAs.
2583 CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
2584 QSslCertificate certificate = getCertificateFromChainElement(element);
2585 if (!caCertificates.contains(certificate)) {
2586 auto error = QSslError(QSslError::CertificateUntrusted, certificate);
2587 sslErrors += error;
2588 emit q->peerVerifyError(error);
2589 if (q->state() != QAbstractSocket::ConnectedState)
2590 return false;
2591 }
2592 }
2593
2594 QList<QSslCertificate> peerCertificateChain;
2595 for (DWORD i = 0; i < verifyDepth; i++) {
2596 CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
2597 QSslCertificate certificate = getCertificateFromChainElement(element);
2598 if (certificate.isNull()) {
2599 const auto &previousCert = !peerCertificateChain.isEmpty() ? peerCertificateChain.last()
2600 : QSslCertificate();
2601 auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate, previousCert);
2602 sslErrors += error;
2603 emit q->peerVerifyError(error);
2604 if (previousCert.isNull() || q->state() != QAbstractSocket::ConnectedState)
2605 return false;
2606 }
2607 const QList<QSslCertificateExtension> extensions = certificate.extensions();
2608
2609#ifdef QSSLSOCKET_DEBUG
2610 qCDebug(lcTlsBackendSchannel) << "issuer:" << certificate.issuerDisplayName()
2611 << "\nsubject:" << certificate.subjectDisplayName()
2612 << "\nQSslCertificate info:" << certificate
2613 << "\nextended error info:" << element->pwszExtendedErrorInfo
2614 << "\nerror status:" << element->TrustStatus.dwErrorStatus;
2615#endif
2616
2617 peerCertificateChain.append(certificate);
2618 QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
2619
2620 if (certificate.isBlacklisted()) {
2621 const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
2622 sslErrors += error;
2623 emit q->peerVerifyError(error);
2624 if (q->state() != QAbstractSocket::ConnectedState)
2625 return false;
2626 }
2627
2628 LONG result = CertVerifyTimeValidity(nullptr /*== now */, element->pCertContext->pCertInfo);
2629 if (result != 0) {
2630 auto error = QSslError(result == -1 ? QSslError::CertificateNotYetValid
2631 : QSslError::CertificateExpired,
2632 certificate);
2633 sslErrors += error;
2634 emit q->peerVerifyError(error);
2635 if (q->state() != QAbstractSocket::ConnectedState)
2636 return false;
2637 }
2638
2639 //// Errors
2640 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
2641 // handled right above
2642 Q_ASSERT(!sslErrors.isEmpty());
2643 }
2644 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
2645 auto error = QSslError(QSslError::CertificateRevoked, certificate);
2646 sslErrors += error;
2647 emit q->peerVerifyError(error);
2648 if (q->state() != QAbstractSocket::ConnectedState)
2649 return false;
2650 }
2651 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
2652 auto error = QSslError(QSslError::CertificateSignatureFailed, certificate);
2653 sslErrors += error;
2654 emit q->peerVerifyError(error);
2655 if (q->state() != QAbstractSocket::ConnectedState)
2656 return false;
2657 }
2658
2659 // While netscape shouldn't be relevant now it defined an extension which is
2660 // still in use. Schannel does not check this automatically, so we do it here.
2661 // It is used to differentiate between client and server certificates.
2662 if (netscapeWrongCertType(extensions, isClient, i == 0))
2663 element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
2664
2665 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
2666 auto error = QSslError(QSslError::InvalidPurpose, certificate);
2667 sslErrors += error;
2668 emit q->peerVerifyError(error);
2669 if (q->state() != QAbstractSocket::ConnectedState)
2670 return false;
2671 }
2672 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
2673 // Override this error if we have the certificate inside our trusted CAs list.
2674 const bool isTrustedRoot = caCertificates.contains(certificate);
2675 if (!isTrustedRoot) {
2676 auto error = QSslError(QSslError::CertificateUntrusted, certificate);
2677 sslErrors += error;
2678 emit q->peerVerifyError(error);
2679 if (q->state() != QAbstractSocket::ConnectedState)
2680 return false;
2681 }
2682 }
2683 static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
2684 | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
2685 if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
2686 // @future(maybe): Do something with this
2687 }
2688
2689 // Dumping ground of errors that don't fit our specific errors
2690 static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
2691 | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
2692 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
2693 | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
2694 | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
2695 | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
2696 | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
2697 | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
2698 if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
2699 auto error = QSslError(QSslError::UnspecifiedError, certificate);
2700 sslErrors += error;
2701 emit q->peerVerifyError(error);
2702 if (q->state() != QAbstractSocket::ConnectedState)
2703 return false;
2704 }
2705 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
2706 auto it = std::find_if(extensions.cbegin(), extensions.cend(),
2707 [](const QSslCertificateExtension &extension) {
2708 return extension.name() == "basicConstraints"_L1;
2709 });
2710 if (it != extensions.cend()) {
2711 // @Note: This is actually one of two errors:
2712 // "either the certificate cannot be used to issue other certificates,
2713 // or the chain path length has been exceeded."
2714 QVariantMap basicConstraints = it->value().toMap();
2715 QSslError error;
2716 if (i > 0 && !basicConstraints.value("ca"_L1, false).toBool())
2717 error = QSslError(QSslError::InvalidPurpose, certificate);
2718 else
2719 error = QSslError(QSslError::PathLengthExceeded, certificate);
2720 sslErrors += error;
2721 emit q->peerVerifyError(error);
2722 if (q->state() != QAbstractSocket::ConnectedState)
2723 return false;
2724 }
2725 }
2726 if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
2727 auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
2728 sslErrors += error;
2729 emit q->peerVerifyError(error);
2730 if (q->state() != QAbstractSocket::ConnectedState)
2731 return false;
2732 }
2733
2734 if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
2735 // If it's self-signed *and* a CA then we can assume it's a root CA certificate
2736 // and we can ignore the "self-signed" note:
2737 // We check the basicConstraints certificate extension when possible, but this didn't
2738 // exist for version 1, so we can only guess in that case
2739 const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
2740 || certificate.version() == "1";
2741
2742 // Root certificate tends to be signed by themselves, so ignore self-signed status.
2743 if (!isRootCertificateAuthority) {
2744 auto error = QSslError(QSslError::SelfSignedCertificate, certificate);
2745 sslErrors += error;
2746 emit q->peerVerifyError(error);
2747 if (q->state() != QAbstractSocket::ConnectedState)
2748 return false;
2749 }
2750 }
2751 }
2752
2753 if (!peerCertificateChain.isEmpty())
2754 QTlsBackend::storePeerCertificate(d, peerCertificateChain.constFirst());
2755
2756 const auto &configuration = q->sslConfiguration(); // Probably, updated by QTlsBackend::storePeerCertificate etc.
2757 // @Note: Somewhat copied from qsslsocket_mac.cpp
2758 const bool doVerifyPeer = q->peerVerifyMode() == QSslSocket::VerifyPeer
2759 || (q->peerVerifyMode() == QSslSocket::AutoVerifyPeer
2760 && d->tlsMode() == QSslSocket::SslClientMode);
2761 // Check the peer certificate itself. First try the subject's common name
2762 // (CN) as a wildcard, then try all alternate subject name DNS entries the
2763 // same way.
2764 if (!configuration.peerCertificate().isNull()) {
2765 // but only if we're a client connecting to a server
2766 // if we're the server, don't check CN
2767 if (d->tlsMode() == QSslSocket::SslClientMode) {
2768 const auto verificationPeerName = d->verificationName();
2769 const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
2770 if (!isMatchingHostname(configuration.peerCertificate(), peerName)) {
2771 // No matches in common names or alternate names.
2772 const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
2773 sslErrors += error;
2774 emit q->peerVerifyError(error);
2775 if (q->state() != QAbstractSocket::ConnectedState)
2776 return false;
2777 }
2778 }
2779 } else if (doVerifyPeer) {
2780 // No peer certificate presented. Report as error if the socket
2781 // expected one.
2782 const QSslError error(QSslError::NoPeerCertificate);
2783 sslErrors += error;
2784 emit q->peerVerifyError(error);
2785 if (q->state() != QAbstractSocket::ConnectedState)
2786 return false;
2787 }
2788
2789 return true;
2790}
2791
2792bool TlsCryptographSchannel::rootCertOnDemandLoadingAllowed()
2793{
2794 Q_ASSERT(d);
2795 return d->isRootsOnDemandAllowed() && QSslSocketPrivate::rootCertOnDemandLoadingSupported();
2796}
2797
2798} // namespace QTlsPrivate
2799
2800QT_END_NAMESPACE
void init(QSslSocket *q, QSslSocketPrivate *d) override
QSsl::SslProtocol sessionProtocol() const override
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
QList< CRYPTO_SETTINGS > cryptoSettingsForCiphers(const QList< QSslCipher > &ciphers)
bool containsTls13Cipher(const QList< QSslCipher > &ciphers)
UNICODE_STRING gcmChainingMode
QList< QSslCipher > ciphersByName(QStringView schannelSuiteName)
static void attachPrivateKeyToCertificate(const QSslCertificate &certificate, const QSslKey &privateKey)
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_2
#define SP_PROT_TLS1_3_SERVER
#define MAP_PROTOCOL(sp_protocol, q_protocol)
#define SP_PROT_TLS1_0
#define SP_PROT_TLS1_3
#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 SP_PROT_TLS1_1
#define SEC_E_APPLICATION_PROTOCOL_MISMATCH
#define SP_PROT_TLS1_CLIENT
#define SP_PROT_TLS1_0_CLIENT
#define SECBUFFER_ALERT
#define SP_PROT_TLS1_2_CLIENT
std::unique_ptr< void, QHCertStoreDeleter > QHCertStorePointer
Definition qwincrypt_p.h:42
QList< QSsl::SslProtocol > protocols