1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 // #define QSSLSOCKET_DEBUG
41 
42 #include "qssl_p.h"
43 #include "qsslsocket.h"
44 #include "qsslsocket_schannel_p.h"
45 #include "qsslcertificate.h"
46 #include "qsslcertificateextension.h"
47 #include "qsslcertificate_p.h"
48 #include "qsslcipher_p.h"
49 
50 #include <QtCore/qscopeguard.h>
51 #include <QtCore/qoperatingsystemversion.h>
52 #include <QtCore/qregularexpression.h>
53 #include <QtCore/qdatastream.h>
54 #include <QtCore/qmutex.h>
55 
56 #define SECURITY_WIN32
57 #include <security.h>
58 #include <schnlsp.h>
59 
60 #if NTDDI_VERSION >= NTDDI_WINBLUE && !defined(Q_CC_MINGW)
61 // ALPN = Application Layer Protocol Negotiation
62 #define SUPPORTS_ALPN 1
63 #endif
64 
65 // Not defined in MinGW
66 #ifndef SECBUFFER_ALERT
67 #define SECBUFFER_ALERT 17
68 #endif
69 #ifndef SECPKG_ATTR_APPLICATION_PROTOCOL
70 #define SECPKG_ATTR_APPLICATION_PROTOCOL 35
71 #endif
72 
73 // Another missing MinGW define
74 #ifndef SEC_E_APPLICATION_PROTOCOL_MISMATCH
75 #define SEC_E_APPLICATION_PROTOCOL_MISMATCH _HRESULT_TYPEDEF_(0x80090367L)
76 #endif
77 
78 // Also not defined in MinGW.......
79 #ifndef SP_PROT_TLS1_SERVER
80 #define SP_PROT_TLS1_SERVER 0x00000040
81 #endif
82 #ifndef SP_PROT_TLS1_CLIENT
83 #define SP_PROT_TLS1_CLIENT 0x00000080
84 #endif
85 #ifndef SP_PROT_TLS1_0_SERVER
86 #define SP_PROT_TLS1_0_SERVER SP_PROT_TLS1_SERVER
87 #endif
88 #ifndef SP_PROT_TLS1_0_CLIENT
89 #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
90 #endif
91 #ifndef SP_PROT_TLS1_0
92 #define SP_PROT_TLS1_0 (SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_0_SERVER)
93 #endif
94 #ifndef SP_PROT_TLS1_1_SERVER
95 #define SP_PROT_TLS1_1_SERVER 0x00000100
96 #endif
97 #ifndef SP_PROT_TLS1_1_CLIENT
98 #define SP_PROT_TLS1_1_CLIENT 0x00000200
99 #endif
100 #ifndef SP_PROT_TLS1_1
101 #define SP_PROT_TLS1_1 (SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER)
102 #endif
103 #ifndef SP_PROT_TLS1_2_SERVER
104 #define SP_PROT_TLS1_2_SERVER 0x00000400
105 #endif
106 #ifndef SP_PROT_TLS1_2_CLIENT
107 #define SP_PROT_TLS1_2_CLIENT 0x00000800
108 #endif
109 #ifndef SP_PROT_TLS1_2
110 #define SP_PROT_TLS1_2 (SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER)
111 #endif
112 #ifndef SP_PROT_TLS1_3_SERVER
113 #define SP_PROT_TLS1_3_SERVER 0x00001000
114 #endif
115 #ifndef SP_PROT_TLS1_3_CLIENT
116 #define SP_PROT_TLS1_3_CLIENT 0x00002000
117 #endif
118 #ifndef SP_PROT_TLS1_3
119 #define SP_PROT_TLS1_3 (SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER)
120 #endif
121 
122 /*
123     @future!:
124 
125     - Transmitting intermediate certificates
126         - Look for a way to avoid putting intermediate certificates in the certificate store
127         - No documentation on how to send the chain
128         - A stackoverflow question on this from 3 years ago implies schannel only sends intermediate
129             certificates if it's "in the system or user certificate store".
130                 - https://stackoverflow.com/q/30156584/2493610
131                 - This can be done by users, but we shouldn't add any and all local intermediate
132                     certs to the stores automatically.
133     - PSK support
134         - Was added in Windows 10 (it seems), documentation at time of writing is sparse/non-existent.
135             - Specifically about how to supply credentials when they're requested.
136             - Or how to recognize that they're requested in the first place.
137         - Skip certificate verification.
138         - Check if "PSK-only" is still required to do PSK _at all_ (all-around bad solution).
139         - Check if SEC_I_INCOMPLETE_CREDENTIALS is still returned for both "missing certificate" and
140             "missing PSK" when calling InitializeSecurityContext in "performHandshake".
141 
142     Medium priority:
143     - Setting cipher-suites (or ALG_ID)
144         - People have survived without it in WinRT
145 
146     Low priority:
147     - Possibly make RAII wrappers for SecBuffer (which I commonly create QScopeGuards for)
148 
149 */
150 
151 QT_BEGIN_NAMESPACE
152 
153 namespace {
createSecBuffer(void * ptr,unsigned long length,unsigned long bufferType)154 SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
155 {
156     return SecBuffer{ length, bufferType, ptr };
157 }
158 
createSecBuffer(QByteArray & buffer,unsigned long bufferType)159 SecBuffer createSecBuffer(QByteArray &buffer, unsigned long bufferType)
160 {
161     return createSecBuffer(buffer.data(), static_cast<unsigned long>(buffer.length()), bufferType);
162 }
163 
schannelErrorToString(qint32 status)164 QString schannelErrorToString(qint32 status)
165 {
166     switch (status) {
167     case SEC_E_INSUFFICIENT_MEMORY:
168         return QSslSocket::tr("Insufficient memory");
169     case SEC_E_INTERNAL_ERROR:
170         return QSslSocket::tr("Internal error");
171     case SEC_E_INVALID_HANDLE:
172         return QSslSocket::tr("An internal handle was invalid");
173     case SEC_E_INVALID_TOKEN:
174         return QSslSocket::tr("An internal token was invalid");
175     case SEC_E_LOGON_DENIED:
176         // According to the link below we get this error when Schannel receives TLS1_ALERT_ACCESS_DENIED
177         // https://docs.microsoft.com/en-us/windows/desktop/secauthn/schannel-error-codes-for-tls-and-ssl-alerts
178         return QSslSocket::tr("Access denied");
179     case SEC_E_NO_AUTHENTICATING_AUTHORITY:
180         return QSslSocket::tr("No authority could be contacted for authorization");
181     case SEC_E_NO_CREDENTIALS:
182         return QSslSocket::tr("No credentials");
183     case SEC_E_TARGET_UNKNOWN:
184         return QSslSocket::tr("The target is unknown or unreachable");
185     case SEC_E_UNSUPPORTED_FUNCTION:
186         return QSslSocket::tr("An unsupported function was requested");
187     case SEC_E_WRONG_PRINCIPAL:
188         // SNI error
189         return QSslSocket::tr("The hostname provided does not match the one received from the peer");
190     case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
191         return QSslSocket::tr("No common protocol exists between the client and the server");
192     case SEC_E_ILLEGAL_MESSAGE:
193         return QSslSocket::tr("Unexpected or badly-formatted message received");
194     case SEC_E_ENCRYPT_FAILURE:
195         return QSslSocket::tr("The data could not be encrypted");
196     case SEC_E_ALGORITHM_MISMATCH:
197         return QSslSocket::tr("No cipher suites in common");
198     case SEC_E_UNKNOWN_CREDENTIALS:
199         // This can mean "invalid argument" in some cases...
200         return QSslSocket::tr("The credentials were not recognized / Invalid argument");
201     case SEC_E_MESSAGE_ALTERED:
202         // According to the Internet it also triggers for messages that are out of order.
203         // https://microsoft.public.platformsdk.security.narkive.com/4JAvlMvD/help-please-schannel-security-contexts-and-decryptmessage
204         return QSslSocket::tr("The message was tampered with, damaged or out of sequence.");
205     case SEC_E_OUT_OF_SEQUENCE:
206         return QSslSocket::tr("A message was received out of sequence.");
207     case SEC_E_CONTEXT_EXPIRED:
208         return QSslSocket::tr("The TLS/SSL connection has been closed");
209     default:
210         return QSslSocket::tr("Unknown error occurred: %1").arg(status);
211     }
212 }
213 
toSchannelProtocol(QSsl::SslProtocol protocol)214 DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
215 {
216     DWORD protocols = SP_PROT_NONE;
217     switch (protocol) {
218     case QSsl::UnknownProtocol:
219         return DWORD(-1);
220     case QSsl::DtlsV1_0:
221     case QSsl::DtlsV1_2:
222     case QSsl::DtlsV1_0OrLater:
223     case QSsl::DtlsV1_2OrLater:
224         return DWORD(-1); // Not supported at the moment (@future)
225     case QSsl::AnyProtocol:
226         protocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2;
227         // @future Add TLS 1.3 when supported by Windows!
228         break;
229     case QSsl::SslV2:
230     case QSsl::SslV3:
231         return DWORD(-1); // Not supported
232     case QSsl::TlsV1SslV3:
233         protocols = SP_PROT_TLS1_0;
234         break;
235     case QSsl::TlsV1_0:
236         protocols = SP_PROT_TLS1_0;
237         break;
238     case QSsl::TlsV1_1:
239         protocols = SP_PROT_TLS1_1;
240         break;
241     case QSsl::TlsV1_2:
242         protocols = SP_PROT_TLS1_2;
243         break;
244     case QSsl::TlsV1_3:
245         if ((false)) // @future[0/1] Replace with version check once it's supported in Windows
246             protocols = SP_PROT_TLS1_3;
247         else
248             protocols = DWORD(-1);
249         break;
250     case QSsl::SecureProtocols: // TLS v1.0 and later is currently considered secure
251     case QSsl::TlsV1_0OrLater:
252         // For the "OrLater" protocols we fall through from one to the next, adding all of them
253         // in ascending order
254         protocols = SP_PROT_TLS1_0;
255         Q_FALLTHROUGH();
256     case QSsl::TlsV1_1OrLater:
257         protocols |= SP_PROT_TLS1_1;
258         Q_FALLTHROUGH();
259     case QSsl::TlsV1_2OrLater:
260         protocols |= SP_PROT_TLS1_2;
261         Q_FALLTHROUGH();
262     case QSsl::TlsV1_3OrLater:
263         if ((false)) // @future[1/1] Also replace this with a version check
264             protocols |= SP_PROT_TLS1_3;
265         else if (protocol == QSsl::TlsV1_3OrLater)
266             protocols = DWORD(-1); // if TlsV1_3OrLater was specifically chosen we should fail
267         break;
268     }
269     return protocols;
270 }
271 
272 /*!
273     \internal
274     Used when converting the established session's \a protocol back to
275     Qt's own SslProtocol type.
276 
277     Only one protocol should be passed in at a time.
278 */
toQtSslProtocol(DWORD protocol)279 QSsl::SslProtocol toQtSslProtocol(DWORD protocol)
280 {
281 #define MAP_PROTOCOL(sp_protocol, q_protocol) \
282     if (protocol & sp_protocol) {             \
283         Q_ASSERT(!(protocol & ~sp_protocol)); \
284         return q_protocol;                    \
285     }
286 
287     MAP_PROTOCOL(SP_PROT_TLS1_0, QSsl::TlsV1_0)
288     MAP_PROTOCOL(SP_PROT_TLS1_1, QSsl::TlsV1_1)
289     MAP_PROTOCOL(SP_PROT_TLS1_2, QSsl::TlsV1_2)
290     MAP_PROTOCOL(SP_PROT_TLS1_3, QSsl::TlsV1_3)
291 #undef MAP_PROTOCOL
292     Q_UNREACHABLE();
293     return QSsl::UnknownProtocol;
294 }
295 
296 /*!
297     \internal
298     Used by verifyCertContext to check if a client cert is used by a server or vice versa.
299 */
netscapeWrongCertType(const QList<QSslCertificateExtension> & extensions,bool isClient)300 bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bool isClient)
301 {
302     const auto netscapeIt = std::find_if(
303             extensions.cbegin(), extensions.cend(),
304             [](const QSslCertificateExtension &extension) {
305                 const auto netscapeCertType = QStringLiteral("2.16.840.1.113730.1.1");
306                 return extension.oid() == netscapeCertType;
307             });
308     if (netscapeIt != extensions.cend()) {
309         const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
310         int netscapeCertType = 0;
311         QDataStream dataStream(netscapeCertTypeByte);
312         dataStream >> netscapeCertType;
313         if (dataStream.status() != QDataStream::Status::Ok)
314             return true;
315         const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
316                                                   : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
317         if ((netscapeCertType & expectedPeerCertType) == 0)
318             return true;
319     }
320     return false;
321 }
322 
323 /*!
324     \internal
325     Used by verifyCertContext to check the basicConstraints certificate
326     extension to see if the certificate is a certificate authority.
327     Returns false if the certificate does not have the basicConstraints
328     extension or if it is not a certificate authority.
329 */
isCertificateAuthority(const QList<QSslCertificateExtension> & extensions)330 bool isCertificateAuthority(const QList<QSslCertificateExtension> &extensions)
331 {
332     auto it = std::find_if(extensions.cbegin(), extensions.cend(),
333                            [](const QSslCertificateExtension &extension) {
334                                return extension.name() == QLatin1String("basicConstraints");
335                            });
336     if (it != extensions.cend()) {
337         QVariantMap basicConstraints = it->value().toMap();
338         return basicConstraints.value(QLatin1String("ca"), false).toBool();
339     }
340     return false;
341 }
342 
343 /*!
344     \internal
345     Returns true if the attributes we requested from the context/handshake have
346     been given.
347 */
matchesContextRequirements(DWORD attributes,DWORD requirements,QSslSocket::PeerVerifyMode verifyMode,bool isClient)348 bool matchesContextRequirements(DWORD attributes, DWORD requirements,
349                                 QSslSocket::PeerVerifyMode verifyMode,
350                                 bool isClient)
351 {
352 #ifdef QSSLSOCKET_DEBUG
353 #define DEBUG_WARN(message) qCWarning(lcSsl, message)
354 #else
355 #define DEBUG_WARN(message)
356 #endif
357 
358 #define CHECK_ATTRIBUTE(attributeName)                                                                 \
359     do {                                                                                               \
360         const DWORD req##attributeName = isClient ? ISC_REQ_##attributeName : ASC_REQ_##attributeName; \
361         const DWORD ret##attributeName = isClient ? ISC_RET_##attributeName : ASC_RET_##attributeName; \
362         if (!(requirements & req##attributeName) != !(attributes & ret##attributeName)) {              \
363             DEBUG_WARN("Missing attribute \"" #attributeName "\"");                                    \
364             return false;                                                                              \
365         }                                                                                              \
366     } while (false)
367 
368     CHECK_ATTRIBUTE(CONFIDENTIALITY);
369     CHECK_ATTRIBUTE(REPLAY_DETECT);
370     CHECK_ATTRIBUTE(SEQUENCE_DETECT);
371     CHECK_ATTRIBUTE(STREAM);
372     if (verifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
373         CHECK_ATTRIBUTE(MUTUAL_AUTH);
374 
375     // This one is manual because there is no server / ASC_ version
376     if (isClient) {
377         const auto reqManualCredValidation = ISC_REQ_MANUAL_CRED_VALIDATION;
378         const auto retManualCredValidation = ISC_RET_MANUAL_CRED_VALIDATION;
379         if (!(requirements & reqManualCredValidation) != !(attributes & retManualCredValidation)) {
380             DEBUG_WARN("Missing attribute \"MANUAL_CRED_VALIDATION\"");
381             return false;
382         }
383     }
384 
385     return true;
386 #undef CHECK_ATTRIBUTE
387 #undef DEBUG_WARN
388 }
389 
390 template<typename Required, typename Actual>
391 Required const_reinterpret_cast(Actual *p)
392 {
393     return Required(p);
394 }
395 
396 #ifdef SUPPORTS_ALPN
supportsAlpn()397 bool supportsAlpn()
398 {
399     return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8_1;
400 }
401 
createAlpnString(const QByteArrayList & nextAllowedProtocols)402 QByteArray createAlpnString(const QByteArrayList &nextAllowedProtocols)
403 {
404     QByteArray alpnString;
405     if (!nextAllowedProtocols.isEmpty() && supportsAlpn()) {
406         const QByteArray names = [&nextAllowedProtocols]() {
407             QByteArray protocolString;
408             for (QByteArray proto : nextAllowedProtocols) {
409                 if (proto.size() > 255) {
410                     qCWarning(lcSsl) << "TLS ALPN extension" << proto
411                                      << "is too long and will be ignored.";
412                     continue;
413                 } else if (proto.isEmpty()) {
414                     continue;
415                 }
416                 protocolString += char(proto.length()) + proto;
417             }
418             return protocolString;
419         }();
420         if (names.isEmpty())
421             return alpnString;
422 
423         const quint16 namesSize = names.size();
424         const quint32 alpnId = SecApplicationProtocolNegotiationExt_ALPN;
425         const quint32 totalSize = sizeof(alpnId) + sizeof(namesSize) + namesSize;
426         alpnString = QByteArray::fromRawData(reinterpret_cast<const char *>(&totalSize), sizeof(totalSize))
427                 + QByteArray::fromRawData(reinterpret_cast<const char *>(&alpnId), sizeof(alpnId))
428                 + QByteArray::fromRawData(reinterpret_cast<const char *>(&namesSize), sizeof(namesSize))
429                 + names;
430     }
431     return alpnString;
432 }
433 #endif // SUPPORTS_ALPN
434 
readToBuffer(QByteArray & buffer,QTcpSocket * plainSocket)435 qint64 readToBuffer(QByteArray &buffer, QTcpSocket *plainSocket)
436 {
437     Q_ASSERT(plainSocket);
438     static const qint64 shrinkCutoff = 1024 * 12;
439     static const qint64 defaultRead = 1024 * 16;
440     qint64 bytesRead = 0;
441 
442     const auto toRead = std::min(defaultRead, plainSocket->bytesAvailable());
443     if (toRead > 0) {
444         const auto bufferSize = buffer.size();
445         buffer.reserve(bufferSize + toRead); // avoid growth strategy kicking in
446         buffer.resize(bufferSize + toRead);
447         bytesRead = plainSocket->read(buffer.data() + bufferSize, toRead);
448         buffer.resize(bufferSize + bytesRead);
449         // In case of excessive memory usage we shrink:
450         if (buffer.size() < shrinkCutoff && buffer.capacity() > defaultRead)
451             buffer.shrink_to_fit();
452     }
453 
454     return bytesRead;
455 }
456 
retainExtraData(QByteArray & buffer,const SecBuffer & secBuffer)457 void retainExtraData(QByteArray &buffer, const SecBuffer &secBuffer)
458 {
459     Q_ASSERT(secBuffer.BufferType == SECBUFFER_EXTRA);
460     if (int(secBuffer.cbBuffer) >= buffer.size())
461         return;
462 
463 #ifdef QSSLSOCKET_DEBUG
464     qCDebug(lcSsl, "We got SECBUFFER_EXTRA, will retain %lu bytes", secBuffer.cbBuffer);
465 #endif
466     std::move(buffer.end() - secBuffer.cbBuffer, buffer.end(), buffer.begin());
467     buffer.resize(secBuffer.cbBuffer);
468 }
469 
checkIncompleteData(const SecBuffer & secBuffer)470 qint64 checkIncompleteData(const SecBuffer &secBuffer)
471 {
472     if (secBuffer.BufferType == SECBUFFER_MISSING) {
473 #ifdef QSSLSOCKET_DEBUG
474         qCDebug(lcSsl, "Need %lu more bytes.", secBuffer.cbBuffer);
475 #endif
476         return secBuffer.cbBuffer;
477 }
478     return 0;
479 }
480 
481 } // anonymous namespace
482 
483 bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
484 bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
Q_GLOBAL_STATIC(QRecursiveMutex,qt_schannel_mutex)485 Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
486 
487 void QSslSocketPrivate::ensureInitialized()
488 {
489     const QMutexLocker locker(qt_schannel_mutex);
490     if (s_loadedCiphersAndCerts)
491         return;
492     s_loadedCiphersAndCerts = true;
493 
494     setDefaultCaCertificates(systemCaCertificates());
495     s_loadRootCertsOnDemand = true; // setDefaultCaCertificates sets it to false, re-enable it.
496 
497     resetDefaultCiphers();
498 }
499 
resetDefaultCiphers()500 void QSslSocketPrivate::resetDefaultCiphers()
501 {
502     setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
503     setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
504 }
505 
resetDefaultEllipticCurves()506 void QSslSocketPrivate::resetDefaultEllipticCurves()
507 {
508     Q_UNIMPLEMENTED();
509 }
510 
supportsSsl()511 bool QSslSocketPrivate::supportsSsl()
512 {
513     return true;
514 }
515 
systemCaCertificates()516 QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
517 {
518     // Copied from qsslsocket_openssl.cpp's systemCaCertificates function.
519     QList<QSslCertificate> systemCerts;
520     auto hSystemStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
521     if (hSystemStore) {
522         PCCERT_CONTEXT pc = nullptr;
523         while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
524                                                 CERT_FIND_ANY, nullptr, pc))) {
525             systemCerts.append(QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(pc));
526         }
527     }
528     return systemCerts;
529 }
530 
sslLibraryVersionNumber()531 long QSslSocketPrivate::sslLibraryVersionNumber()
532 {
533     const auto os = QOperatingSystemVersion::current();
534     return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
535 }
536 
sslLibraryVersionString()537 QString QSslSocketPrivate::sslLibraryVersionString()
538 {
539     const auto os = QOperatingSystemVersion::current();
540     return QString::fromLatin1("Secure Channel, %1 %2.%3.%4")
541             .arg(os.name(),
542                  QString::number(os.majorVersion()),
543                  QString::number(os.minorVersion()),
544                  QString::number(os.microVersion()));
545 }
546 
sslLibraryBuildVersionNumber()547 long QSslSocketPrivate::sslLibraryBuildVersionNumber()
548 {
549     // There is no separate build version
550     return sslLibraryVersionNumber();
551 }
552 
sslLibraryBuildVersionString()553 QString QSslSocketPrivate::sslLibraryBuildVersionString()
554 {
555     const auto os = QOperatingSystemVersion::current();
556     return QString::fromLatin1("%1.%2.%3")
557             .arg(QString::number(os.majorVersion()),
558                  QString::number(os.minorVersion()),
559                  QString::number(os.microVersion()));
560 }
561 
QSslSocketBackendPrivate()562 QSslSocketBackendPrivate::QSslSocketBackendPrivate()
563 {
564     SecInvalidateHandle(&credentialHandle);
565     SecInvalidateHandle(&contextHandle);
566     ensureInitialized();
567 }
568 
~QSslSocketBackendPrivate()569 QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
570 {
571     closeCertificateStores();
572     deallocateContext();
573     freeCredentialsHandle();
574     CertFreeCertificateContext(localCertContext);
575 }
576 
sendToken(void * token,unsigned long tokenLength,bool emitError)577 bool QSslSocketBackendPrivate::sendToken(void *token, unsigned long tokenLength, bool emitError)
578 {
579     if (tokenLength == 0)
580         return true;
581     const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
582     if (written != qint64(tokenLength)) {
583         // Failed to write/buffer everything or an error occurred
584         if (emitError)
585             setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
586         return false;
587     }
588     return true;
589 }
590 
targetName() const591 QString QSslSocketBackendPrivate::targetName() const
592 {
593     // Used for SNI extension
594     return verificationPeerName.isEmpty() ? q_func()->peerName() : verificationPeerName;
595 }
596 
getContextRequirements()597 ULONG QSslSocketBackendPrivate::getContextRequirements()
598 {
599     const bool isClient = mode == QSslSocket::SslClientMode;
600     ULONG req = 0;
601 
602     req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
603     req |= ISC_REQ_CONFIDENTIALITY; // Encrypt messages
604     req |= ISC_REQ_REPLAY_DETECT; // Detect replayed messages
605     req |= ISC_REQ_SEQUENCE_DETECT; // Detect out of sequence messages
606     req |= ISC_REQ_STREAM; // Support a stream-oriented connection
607 
608     if (isClient) {
609         req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
610     } else {
611         switch (configuration.peerVerifyMode) {
612         case QSslSocket::PeerVerifyMode::VerifyNone:
613         // There doesn't seem to be a way to ask for an optional client cert :-(
614         case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
615         case QSslSocket::PeerVerifyMode::QueryPeer:
616             break;
617         case QSslSocket::PeerVerifyMode::VerifyPeer:
618             req |= ISC_REQ_MUTUAL_AUTH;
619             break;
620         }
621     }
622 
623     return req;
624 }
625 
acquireCredentialsHandle()626 bool QSslSocketBackendPrivate::acquireCredentialsHandle()
627 {
628     Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
629 
630     const bool isClient = mode == QSslSocket::SslClientMode;
631     const DWORD protocols = toSchannelProtocol(configuration.protocol);
632     if (protocols == DWORD(-1)) {
633         setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
634                         QSslSocket::tr("Invalid protocol chosen"));
635         return false;
636     }
637 
638     const CERT_CHAIN_CONTEXT *chainContext = nullptr;
639     auto freeCertChain = qScopeGuard([&chainContext]() {
640         if (chainContext)
641             CertFreeCertificateChain(chainContext);
642     });
643 
644     DWORD certsCount = 0;
645     // Set up our certificate stores before trying to use one...
646     initializeCertificateStores();
647 
648     // Check if user has specified a certificate chain but it could not be loaded.
649     // This happens if there was something wrong with the certificate chain or there was no private
650     // key.
651     if (!configuration.localCertificateChain.isEmpty() && !localCertificateStore)
652         return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
653 
654     if (localCertificateStore != nullptr) {
655         CERT_CHAIN_FIND_BY_ISSUER_PARA findParam;
656         ZeroMemory(&findParam, sizeof(findParam));
657         findParam.cbSize = sizeof(findParam);
658         findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH;
659 
660         // There should only be one chain in our store, so.. we grab that one.
661         chainContext = CertFindChainInStore(localCertificateStore.get(),
662                                             X509_ASN_ENCODING,
663                                             0,
664                                             CERT_CHAIN_FIND_BY_ISSUER,
665                                             &findParam,
666                                             nullptr);
667         if (!chainContext) {
668             const QString message = isClient
669                     ? QSslSocket::tr("The certificate provided cannot be used for a client.")
670                     : QSslSocket::tr("The certificate provided cannot be used for a server.");
671             setErrorAndEmit(QAbstractSocket::SocketError::SslInvalidUserDataError, message);
672             return false;
673         }
674         Q_ASSERT(chainContext->cChain == 1);
675         Q_ASSERT(chainContext->rgpChain[0]);
676         Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1);
677         Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]);
678         Q_ASSERT(!localCertContext);
679         localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0]
680                                                                    ->rgpElement[0]
681                                                                    ->pCertContext);
682         certsCount = 1;
683         Q_ASSERT(localCertContext);
684     }
685 
686     SCHANNEL_CRED cred{
687         SCHANNEL_CRED_VERSION, // dwVersion
688         certsCount, // cCreds
689         &localCertContext, // paCred (certificate(s) containing a private key for authentication)
690         nullptr, // hRootStore
691 
692         0, // cMappers (reserved)
693         nullptr, // aphMappers (reserved)
694 
695         0, // cSupportedAlgs
696         nullptr, // palgSupportedAlgs (nullptr = system default) @future: QSslCipher-related
697 
698         protocols, // grbitEnabledProtocols
699         0, // dwMinimumCipherStrength (0 = system default)
700         0, // dwMaximumCipherStrength (0 = system default)
701         0, // dwSessionLifespan (0 = schannel default, 10 hours)
702         SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
703                 | SCH_CRED_NO_DEFAULT_CREDS, // dwFlags
704         0 // dwCredFormat (must be 0)
705     };
706 
707     TimeStamp expiration{};
708     auto status = AcquireCredentialsHandle(nullptr, // pszPrincipal (unused)
709                                            const_cast<wchar_t *>(UNISP_NAME), // pszPackage
710                                            isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND, // fCredentialUse
711                                            nullptr, // pvLogonID (unused)
712                                            &cred, // pAuthData
713                                            nullptr, // pGetKeyFn (unused)
714                                            nullptr, // pvGetKeyArgument (unused)
715                                            &credentialHandle, // phCredential
716                                            &expiration // ptsExpir
717     );
718 
719     if (status != SEC_E_OK) {
720         setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
721         return false;
722     }
723     return true;
724 }
725 
deallocateContext()726 void QSslSocketBackendPrivate::deallocateContext()
727 {
728     if (SecIsValidHandle(&contextHandle)) {
729         DeleteSecurityContext(&contextHandle);
730         SecInvalidateHandle(&contextHandle);
731     }
732 }
733 
freeCredentialsHandle()734 void QSslSocketBackendPrivate::freeCredentialsHandle()
735 {
736     if (SecIsValidHandle(&credentialHandle)) {
737         FreeCredentialsHandle(&credentialHandle);
738         SecInvalidateHandle(&credentialHandle);
739     }
740 }
741 
closeCertificateStores()742 void QSslSocketBackendPrivate::closeCertificateStores()
743 {
744     localCertificateStore.reset();
745     peerCertificateStore.reset();
746     caCertificateStore.reset();
747 }
748 
createContext()749 bool QSslSocketBackendPrivate::createContext()
750 {
751     Q_ASSERT(SecIsValidHandle(&credentialHandle));
752     Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
753     Q_ASSERT(mode == QSslSocket::SslClientMode);
754     ULONG contextReq = getContextRequirements();
755 
756     SecBuffer outBuffers[3];
757     outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
758     outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
759     outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
760     auto freeBuffers = qScopeGuard([&outBuffers]() {
761         for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
762             if (outBuffers[i].pvBuffer)
763                 FreeContextBuffer(outBuffers[i].pvBuffer);
764         }
765     });
766     SecBufferDesc outputBufferDesc{
767         SECBUFFER_VERSION,
768         ARRAYSIZE(outBuffers),
769         outBuffers
770     };
771 
772     TimeStamp expiry;
773 
774     SecBufferDesc alpnBufferDesc;
775     bool useAlpn = false;
776 #ifdef SUPPORTS_ALPN
777     configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
778     QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
779     useAlpn = !alpnString.isEmpty();
780     SecBuffer alpnBuffers[1];
781     alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
782     alpnBufferDesc = {
783         SECBUFFER_VERSION,
784         ARRAYSIZE(alpnBuffers),
785         alpnBuffers
786     };
787 #endif
788 
789     auto status = InitializeSecurityContext(&credentialHandle, // phCredential
790                                             nullptr, // phContext
791                                             const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
792                                             contextReq, // fContextReq
793                                             0, // Reserved1
794                                             0, // TargetDataRep (unused)
795                                             useAlpn ? &alpnBufferDesc : nullptr, // pInput
796                                             0, // Reserved2
797                                             &contextHandle, // phNewContext
798                                             &outputBufferDesc, // pOutput
799                                             &contextAttributes, // pfContextAttr
800                                             &expiry // ptsExpiry
801     );
802 
803     // This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
804     // should be the only non-error return-code here.
805     if (status != SEC_I_CONTINUE_NEEDED) {
806         setErrorAndEmit(QAbstractSocket::SslInternalError,
807                         QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
808         return false;
809     }
810 
811     if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
812         return false;
813     schannelState = SchannelState::PerformHandshake;
814     return true;
815 }
816 
acceptContext()817 bool QSslSocketBackendPrivate::acceptContext()
818 {
819     Q_ASSERT(SecIsValidHandle(&credentialHandle));
820     Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
821     Q_ASSERT(mode == QSslSocket::SslServerMode);
822     ULONG contextReq = getContextRequirements();
823 
824     if (missingData > plainSocket->bytesAvailable())
825         return true;
826 
827     missingData = 0;
828     readToBuffer(intermediateBuffer, plainSocket);
829     if (intermediateBuffer.isEmpty())
830         return true; // definitely need more data..
831 
832     SecBuffer inBuffers[2];
833     inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
834 
835 #ifdef SUPPORTS_ALPN
836     configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
837     // The string must be alive when we call AcceptSecurityContext
838     QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
839     if (!alpnString.isEmpty()) {
840         inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
841     } else
842 #endif
843     {
844         inBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
845     }
846 
847     SecBufferDesc inputBufferDesc{
848         SECBUFFER_VERSION,
849         ARRAYSIZE(inBuffers),
850         inBuffers
851     };
852 
853     SecBuffer outBuffers[3];
854     outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
855     outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
856     outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
857     auto freeBuffers = qScopeGuard([&outBuffers]() {
858         for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
859             if (outBuffers[i].pvBuffer)
860                 FreeContextBuffer(outBuffers[i].pvBuffer);
861         }
862     });
863     SecBufferDesc outputBufferDesc{
864         SECBUFFER_VERSION,
865         ARRAYSIZE(outBuffers),
866         outBuffers
867     };
868 
869     TimeStamp expiry;
870     auto status = AcceptSecurityContext(
871             &credentialHandle, // phCredential
872             nullptr, // phContext
873             &inputBufferDesc, // pInput
874             contextReq, // fContextReq
875             0, // TargetDataRep (unused)
876             &contextHandle, // phNewContext
877             &outputBufferDesc, // pOutput
878             &contextAttributes, // pfContextAttr
879             &expiry // ptsTimeStamp
880     );
881 
882     if (status == SEC_E_INCOMPLETE_MESSAGE) {
883         // Need more data
884         missingData = checkIncompleteData(outBuffers[0]);
885         return true;
886     }
887 
888     if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
889         // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
890         // inBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need to
891         // be stored.
892         retainExtraData(intermediateBuffer, inBuffers[1]);
893     } else { /* No 'extra' data, message not incomplete */
894         intermediateBuffer.resize(0);
895     }
896 
897     if (status != SEC_I_CONTINUE_NEEDED) {
898         setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
899                         QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
900         return false;
901     }
902     if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
903         return false;
904     schannelState = SchannelState::PerformHandshake;
905     return true;
906 }
907 
performHandshake()908 bool QSslSocketBackendPrivate::performHandshake()
909 {
910     if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
911         setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
912                         QSslSocket::tr("The TLS/SSL connection has been closed"));
913         return false;
914     }
915     Q_ASSERT(SecIsValidHandle(&credentialHandle));
916     Q_ASSERT(SecIsValidHandle(&contextHandle));
917     Q_ASSERT(schannelState == SchannelState::PerformHandshake);
918 
919 #ifdef QSSLSOCKET_DEBUG
920     qCDebug(lcSsl, "Bytes available from socket: %lld", plainSocket->bytesAvailable());
921     qCDebug(lcSsl, "intermediateBuffer size: %d", intermediateBuffer.size());
922 #endif
923 
924     if (missingData > plainSocket->bytesAvailable())
925         return true;
926 
927     missingData = 0;
928     readToBuffer(intermediateBuffer, plainSocket);
929     if (intermediateBuffer.isEmpty())
930         return true; // no data, will fail
931 
932     SecBuffer outBuffers[3] = {};
933     const auto freeOutBuffers = [&outBuffers]() {
934         for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
935             if (outBuffers[i].pvBuffer)
936                 FreeContextBuffer(outBuffers[i].pvBuffer);
937         }
938     };
939     const auto outBuffersGuard = qScopeGuard(freeOutBuffers);
940     // For this call to InitializeSecurityContext we may need to call it twice.
941     // In some cases us not having a certificate isn't actually an error, but just a request.
942     // With Schannel, to ignore this warning, we need to call InitializeSecurityContext again
943     // when we get SEC_I_INCOMPLETE_CREDENTIALS! As far as I can tell it's not documented anywhere.
944     // https://stackoverflow.com/a/47479968/2493610
945     SECURITY_STATUS status;
946     short attempts = 2;
947     do {
948         SecBuffer inputBuffers[2];
949         inputBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
950         inputBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
951         SecBufferDesc inputBufferDesc{
952             SECBUFFER_VERSION,
953             ARRAYSIZE(inputBuffers),
954             inputBuffers
955         };
956 
957         freeOutBuffers(); // free buffers from any previous attempt
958         outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
959         outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
960         outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
961         SecBufferDesc outputBufferDesc{
962             SECBUFFER_VERSION,
963             ARRAYSIZE(outBuffers),
964             outBuffers
965         };
966 
967         ULONG contextReq = getContextRequirements();
968         TimeStamp expiry;
969         status = InitializeSecurityContext(
970                 &credentialHandle, // phCredential
971                 &contextHandle, // phContext
972                 const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
973                 contextReq, // fContextReq
974                 0, // Reserved1
975                 0, // TargetDataRep (unused)
976                 &inputBufferDesc, // pInput
977                 0, // Reserved2
978                 nullptr, // phNewContext (we already have one)
979                 &outputBufferDesc, // pOutput
980                 &contextAttributes, // pfContextAttr
981                 &expiry // ptsExpiry
982         );
983 
984         if (inputBuffers[1].BufferType == SECBUFFER_EXTRA) {
985             // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
986             // inputBuffers[1].cbBuffer indicates the amount of bytes _NOT_ processed, the rest need
987             // to be stored.
988             retainExtraData(intermediateBuffer, inputBuffers[1]);
989         } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
990             // Clear the buffer if we weren't asked for more data
991             intermediateBuffer.resize(0);
992         }
993 
994         --attempts;
995     } while (status == SEC_I_INCOMPLETE_CREDENTIALS && attempts > 0);
996 
997     switch (status) {
998     case SEC_E_OK:
999         // Need to transmit a final token in the handshake if 'cbBuffer' is non-zero.
1000         if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1001             return false;
1002         schannelState = SchannelState::VerifyHandshake;
1003         return true;
1004     case SEC_I_CONTINUE_NEEDED:
1005         if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1006             return false;
1007         // Must call InitializeSecurityContext again later (done through continueHandshake)
1008         return true;
1009     case SEC_I_INCOMPLETE_CREDENTIALS:
1010         // Schannel takes care of picking certificate to send (other than the one we can specify),
1011         // so if we get here then that means we don't have a certificate the server accepts.
1012         setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
1013                         QSslSocket::tr("Server did not accept any certificate we could present."));
1014         return false;
1015     case SEC_I_CONTEXT_EXPIRED:
1016         // "The message sender has finished using the connection and has initiated a shutdown."
1017         if (outBuffers[0].BufferType == SECBUFFER_TOKEN) {
1018             if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
1019                 return false;
1020         }
1021         if (!shutdown) { // we did not initiate this
1022             setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
1023                             QSslSocket::tr("The TLS/SSL connection has been closed"));
1024         }
1025         return true;
1026     case SEC_E_INCOMPLETE_MESSAGE:
1027         // Simply incomplete, wait for more data
1028         missingData = checkIncompleteData(outBuffers[0]);
1029         return true;
1030     case SEC_E_ALGORITHM_MISMATCH:
1031         setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
1032                         QSslSocket::tr("Algorithm mismatch"));
1033         shutdown = true; // skip sending the "Shutdown" alert
1034         return false;
1035     }
1036 
1037     // Note: We can get here if the connection is using TLS 1.2 and the server certificate uses
1038     // MD5, which is not allowed in Schannel. This causes an "invalid token" error during handshake.
1039     // (If you came here investigating an error: md5 is insecure, update your certificate)
1040     setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
1041                     QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
1042     return false;
1043 }
1044 
verifyHandshake()1045 bool QSslSocketBackendPrivate::verifyHandshake()
1046 {
1047     Q_Q(QSslSocket);
1048     sslErrors.clear();
1049 
1050     const bool isClient = mode == QSslSocket::SslClientMode;
1051 #define CHECK_STATUS(status)                                                  \
1052     if (status != SEC_E_OK) {                                                 \
1053         setErrorAndEmit(QAbstractSocket::SslInternalError,                    \
1054                         QSslSocket::tr("Failed to query the TLS context: %1") \
1055                                 .arg(schannelErrorToString(status)));         \
1056         return false;                                                         \
1057     }
1058 
1059     // Everything is set up, now make sure there's nothing wrong and query some attributes...
1060     if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
1061                                     configuration.peerVerifyMode, isClient)) {
1062         setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
1063                         QSslSocket::tr("Did not get the required attributes for the connection."));
1064         return false;
1065     }
1066 
1067     // Get stream sizes (to know the max size of a message and the size of the header and trailer)
1068     auto status = QueryContextAttributes(&contextHandle,
1069                                          SECPKG_ATTR_STREAM_SIZES,
1070                                          &streamSizes);
1071     CHECK_STATUS(status);
1072 
1073     // Get session cipher info
1074     status = QueryContextAttributes(&contextHandle,
1075                                     SECPKG_ATTR_CONNECTION_INFO,
1076                                     &connectionInfo);
1077     CHECK_STATUS(status);
1078 
1079 #ifdef SUPPORTS_ALPN
1080     if (!configuration.nextAllowedProtocols.isEmpty() && supportsAlpn()) {
1081         SecPkgContext_ApplicationProtocol alpn;
1082         status = QueryContextAttributes(&contextHandle,
1083                                         SECPKG_ATTR_APPLICATION_PROTOCOL,
1084                                         &alpn);
1085         CHECK_STATUS(status);
1086         if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
1087             QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
1088                                                     alpn.ProtocolIdSize);
1089             if (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
1090                 setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
1091                                 QSslSocket::tr("Unwanted protocol was negotiated"));
1092                 return false;
1093             }
1094             configuration.nextNegotiatedProtocol = negotiatedProto;
1095             configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
1096         } else {
1097             configuration.nextNegotiatedProtocol = "";
1098             configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationUnsupported;
1099         }
1100     }
1101 #endif // supports ALPN
1102 
1103 #undef CHECK_STATUS
1104 
1105     // Verify certificate
1106     CERT_CONTEXT *certificateContext = nullptr;
1107     auto freeCertificate = qScopeGuard([&certificateContext]() {
1108         if (certificateContext)
1109             CertFreeCertificateContext(certificateContext);
1110     });
1111     status = QueryContextAttributes(&contextHandle,
1112                                     SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1113                                     &certificateContext);
1114 
1115     // QueryPeer can (currently) not work in Schannel since Schannel itself doesn't have a way to
1116     // ask for a certificate and then still be OK if it's not received.
1117     // To work around this we don't request a certificate at all for QueryPeer.
1118     // For servers AutoVerifyPeer is supposed to be treated the same as QueryPeer.
1119     // This means that servers using Schannel will only request client certificate for "VerifyPeer".
1120     if ((!isClient && configuration.peerVerifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
1121         || (isClient && configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::VerifyNone
1122             && configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::QueryPeer)) {
1123         if (status != SEC_E_OK) {
1124 #ifdef QSSLSOCKET_DEBUG
1125             qCDebug(lcSsl) << "Couldn't retrieve peer certificate, status:"
1126                            << schannelErrorToString(status);
1127 #endif
1128             const QSslError error{ QSslError::NoPeerCertificate };
1129             sslErrors += error;
1130             emit q->peerVerifyError(error);
1131             if (q->state() != QAbstractSocket::ConnectedState)
1132                 return false;
1133         }
1134     }
1135 
1136     // verifyCertContext returns false if the user disconnected while it was checking errors.
1137     if (certificateContext && !verifyCertContext(certificateContext))
1138         return false;
1139 
1140     if (!checkSslErrors() || state != QAbstractSocket::ConnectedState) {
1141 #ifdef QSSLSOCKET_DEBUG
1142         qCDebug(lcSsl) << __func__ << "was unsuccessful. Paused:" << paused;
1143 #endif
1144         // If we're paused then checkSslErrors returned false, but it's not an error
1145         return paused && state == QAbstractSocket::ConnectedState;
1146     }
1147 
1148     schannelState = SchannelState::Done;
1149     return true;
1150 }
1151 
renegotiate()1152 bool QSslSocketBackendPrivate::renegotiate()
1153 {
1154     SecBuffer outBuffers[3];
1155     outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
1156     outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
1157     outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1158     auto freeBuffers = qScopeGuard([&outBuffers]() {
1159         for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1160             if (outBuffers[i].pvBuffer)
1161                 FreeContextBuffer(outBuffers[i].pvBuffer);
1162         }
1163     });
1164     SecBufferDesc outputBufferDesc{
1165         SECBUFFER_VERSION,
1166         ARRAYSIZE(outBuffers),
1167         outBuffers
1168     };
1169 
1170     ULONG contextReq = getContextRequirements();
1171     TimeStamp expiry;
1172     SECURITY_STATUS status;
1173     if (mode == QSslSocket::SslClientMode) {
1174         status = InitializeSecurityContext(&credentialHandle, // phCredential
1175                                            &contextHandle, // phContext
1176                                            const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
1177                                            contextReq, // fContextReq
1178                                            0, // Reserved1
1179                                            0, // TargetDataRep (unused)
1180                                            nullptr, // pInput (nullptr for renegotiate)
1181                                            0, // Reserved2
1182                                            nullptr, // phNewContext (we already have one)
1183                                            &outputBufferDesc, // pOutput
1184                                            &contextAttributes, // pfContextAttr
1185                                            &expiry // ptsExpiry
1186         );
1187     } else {
1188         status = AcceptSecurityContext(
1189                 &credentialHandle, // phCredential
1190                 &contextHandle, // phContext
1191                 nullptr, // pInput
1192                 contextReq, // fContextReq
1193                 0, // TargetDataRep (unused)
1194                 nullptr, // phNewContext
1195                 &outputBufferDesc, // pOutput
1196                 &contextAttributes, // pfContextAttr,
1197                 &expiry // ptsTimeStamp
1198         );
1199     }
1200     if (status == SEC_I_CONTINUE_NEEDED) {
1201         schannelState = SchannelState::PerformHandshake;
1202         return sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);
1203     }
1204     setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
1205                     QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
1206     return false;
1207 }
1208 
1209 /*!
1210     \internal
1211     reset the state in preparation for reuse of socket
1212 */
reset()1213 void QSslSocketBackendPrivate::reset()
1214 {
1215     closeCertificateStores(); // certificate stores could've changed
1216     deallocateContext();
1217     freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
1218 
1219     connectionInfo = {};
1220     streamSizes = {};
1221 
1222     CertFreeCertificateContext(localCertContext);
1223     localCertContext = nullptr;
1224 
1225     contextAttributes = 0;
1226     intermediateBuffer.clear();
1227     schannelState = SchannelState::InitializeHandshake;
1228 
1229     connectionEncrypted = false;
1230     shutdown = false;
1231     renegotiating = false;
1232 
1233     missingData = 0;
1234 }
1235 
startClientEncryption()1236 void QSslSocketBackendPrivate::startClientEncryption()
1237 {
1238     if (connectionEncrypted)
1239         return; // let's not mess up the connection...
1240     reset();
1241     continueHandshake();
1242 }
1243 
startServerEncryption()1244 void QSslSocketBackendPrivate::startServerEncryption()
1245 {
1246     if (connectionEncrypted)
1247         return; // let's not mess up the connection...
1248     reset();
1249     continueHandshake();
1250 }
1251 
transmit()1252 void QSslSocketBackendPrivate::transmit()
1253 {
1254     Q_Q(QSslSocket);
1255 
1256     if (mode == QSslSocket::UnencryptedMode)
1257         return; // This function should not have been called
1258 
1259     // Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
1260     if (plainSocket->state() == QAbstractSocket::SocketState::UnconnectedState)
1261         return;
1262 
1263     if (schannelState != SchannelState::Done) {
1264         continueHandshake();
1265         return;
1266     }
1267 
1268     if (connectionEncrypted) { // encrypt data in writeBuffer and write it to plainSocket
1269         qint64 totalBytesWritten = 0;
1270         qint64 writeBufferSize;
1271         while ((writeBufferSize = writeBuffer.size()) > 0) {
1272             const int headerSize = int(streamSizes.cbHeader);
1273             const int trailerSize = int(streamSizes.cbTrailer);
1274             // Try to read 'cbMaximumMessage' bytes from buffer before encrypting.
1275             const int size = int(std::min(writeBufferSize, qint64(streamSizes.cbMaximumMessage)));
1276             QByteArray fullMessage(headerSize + trailerSize + size, Qt::Uninitialized);
1277             {
1278                 // Use peek() here instead of read() so we don't lose data if encryption fails.
1279                 qint64 copied = writeBuffer.peek(fullMessage.data() + headerSize, size);
1280                 Q_ASSERT(copied == size);
1281             }
1282 
1283             SecBuffer inputBuffers[4]{
1284                 createSecBuffer(fullMessage.data(), headerSize, SECBUFFER_STREAM_HEADER),
1285                 createSecBuffer(fullMessage.data() + headerSize, size, SECBUFFER_DATA),
1286                 createSecBuffer(fullMessage.data() + headerSize + size, trailerSize, SECBUFFER_STREAM_TRAILER),
1287                 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
1288             };
1289             SecBufferDesc message{
1290                 SECBUFFER_VERSION,
1291                 ARRAYSIZE(inputBuffers),
1292                 inputBuffers
1293             };
1294             auto status = EncryptMessage(&contextHandle, 0, &message, 0);
1295             if (status != SEC_E_OK) {
1296                 setErrorAndEmit(QAbstractSocket::SslInternalError,
1297                                 QSslSocket::tr("Schannel failed to encrypt data: %1")
1298                                         .arg(schannelErrorToString(status)));
1299                 return;
1300             }
1301             // Data was encrypted successfully, so we free() what we peek()ed earlier
1302             writeBuffer.free(size);
1303 
1304             // The trailer's size is not final, so resize fullMessage to not send trailing junk
1305             fullMessage.resize(inputBuffers[0].cbBuffer + inputBuffers[1].cbBuffer + inputBuffers[2].cbBuffer);
1306             const qint64 bytesWritten = plainSocket->write(fullMessage);
1307 #ifdef QSSLSOCKET_DEBUG
1308             qCDebug(lcSsl, "Wrote %lld of total %d bytes", bytesWritten, fullMessage.length());
1309 #endif
1310             if (bytesWritten >= 0) {
1311                 totalBytesWritten += bytesWritten;
1312             } else {
1313                 setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
1314                 return;
1315             }
1316         }
1317 
1318         if (totalBytesWritten > 0) {
1319             // Don't emit bytesWritten() recursively.
1320             if (!emittedBytesWritten) {
1321                 emittedBytesWritten = true;
1322                 emit q->bytesWritten(totalBytesWritten);
1323                 emittedBytesWritten = false;
1324             }
1325             emit q->channelBytesWritten(0, totalBytesWritten);
1326         }
1327     }
1328 
1329     if (connectionEncrypted) { // Decrypt data from remote
1330         int totalRead = 0;
1331         bool hadIncompleteData = false;
1332         while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
1333             if (missingData > plainSocket->bytesAvailable()
1334                 && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
1335 #ifdef QSSLSOCKET_DEBUG
1336                 qCDebug(lcSsl, "We're still missing %lld bytes, will check later.", missingData);
1337 #endif
1338                 break;
1339             }
1340 
1341             missingData = 0;
1342             const qint64 bytesRead = readToBuffer(intermediateBuffer, plainSocket);
1343 #ifdef QSSLSOCKET_DEBUG
1344             qCDebug(lcSsl, "Read %lld encrypted bytes from the socket", bytesRead);
1345 #endif
1346             if (intermediateBuffer.length() == 0 || (hadIncompleteData && bytesRead == 0)) {
1347 #ifdef QSSLSOCKET_DEBUG
1348                 qCDebug(lcSsl, (hadIncompleteData ? "No new data received, leaving loop!"
1349                                                     : "Nothing to decrypt, leaving loop!"));
1350 #endif
1351                 break;
1352             }
1353             hadIncompleteData = false;
1354 #ifdef QSSLSOCKET_DEBUG
1355             qCDebug(lcSsl, "Total amount of bytes to decrypt: %d", intermediateBuffer.length());
1356 #endif
1357 
1358             SecBuffer dataBuffer[4]{
1359                 createSecBuffer(intermediateBuffer, SECBUFFER_DATA),
1360                 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
1361                 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY),
1362                 createSecBuffer(nullptr, 0, SECBUFFER_EMPTY)
1363             };
1364             SecBufferDesc message{
1365                 SECBUFFER_VERSION,
1366                 ARRAYSIZE(dataBuffer),
1367                 dataBuffer
1368             };
1369             auto status = DecryptMessage(&contextHandle, &message, 0, nullptr);
1370             if (status == SEC_E_OK || status == SEC_I_RENEGOTIATE || status == SEC_I_CONTEXT_EXPIRED) {
1371                 // There can still be 0 output even if it succeeds, this is fine
1372                 if (dataBuffer[1].cbBuffer > 0) {
1373                     // It is always decrypted in-place.
1374                     // But [0] is the STREAM_HEADER, [1] is the DATA and [2] is the STREAM_TRAILER.
1375                     // The pointers in all of those still point into 'intermediateBuffer'.
1376                     buffer.append(static_cast<char *>(dataBuffer[1].pvBuffer),
1377                                   dataBuffer[1].cbBuffer);
1378                     totalRead += dataBuffer[1].cbBuffer;
1379 #ifdef QSSLSOCKET_DEBUG
1380                     qCDebug(lcSsl, "Decrypted %lu bytes. New read buffer size: %d",
1381                             dataBuffer[1].cbBuffer, buffer.size());
1382 #endif
1383                 }
1384                 if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
1385                     // https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
1386                     // dataBuffer[3].cbBuffer indicates the amount of bytes _NOT_ processed,
1387                     // the rest need to be stored.
1388                     retainExtraData(intermediateBuffer, dataBuffer[3]);
1389                 } else {
1390                     intermediateBuffer.resize(0);
1391                 }
1392             }
1393 
1394             if (status == SEC_E_INCOMPLETE_MESSAGE) {
1395                 missingData = checkIncompleteData(dataBuffer[0]);
1396 #ifdef QSSLSOCKET_DEBUG
1397                 qCDebug(lcSsl, "We didn't have enough data to decrypt anything, will try again!");
1398 #endif
1399                 // We try again, but if we don't get any more data then we leave
1400                 hadIncompleteData = true;
1401             } else if (status == SEC_E_INVALID_HANDLE) {
1402                 // I don't think this should happen, if it does we're done...
1403                 qCWarning(lcSsl, "The internal SSPI handle is invalid!");
1404                 Q_UNREACHABLE();
1405             } else if (status == SEC_E_INVALID_TOKEN) {
1406                 qCWarning(lcSsl, "Got SEC_E_INVALID_TOKEN!");
1407                 Q_UNREACHABLE(); // Happened once due to a bug, but shouldn't generally happen(?)
1408             } else if (status == SEC_E_MESSAGE_ALTERED) {
1409                 // The message has been altered, disconnect now.
1410                 shutdown = true; // skips sending the shutdown alert
1411                 disconnectFromHost();
1412                 setErrorAndEmit(QAbstractSocket::SslInternalError,
1413                                 schannelErrorToString(status));
1414                 break;
1415             } else if (status == SEC_E_OUT_OF_SEQUENCE) {
1416                 // @todo: I don't know if this one is actually "fatal"..
1417                 // This path might never be hit as it seems this is for connection-oriented connections,
1418                 // while SEC_E_MESSAGE_ALTERED is for stream-oriented ones (what we use).
1419                 shutdown = true; // skips sending the shutdown alert
1420                 disconnectFromHost();
1421                 setErrorAndEmit(QAbstractSocket::SslInternalError,
1422                                 schannelErrorToString(status));
1423                 break;
1424             } else if (status == SEC_I_CONTEXT_EXPIRED) {
1425                 // 'remote' has initiated a shutdown
1426                 disconnectFromHost();
1427                 setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
1428                                 schannelErrorToString(status));
1429                 break;
1430             } else if (status == SEC_I_RENEGOTIATE) {
1431                 // 'remote' wants to renegotiate
1432 #ifdef QSSLSOCKET_DEBUG
1433                 qCDebug(lcSsl, "The peer wants to renegotiate.");
1434 #endif
1435                 schannelState = SchannelState::Renegotiate;
1436                 renegotiating = true;
1437 
1438                 // We need to call 'continueHandshake' or else there's no guarantee it ever gets called
1439                 continueHandshake();
1440                 break;
1441             }
1442         }
1443 
1444         if (totalRead) {
1445             if (readyReadEmittedPointer)
1446                 *readyReadEmittedPointer = true;
1447             emit q->readyRead();
1448             emit q->channelReadyRead(0);
1449         }
1450     }
1451 }
1452 
sendShutdown()1453 void QSslSocketBackendPrivate::sendShutdown()
1454 {
1455     const bool isClient = mode == QSslSocket::SslClientMode;
1456     DWORD shutdownToken = SCHANNEL_SHUTDOWN;
1457     SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(SCHANNEL_SHUTDOWN), SECBUFFER_TOKEN);
1458     SecBufferDesc token{
1459         SECBUFFER_VERSION,
1460         1,
1461         &buffer
1462     };
1463     auto status = ApplyControlToken(&contextHandle, &token);
1464 
1465     if (status != SEC_E_OK) {
1466 #ifdef QSSLSOCKET_DEBUG
1467         qCDebug(lcSsl) << "Failed to apply shutdown control token:" << schannelErrorToString(status);
1468 #endif
1469         return;
1470     }
1471 
1472     SecBuffer outBuffers[3];
1473     outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
1474     outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
1475     outBuffers[2] = createSecBuffer(nullptr, 0, SECBUFFER_EMPTY);
1476     auto freeBuffers = qScopeGuard([&outBuffers]() {
1477         for (auto i = 0ull; i < ARRAYSIZE(outBuffers); i++) {
1478             if (outBuffers[i].pvBuffer)
1479                 FreeContextBuffer(outBuffers[i].pvBuffer);
1480         }
1481     });
1482     SecBufferDesc outputBufferDesc{
1483         SECBUFFER_VERSION,
1484         ARRAYSIZE(outBuffers),
1485         outBuffers
1486     };
1487 
1488     ULONG contextReq = getContextRequirements();
1489     TimeStamp expiry;
1490     if (isClient) {
1491         status = InitializeSecurityContext(&credentialHandle, // phCredential
1492                                            &contextHandle, // phContext
1493                                            const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
1494                                            contextReq, // fContextReq
1495                                            0, // Reserved1
1496                                            0, // TargetDataRep (unused)
1497                                            nullptr, // pInput
1498                                            0, // Reserved2
1499                                            nullptr, // phNewContext (we already have one)
1500                                            &outputBufferDesc, // pOutput
1501                                            &contextAttributes, // pfContextAttr
1502                                            &expiry // ptsExpiry
1503         );
1504     } else {
1505         status = AcceptSecurityContext(
1506                 &credentialHandle, // phCredential
1507                 &contextHandle, // phContext
1508                 nullptr, // pInput
1509                 contextReq, // fContextReq
1510                 0, // TargetDataRep (unused)
1511                 nullptr, // phNewContext
1512                 &outputBufferDesc, // pOutput
1513                 &contextAttributes, // pfContextAttr,
1514                 &expiry // ptsTimeStamp
1515         );
1516     }
1517     if (status == SEC_E_OK || status == SEC_I_CONTEXT_EXPIRED) {
1518         if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, false)) {
1519             // We failed to send the shutdown message, but it's not that important since we're
1520             // shutting down anyway.
1521             return;
1522         }
1523     } else {
1524 #ifdef QSSLSOCKET_DEBUG
1525         qCDebug(lcSsl) << "Failed to initialize shutdown:" << schannelErrorToString(status);
1526 #endif
1527     }
1528 }
1529 
disconnectFromHost()1530 void QSslSocketBackendPrivate::disconnectFromHost()
1531 {
1532     if (SecIsValidHandle(&contextHandle)) {
1533         if (!shutdown) {
1534             shutdown = true;
1535             if (plainSocket->state() != QAbstractSocket::UnconnectedState) {
1536                 if (connectionEncrypted) {
1537                     // Read as much as possible because this is likely our last chance
1538                     qint64 tempMax = readBufferMaxSize;
1539                     readBufferMaxSize = 0;
1540                     transmit();
1541                     readBufferMaxSize = tempMax;
1542                     sendShutdown();
1543                 }
1544             }
1545         }
1546     }
1547     if (plainSocket->state() != QAbstractSocket::UnconnectedState)
1548         plainSocket->disconnectFromHost();
1549 }
1550 
disconnected()1551 void QSslSocketBackendPrivate::disconnected()
1552 {
1553     shutdown = true;
1554     connectionEncrypted = false;
1555     deallocateContext();
1556     freeCredentialsHandle();
1557 }
1558 
sessionCipher() const1559 QSslCipher QSslSocketBackendPrivate::sessionCipher() const
1560 {
1561     if (!connectionEncrypted)
1562         return QSslCipher();
1563     return QSslCipher(QStringLiteral("Schannel"), sessionProtocol());
1564 }
1565 
sessionProtocol() const1566 QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
1567 {
1568     if (!connectionEncrypted)
1569         return QSsl::SslProtocol::UnknownProtocol;
1570     return toQtSslProtocol(connectionInfo.dwProtocol);
1571 }
1572 
continueHandshake()1573 void QSslSocketBackendPrivate::continueHandshake()
1574 {
1575     Q_Q(QSslSocket);
1576     const bool isServer = mode == QSslSocket::SslServerMode;
1577     switch (schannelState) {
1578     case SchannelState::InitializeHandshake:
1579         if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
1580             disconnectFromHost();
1581             return;
1582         }
1583         if (!SecIsValidHandle(&credentialHandle)) // Needed to support tst_QSslSocket::setEmptyKey
1584             return;
1585         if (!SecIsValidHandle(&contextHandle) && !(isServer ? acceptContext() : createContext())) {
1586             disconnectFromHost();
1587             return;
1588         }
1589         if (schannelState != SchannelState::PerformHandshake)
1590             break;
1591         Q_FALLTHROUGH();
1592     case SchannelState::PerformHandshake:
1593         if (!performHandshake()) {
1594             disconnectFromHost();
1595             return;
1596         }
1597         if (schannelState != SchannelState::VerifyHandshake)
1598             break;
1599         Q_FALLTHROUGH();
1600     case SchannelState::VerifyHandshake:
1601         // if we're in shutdown or renegotiating then we might not need to verify
1602         // (since we already did)
1603         if (!verifyHandshake()) {
1604             shutdown = true; // Skip sending shutdown alert
1605             q->abort(); // We don't want to send buffered data
1606             disconnectFromHost();
1607             return;
1608         }
1609         if (schannelState != SchannelState::Done)
1610             break;
1611         Q_FALLTHROUGH();
1612     case SchannelState::Done:
1613         // connectionEncrypted is already true if we come here from a renegotiation
1614         if (!connectionEncrypted) {
1615             connectionEncrypted = true; // all is done
1616             emit q->encrypted();
1617         }
1618         renegotiating = false;
1619         if (pendingClose) {
1620             pendingClose = false;
1621             disconnectFromHost();
1622         } else {
1623             transmit();
1624         }
1625         break;
1626     case SchannelState::Renegotiate:
1627         if (!renegotiate()) {
1628             disconnectFromHost();
1629             return;
1630         }
1631         break;
1632     }
1633 }
1634 
defaultCiphers()1635 QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
1636 {
1637     QList<QSslCipher> ciphers;
1638     // @temp (I hope), stolen from qsslsocket_winrt.cpp
1639     const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"),
1640                                         QStringLiteral("TLSv1.2"), QStringLiteral("TLSv1.3") };
1641     const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1,
1642                                             QSsl::TlsV1_2, QSsl::TlsV1_3 };
1643     const int size = ARRAYSIZE(protocols);
1644     Q_STATIC_ASSERT(size == ARRAYSIZE(protocolStrings));
1645     ciphers.reserve(size);
1646     for (int i = 0; i < size; ++i) {
1647         QSslCipher cipher;
1648         cipher.d->isNull = false;
1649         cipher.d->name = QStringLiteral("Schannel");
1650         cipher.d->protocol = protocols[i];
1651         cipher.d->protocolString = protocolStrings[i];
1652         ciphers.append(cipher);
1653     }
1654 
1655     return ciphers;
1656 }
1657 
verify(const QList<QSslCertificate> & certificateChain,const QString & hostName)1658 QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain,
1659                                                   const QString &hostName)
1660 {
1661     Q_UNUSED(certificateChain);
1662     Q_UNUSED(hostName);
1663 
1664     Q_UNIMPLEMENTED();
1665     return {}; // @future implement(?)
1666 }
1667 
importPkcs12(QIODevice * device,QSslKey * key,QSslCertificate * cert,QList<QSslCertificate> * caCertificates,const QByteArray & passPhrase)1668 bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
1669                                             QList<QSslCertificate> *caCertificates,
1670                                             const QByteArray &passPhrase)
1671 {
1672     Q_UNUSED(device);
1673     Q_UNUSED(key);
1674     Q_UNUSED(cert);
1675     Q_UNUSED(caCertificates);
1676     Q_UNUSED(passPhrase);
1677     // @future: can load into its own certificate store (encountered problems extracting key).
1678     Q_UNIMPLEMENTED();
1679     return false;
1680 }
1681 
1682 /*
1683     Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
1684 */
checkSslErrors()1685 bool QSslSocketBackendPrivate::checkSslErrors()
1686 {
1687     if (sslErrors.isEmpty())
1688         return true;
1689     Q_Q(QSslSocket);
1690 
1691     emit q->sslErrors(sslErrors);
1692 
1693     const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
1694             || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
1695                 && mode == QSslSocket::SslClientMode);
1696     const bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
1697     // check whether we need to emit an SSL handshake error
1698     if (doVerifyPeer && doEmitSslError) {
1699         if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
1700             pauseSocketNotifiers(q);
1701             paused = true;
1702         } else {
1703             setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
1704                             sslErrors.constFirst().errorString());
1705             plainSocket->disconnectFromHost();
1706         }
1707         return false;
1708     }
1709 
1710     return true;
1711 }
1712 
initializeCertificateStores()1713 void QSslSocketBackendPrivate::initializeCertificateStores()
1714 {
1715     //// helper function which turns a chain into a certificate store
1716     auto createStoreFromCertificateChain = [](const QList<QSslCertificate> certChain, const QSslKey &privateKey) {
1717         const wchar_t *passphrase = L"";
1718         // Need to embed the private key in the certificate
1719         QByteArray pkcs12 = _q_makePkcs12(certChain,
1720                                           privateKey,
1721                                           QString::fromWCharArray(passphrase, 0));
1722         CRYPT_DATA_BLOB pfxBlob;
1723         pfxBlob.cbData = DWORD(pkcs12.length());
1724         pfxBlob.pbData = reinterpret_cast<unsigned char *>(pkcs12.data());
1725         return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
1726     };
1727 
1728     if (!configuration.localCertificateChain.isEmpty()) {
1729         if (configuration.privateKey.isNull()) {
1730             setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
1731                             QSslSocket::tr("Cannot provide a certificate with no key"));
1732             return;
1733         }
1734         if (localCertificateStore == nullptr) {
1735             localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain,
1736                                                                     configuration.privateKey);
1737             if (localCertificateStore == nullptr)
1738                 qCWarning(lcSsl, "Failed to load certificate chain!");
1739         }
1740     }
1741 
1742     if (!configuration.caCertificates.isEmpty() && !caCertificateStore) {
1743         caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates,
1744                                                              {}); // No private key for the CA certs
1745     }
1746 }
1747 
verifyCertContext(CERT_CONTEXT * certContext)1748 bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
1749 {
1750     Q_ASSERT(certContext);
1751     Q_Q(QSslSocket);
1752 
1753     const bool isClient = mode == QSslSocket::SslClientMode;
1754 
1755     // Create a collection of stores so we can pass in multiple stores as additional locations to
1756     // search for the certificate chain
1757     auto tempCertCollection = QHCertStorePointer(CertOpenStore(CERT_STORE_PROV_COLLECTION,
1758                                                                X509_ASN_ENCODING,
1759                                                                0,
1760                                                                CERT_STORE_CREATE_NEW_FLAG,
1761                                                                nullptr));
1762     if (!tempCertCollection) {
1763 #ifdef QSSLSOCKET_DEBUG
1764         qCWarning(lcSsl, "Failed to create certificate store collection!");
1765 #endif
1766         return false;
1767     }
1768 
1769     if (rootCertOnDemandLoadingAllowed()) {
1770         // @future(maybe): following the OpenSSL backend these certificates should be added into
1771         // the Ca list, not just included during verification.
1772         // That being said, it's not trivial to add the root certificates (if and only if they
1773         // came from the system root store). And I don't see this mentioned in our documentation.
1774         auto rootStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
1775         if (!rootStore) {
1776 #ifdef QSSLSOCKET_DEBUG
1777             qCWarning(lcSsl, "Failed to open the system root CA certificate store!");
1778 #endif
1779             return false;
1780         } else if (!CertAddStoreToCollection(tempCertCollection.get(), rootStore.get(), 0, 1)) {
1781 #ifdef QSSLSOCKET_DEBUG
1782             qCWarning(lcSsl, "Failed to add the system root CA certificate store to the certificate store collection!");
1783 #endif
1784             return false;
1785         }
1786     }
1787     if (caCertificateStore) {
1788         if (!CertAddStoreToCollection(tempCertCollection.get(), caCertificateStore.get(), 0, 1)) {
1789 #ifdef QSSLSOCKET_DEBUG
1790             qCWarning(lcSsl, "Failed to add the user's CA certificate store to the certificate store collection!");
1791 #endif
1792             return false;
1793         }
1794     }
1795 
1796     if (!CertAddStoreToCollection(tempCertCollection.get(), certContext->hCertStore, 0, 0)) {
1797 #ifdef QSSLSOCKET_DEBUG
1798         qCWarning(lcSsl, "Failed to add certificate's origin store to the certificate store collection!");
1799 #endif
1800         return false;
1801     }
1802 
1803     CERT_CHAIN_PARA parameters;
1804     ZeroMemory(&parameters, sizeof(parameters));
1805     parameters.cbSize = sizeof(CERT_CHAIN_PARA);
1806     parameters.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
1807     parameters.RequestedUsage.Usage.cUsageIdentifier = 1;
1808     LPSTR oid = LPSTR(isClient ? szOID_PKIX_KP_SERVER_AUTH
1809                                : szOID_PKIX_KP_CLIENT_AUTH);
1810     parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
1811 
1812     configuration.peerCertificate.clear();
1813     configuration.peerCertificateChain.clear();
1814     const CERT_CHAIN_CONTEXT *chainContext = nullptr;
1815     auto freeCertChain = qScopeGuard([&chainContext]() {
1816         if (chainContext)
1817             CertFreeCertificateChain(chainContext);
1818     });
1819     BOOL status = CertGetCertificateChain(nullptr, // hChainEngine, default
1820                                           certContext, // pCertContext
1821                                           nullptr, // pTime, 'now'
1822                                           tempCertCollection.get(), // hAdditionalStore, additional cert store
1823                                           &parameters, // pChainPara
1824                                           CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, // dwFlags
1825                                           nullptr, // reserved
1826                                           &chainContext // ppChainContext
1827     );
1828     if (status == FALSE || !chainContext || chainContext->cChain == 0) {
1829         QSslError error(QSslError::UnableToVerifyFirstCertificate);
1830         sslErrors += error;
1831         emit q->peerVerifyError(error);
1832         return q->state() == QAbstractSocket::ConnectedState;
1833     }
1834 
1835     // Helper-function to get a QSslCertificate given a CERT_CHAIN_ELEMENT
1836     static auto getCertificateFromChainElement = [](CERT_CHAIN_ELEMENT *element) {
1837         if (!element)
1838             return QSslCertificate();
1839 
1840         const CERT_CONTEXT *certContext = element->pCertContext;
1841         return QSslCertificatePrivate::QSslCertificate_from_CERT_CONTEXT(certContext);
1842     };
1843 
1844     // Pick a chain to use as the certificate chain, if multiple are available:
1845     // According to https://docs.microsoft.com/en-gb/windows/desktop/api/wincrypt/ns-wincrypt-_cert_chain_context
1846     // this seems to be the best way to get a trusted chain.
1847     CERT_SIMPLE_CHAIN *chain = chainContext->rgpChain[chainContext->cChain - 1];
1848 
1849     if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) {
1850         auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate,
1851                                getCertificateFromChainElement(chain->rgpElement[chain->cElement - 1]));
1852         sslErrors += error;
1853         emit q->peerVerifyError(error);
1854         if (q->state() != QAbstractSocket::ConnectedState)
1855             return false;
1856     }
1857     if (chain->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
1858         // @Note: This is actually one of two errors:
1859         // "either the certificate cannot be used to issue other certificates, or the chain path length has been exceeded."
1860         // But here we are checking the chain's status, so we assume the "issuing" error cannot occur here.
1861         auto error = QSslError(QSslError::PathLengthExceeded);
1862         sslErrors += error;
1863         emit q->peerVerifyError(error);
1864         if (q->state() != QAbstractSocket::ConnectedState)
1865             return false;
1866     }
1867     static const DWORD leftoverCertChainErrorMask = CERT_TRUST_IS_CYCLIC | CERT_TRUST_INVALID_EXTENSION
1868             | CERT_TRUST_INVALID_POLICY_CONSTRAINTS | CERT_TRUST_INVALID_NAME_CONSTRAINTS
1869             | CERT_TRUST_CTL_IS_NOT_TIME_VALID | CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID
1870             | CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
1871     if (chain->TrustStatus.dwErrorStatus & leftoverCertChainErrorMask) {
1872         auto error = QSslError(QSslError::SslError::UnspecifiedError);
1873         sslErrors += error;
1874         emit q->peerVerifyError(error);
1875         if (q->state() != QAbstractSocket::ConnectedState)
1876             return false;
1877     }
1878 
1879     DWORD verifyDepth = chain->cElement;
1880     if (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
1881         verifyDepth = DWORD(configuration.peerVerifyDepth);
1882 
1883     for (DWORD i = 0; i < verifyDepth; i++) {
1884         CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
1885         QSslCertificate certificate = getCertificateFromChainElement(element);
1886         const QList<QSslCertificateExtension> extensions = certificate.extensions();
1887 
1888 #ifdef QSSLSOCKET_DEBUG
1889         qCDebug(lcSsl) << "issuer:" << certificate.issuerDisplayName()
1890                        << "\nsubject:" << certificate.subjectDisplayName()
1891                        << "\nQSslCertificate info:" << certificate
1892                        << "\nextended error info:" << element->pwszExtendedErrorInfo
1893                        << "\nerror status:" << element->TrustStatus.dwErrorStatus;
1894 #endif
1895 
1896         configuration.peerCertificateChain.append(certificate);
1897 
1898         if (certificate.isBlacklisted()) {
1899             const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
1900             sslErrors += error;
1901             emit q->peerVerifyError(error);
1902             if (q->state() != QAbstractSocket::ConnectedState)
1903                 return false;
1904         }
1905 
1906         LONG result = CertVerifyTimeValidity(nullptr /*== now */, element->pCertContext->pCertInfo);
1907         if (result != 0) {
1908             auto error = QSslError(result == -1 ? QSslError::CertificateNotYetValid
1909                                                 : QSslError::CertificateExpired,
1910                                    certificate);
1911             sslErrors += error;
1912             emit q->peerVerifyError(error);
1913             if (q->state() != QAbstractSocket::ConnectedState)
1914                 return false;
1915         }
1916 
1917         //// Errors
1918         if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_TIME_VALID) {
1919             // handled right above
1920             Q_ASSERT(!sslErrors.isEmpty());
1921         }
1922         if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_REVOKED) {
1923             auto error = QSslError(QSslError::CertificateRevoked, certificate);
1924             sslErrors += error;
1925             emit q->peerVerifyError(error);
1926             if (q->state() != QAbstractSocket::ConnectedState)
1927                 return false;
1928         }
1929         if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) {
1930             auto error = QSslError(QSslError::CertificateSignatureFailed, certificate);
1931             sslErrors += error;
1932             emit q->peerVerifyError(error);
1933             if (q->state() != QAbstractSocket::ConnectedState)
1934                 return false;
1935         }
1936 
1937         // While netscape shouldn't be relevant now it defined an extension which is
1938         // still in use. Schannel does not check this automatically, so we do it here.
1939         // It is used to differentiate between client and server certificates.
1940         if (netscapeWrongCertType(extensions, isClient))
1941             element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
1942 
1943         if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {
1944             auto error = QSslError(QSslError::InvalidPurpose, certificate);
1945             sslErrors += error;
1946             emit q->peerVerifyError(error);
1947             if (q->state() != QAbstractSocket::ConnectedState)
1948                 return false;
1949         }
1950         if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
1951             // Override this error if we have the certificate inside our trusted CAs list.
1952             const bool isTrustedRoot = configuration.caCertificates.contains(certificate);
1953             if (!isTrustedRoot) {
1954                 auto error = QSslError(QSslError::CertificateUntrusted, certificate);
1955                 sslErrors += error;
1956                 emit q->peerVerifyError(error);
1957                 if (q->state() != QAbstractSocket::ConnectedState)
1958                     return false;
1959             }
1960         }
1961         static const DWORD certRevocationCheckUnavailableError = CERT_TRUST_IS_OFFLINE_REVOCATION
1962                 | CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
1963         if (element->TrustStatus.dwErrorStatus & certRevocationCheckUnavailableError) {
1964             // @future(maybe): Do something with this
1965         }
1966 
1967         // Dumping ground of errors that don't fit our specific errors
1968         static const DWORD leftoverCertErrorMask = CERT_TRUST_IS_CYCLIC
1969                 | CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS
1970                 | CERT_TRUST_INVALID_POLICY_CONSTRAINTS
1971                 | CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT
1972                 | CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT
1973                 | CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT
1974                 | CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT
1975                 | CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
1976         if (element->TrustStatus.dwErrorStatus & leftoverCertErrorMask) {
1977             auto error = QSslError(QSslError::UnspecifiedError, certificate);
1978             sslErrors += error;
1979             emit q->peerVerifyError(error);
1980             if (q->state() != QAbstractSocket::ConnectedState)
1981                 return false;
1982         }
1983         if (element->TrustStatus.dwErrorStatus & CERT_TRUST_INVALID_BASIC_CONSTRAINTS) {
1984             auto it = std::find_if(extensions.cbegin(), extensions.cend(),
1985                                    [](const QSslCertificateExtension &extension) {
1986                                        return extension.name() == QLatin1String("basicConstraints");
1987                                    });
1988             if (it != extensions.cend()) {
1989                 // @Note: This is actually one of two errors:
1990                 // "either the certificate cannot be used to issue other certificates,
1991                 // or the chain path length has been exceeded."
1992                 QVariantMap basicConstraints = it->value().toMap();
1993                 QSslError error;
1994                 if (i > 0 && !basicConstraints.value(QLatin1String("ca"), false).toBool())
1995                     error = QSslError(QSslError::InvalidPurpose, certificate);
1996                 else
1997                     error = QSslError(QSslError::PathLengthExceeded, certificate);
1998                 sslErrors += error;
1999                 emit q->peerVerifyError(error);
2000                 if (q->state() != QAbstractSocket::ConnectedState)
2001                     return false;
2002             }
2003         }
2004         if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_EXPLICIT_DISTRUST) {
2005             auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
2006             sslErrors += error;
2007             emit q->peerVerifyError(error);
2008             if (q->state() != QAbstractSocket::ConnectedState)
2009                 return false;
2010         }
2011 
2012         if (element->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) {
2013             // If it's self-signed *and* a CA then we can assume it's a root CA certificate
2014             // and we can ignore the "self-signed" note:
2015             // We check the basicConstraints certificate extension when possible, but this didn't
2016             // exist for version 1, so we can only guess in that case
2017             const bool isRootCertificateAuthority = isCertificateAuthority(extensions)
2018                     || certificate.version() == "1";
2019 
2020             // Root certificate tends to be signed by themselves, so ignore self-signed status.
2021             if (!isRootCertificateAuthority) {
2022                 auto error = QSslError(QSslError::SelfSignedCertificate, certificate);
2023                 sslErrors += error;
2024                 emit q->peerVerifyError(error);
2025                 if (q->state() != QAbstractSocket::ConnectedState)
2026                     return false;
2027             }
2028         }
2029     }
2030 
2031     if (!configuration.peerCertificateChain.isEmpty())
2032         configuration.peerCertificate = configuration.peerCertificateChain.first();
2033 
2034     // @Note: Somewhat copied from qsslsocket_mac.cpp
2035     const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
2036             || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
2037                 && mode == QSslSocket::SslClientMode);
2038     // Check the peer certificate itself. First try the subject's common name
2039     // (CN) as a wildcard, then try all alternate subject name DNS entries the
2040     // same way.
2041     if (!configuration.peerCertificate.isNull()) {
2042         // but only if we're a client connecting to a server
2043         // if we're the server, don't check CN
2044         if (mode == QSslSocket::SslClientMode) {
2045             const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
2046             if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
2047                 // No matches in common names or alternate names.
2048                 const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
2049                 sslErrors += error;
2050                 emit q->peerVerifyError(error);
2051                 if (q->state() != QAbstractSocket::ConnectedState)
2052                     return false;
2053             }
2054         }
2055     } else if (doVerifyPeer) {
2056         // No peer certificate presented. Report as error if the socket
2057         // expected one.
2058         const QSslError error(QSslError::NoPeerCertificate);
2059         sslErrors += error;
2060         emit q->peerVerifyError(error);
2061         if (q->state() != QAbstractSocket::ConnectedState)
2062             return false;
2063     }
2064 
2065     return true;
2066 }
2067 
rootCertOnDemandLoadingAllowed()2068 bool QSslSocketBackendPrivate::rootCertOnDemandLoadingAllowed()
2069 {
2070     return allowRootCertOnDemandLoading && s_loadRootCertsOnDemand;
2071 }
2072 
2073 QT_END_NAMESPACE
2074