1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 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 #include "qssl_p.h"
41 #include "qsslsocket_winrt_p.h"
42 #include "qsslsocket.h"
43 #include "qsslcertificate_p.h"
44 #include "qsslcipher_p.h"
45 
46 #include <QtCore/QCoreApplication>
47 #include <QtCore/QSysInfo>
48 #include <QtCore/qfunctions_winrt.h>
49 #include <private/qnativesocketengine_winrt_p.h>
50 #include <private/qeventdispatcher_winrt_p.h>
51 
52 #include <windows.networking.h>
53 #include <windows.networking.sockets.h>
54 #include <windows.security.cryptography.certificates.h>
55 #include <robuffer.h>
56 
57 using namespace Microsoft::WRL;
58 using namespace Microsoft::WRL::Wrappers;
59 using namespace ABI::Windows::Foundation;
60 using namespace ABI::Windows::Foundation::Collections;
61 using namespace ABI::Windows::Networking;
62 using namespace ABI::Windows::Networking::Sockets;
63 using namespace ABI::Windows::Security::Cryptography::Certificates;
64 using namespace ABI::Windows::Storage::Streams;
65 
66 QT_BEGIN_NAMESPACE
67 
68 bool QSslSocketPrivate::s_libraryLoaded = true;
69 bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
70 bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
71 
72 struct SslSocketGlobal
73 {
SslSocketGlobalSslSocketGlobal74     SslSocketGlobal()
75     {
76         HRESULT hr;
77         hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
78                                   &hostNameFactory);
79         Q_ASSERT_SUCCEEDED(hr);
80 
81         ComPtr<ICertificateStoresStatics> certificateStores;
82         hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Certificates_CertificateStores).Get(),
83                                   &certificateStores);
84         Q_ASSERT_SUCCEEDED(hr);
85 
86         hr = certificateStores->get_TrustedRootCertificationAuthorities(&rootStore);
87         Q_ASSERT_SUCCEEDED(hr);
88 
89         ComPtr<IAsyncOperation<IVectorView<Certificate *> *>> op;
90         hr = certificateStores->FindAllAsync(&op);
91         Q_ASSERT_SUCCEEDED(hr);
92         ComPtr<IVectorView<Certificate *>> certificates;
93         hr = QWinRTFunctions::await(op, certificates.GetAddressOf());
94         Q_ASSERT_SUCCEEDED(hr);
95         quint32 size;
96         hr = certificates->get_Size(&size);
97         Q_ASSERT_SUCCEEDED(hr);
98         for (quint32 i = 0; i < size; ++i) {
99             ComPtr<ICertificate> certificate;
100             hr = certificates->GetAt(i, &certificate);
101             Q_ASSERT_SUCCEEDED(hr);
102             systemCaCertificates.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get()));
103         }
104     }
105 
syncCaCertificatesSslSocketGlobal106     void syncCaCertificates(const QSet<QSslCertificate> &add, const QSet<QSslCertificate> &remove)
107     {
108         QMutexLocker locker(&certificateMutex);
109         for (const QSslCertificate &certificate : add) {
110             QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
111             if (it != additionalCertificates.end()) {
112                 it.value().ref(); // Add a reference
113             } else {
114                 // install certificate
115                 HRESULT hr;
116                 hr = rootStore->Add(static_cast<ICertificate *>(certificate.handle()));
117                 Q_ASSERT_SUCCEEDED(hr);
118                 additionalCertificates.insert(certificate, 1);
119             }
120         }
121         for (const QSslCertificate &certificate : remove) {
122             QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
123             if (it != additionalCertificates.end() && !it.value().deref()) {
124                 // no more references, remove certificate
125                 HRESULT hr;
126                 hr = rootStore->Delete(static_cast<ICertificate *>(certificate.handle()));
127                 Q_ASSERT_SUCCEEDED(hr);
128                 additionalCertificates.erase(it);
129             }
130         }
131     }
132 
133     ComPtr<IHostNameFactory> hostNameFactory;
134     QList<QSslCertificate> systemCaCertificates;
135 
136 private:
137     QMutex certificateMutex;
138     ComPtr<ICertificateStore> rootStore;
139     QHash<QSslCertificate, QAtomicInt> additionalCertificates;
140 };
Q_GLOBAL_STATIC(SslSocketGlobal,g)141 Q_GLOBAL_STATIC(SslSocketGlobal, g)
142 
143 // Called on the socket's thread to avoid cross-thread deletion
144 void QSslSocketConnectionHelper::disconnectSocketFromHost()
145 {
146     if (d->plainSocket)
147         d->plainSocket->disconnectFromHost();
148 }
149 
QSslSocketBackendPrivate()150 QSslSocketBackendPrivate::QSslSocketBackendPrivate()
151     : connectionHelper(new QSslSocketConnectionHelper(this))
152 {
153 }
154 
~QSslSocketBackendPrivate()155 QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
156 {
157     g->syncCaCertificates(QSet<QSslCertificate>(), previousCaCertificates);
158 }
159 
supportsSsl()160 bool QSslSocketPrivate::supportsSsl()
161 {
162     return true;
163 }
164 
ensureInitialized()165 void QSslSocketPrivate::ensureInitialized()
166 {
167     if (s_loadedCiphersAndCerts)
168         return;
169     s_loadedCiphersAndCerts = true;
170     resetDefaultCiphers();
171 }
172 
sslLibraryVersionNumber()173 long QSslSocketPrivate::sslLibraryVersionNumber()
174 {
175     // ### Qt 6: Find a proper replacement for the deprecated method below.
176     return QSysInfo::windowsVersion();
177 }
178 
sslLibraryVersionString()179 QString QSslSocketPrivate::sslLibraryVersionString()
180 {
181     return QStringLiteral("Windows Runtime, ") + QSysInfo::prettyProductName();
182 }
183 
sslLibraryBuildVersionNumber()184 long QSslSocketPrivate::sslLibraryBuildVersionNumber()
185 {
186     Q_UNIMPLEMENTED();
187     return 0;
188 }
189 
sslLibraryBuildVersionString()190 QString QSslSocketPrivate::sslLibraryBuildVersionString()
191 {
192     Q_UNIMPLEMENTED();
193     return QString::number(sslLibraryBuildVersionNumber());
194 }
195 
resetDefaultCiphers()196 void QSslSocketPrivate::resetDefaultCiphers()
197 {
198     setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
199     setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
200 }
201 
202 
defaultCiphers()203 QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
204 {
205     QList<QSslCipher> ciphers;
206     const QString protocolStrings[] = { QStringLiteral("TLSv1"),
207                                         QStringLiteral("TLSv1.1"), QStringLiteral("TLSv1.2") };
208     const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1, QSsl::TlsV1_2 };
209     const int size = static_cast<int>(ARRAYSIZE(protocols));
210     ciphers.reserve(size);
211     for (int i = 0; i < size; ++i) {
212         QSslCipher cipher;
213         cipher.d->isNull = false;
214         cipher.d->name = QStringLiteral("WINRT");
215         cipher.d->protocol = protocols[i];
216         cipher.d->protocolString = protocolStrings[i];
217         ciphers.append(cipher);
218     }
219     return ciphers;
220 }
221 
systemCaCertificates()222 QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
223 {
224     return g->systemCaCertificates;
225 }
226 
startClientEncryption()227 void QSslSocketBackendPrivate::startClientEncryption()
228 {
229     Q_Q(QSslSocket);
230 
231     QSsl::SslProtocol protocol = q->protocol();
232     switch (q->protocol()) {
233     case QSsl::SslV2:
234     case QSsl::SslV3:
235         setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
236                         QStringLiteral("unsupported protocol"));
237         return;
238     case QSsl::AnyProtocol:
239     case QSsl::TlsV1SslV3:
240         protectionLevel = SocketProtectionLevel_Tls10;
241         break;
242     case QSsl::TlsV1_0:
243         protectionLevel = SocketProtectionLevel_Tls10;
244         break;
245     case QSsl::TlsV1_1:
246         protectionLevel = SocketProtectionLevel_Tls11;
247         break;
248     case QSsl::TlsV1_2:
249         protectionLevel = SocketProtectionLevel_Tls12;
250         break;
251     case QSsl::TlsV1_0OrLater:
252     case QSsl::TlsV1_1OrLater:
253     case QSsl::TlsV1_2OrLater:
254     case QSsl::TlsV1_3:
255     case QSsl::TlsV1_3OrLater:
256         // TlsV1_0OrLater, TlsV1_1OrLater and TlsV1_2OrLater are disabled on WinRT
257         // because there is no good way to map them to the native API.
258         setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
259                         QStringLiteral("unsupported protocol"));
260         return;
261     case QSsl::SecureProtocols:
262         // SocketProtectionLevel_Tls12 actually means "use TLS1.0, 1.1 or 1.2"
263         // https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.socketprotectionlevel
264         protectionLevel = SocketProtectionLevel_Tls12;
265         break;
266     default:
267         protectionLevel = SocketProtectionLevel_Tls12; // default to highest
268         protocol = QSsl::TlsV1_2;
269         break;
270     }
271 
272     // Sync custom certificates
273     const QSet<QSslCertificate> caCertificates = configuration.caCertificates.toSet();
274     const QSet<QSslCertificate> newCertificates = caCertificates - previousCaCertificates;
275     const QSet<QSslCertificate> oldCertificates = previousCaCertificates - caCertificates;
276     g->syncCaCertificates(newCertificates, oldCertificates);
277     previousCaCertificates = caCertificates;
278 
279     continueHandshake();
280 }
281 
startServerEncryption()282 void QSslSocketBackendPrivate::startServerEncryption()
283 {
284     Q_UNIMPLEMENTED();
285 }
286 
transmit()287 void QSslSocketBackendPrivate::transmit()
288 {
289     Q_Q(QSslSocket);
290 
291     if (connectionEncrypted && !writeBuffer.isEmpty()) {
292         qint64 totalBytesWritten = 0;
293         int nextDataBlockSize;
294         while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
295             int writtenBytes = plainSocket->write(writeBuffer.readPointer(), nextDataBlockSize);
296             writtenBytes = nextDataBlockSize;
297 
298             writeBuffer.free(writtenBytes);
299             totalBytesWritten += writtenBytes;
300 
301             if (writtenBytes < nextDataBlockSize)
302                 break;
303         }
304 
305         if (totalBytesWritten > 0) {
306             // Don't emit bytesWritten() recursively.
307             if (!emittedBytesWritten) {
308                 emittedBytesWritten = true;
309                 emit q->bytesWritten(totalBytesWritten);
310                 emittedBytesWritten = false;
311             }
312             emit q->channelBytesWritten(0, totalBytesWritten);
313         }
314     }
315 
316     // Check if we've got any data to be read from the socket.
317     int pendingBytes;
318     bool bytesRead = false;
319     while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
320         char *ptr = buffer.reserve(pendingBytes);
321         int readBytes = plainSocket->read(ptr, pendingBytes);
322         buffer.chop(pendingBytes - readBytes);
323         bytesRead = true;
324     }
325 
326     if (bytesRead) {
327         if (readyReadEmittedPointer)
328             *readyReadEmittedPointer = true;
329         emit q->readyRead();
330         emit q->channelReadyRead(0);
331     }
332 
333     if (pendingClose) {
334         pendingClose = false;
335         q->disconnectFromHost();
336     }
337 }
338 
disconnectFromHost()339 void QSslSocketBackendPrivate::disconnectFromHost()
340 {
341     QMetaObject::invokeMethod(connectionHelper.data(), "disconnectSocketFromHost", Qt::QueuedConnection);
342 }
343 
disconnected()344 void QSslSocketBackendPrivate::disconnected()
345 {
346 }
347 
sessionCipher() const348 QSslCipher QSslSocketBackendPrivate::sessionCipher() const
349 {
350     return configuration.sessionCipher;
351 }
352 
sessionProtocol() const353 QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
354 {
355     return configuration.sessionCipher.protocol();
356 }
357 
continueHandshake()358 void QSslSocketBackendPrivate::continueHandshake()
359 {
360     IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
361     if (qintptr(socket) == -1) {
362         setErrorAndEmit(QAbstractSocket::SslInternalError,
363                         QStringLiteral("At attempt was made to continue the handshake on an invalid socket."));
364         return;
365     }
366 
367     HRESULT hr;
368     ComPtr<IHostName> hostName;
369     const QString host = verificationPeerName.isEmpty() ? plainSocket->peerName()
370                                                         : verificationPeerName;
371     if (host.isEmpty()) {
372         ComPtr<IStreamSocketInformation> info;
373         hr = socket->get_Information(&info);
374         Q_ASSERT_SUCCEEDED(hr);
375         hr = info->get_RemoteAddress(&hostName);
376     } else {
377         HStringReference hostRef(reinterpret_cast<LPCWSTR>(host.utf16()), host.length());
378         hr = g->hostNameFactory->CreateHostName(hostRef.Get(), &hostName);
379         Q_ASSERT_SUCCEEDED(hr);
380     }
381     if (FAILED(hr)) {
382         setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, qt_error_string(hr));
383         return;
384     }
385 
386     ComPtr<IStreamSocketControl> control;
387     hr = socket->get_Control(&control);
388     Q_ASSERT_SUCCEEDED(hr);
389 
390     ComPtr<IStreamSocketControl2> control2;
391     hr = control.As(&control2);
392     ComPtr<IVector<ChainValidationResult>> ignoreList;
393     hr = control2->get_IgnorableServerCertificateErrors(&ignoreList);
394     Q_ASSERT_SUCCEEDED(hr);
395 
396     QSet<QSslError> ignoreErrors = ignoreErrorsList.toSet();
397     for (int i = ChainValidationResult_Untrusted; i < ChainValidationResult_OtherErrors + 1; ++i) {
398         // Populate the native ignore list - break to add, continue to skip
399         switch (i) {
400         case ChainValidationResult_Revoked:
401         case ChainValidationResult_InvalidSignature:
402         case ChainValidationResult_BasicConstraintsError:
403         case ChainValidationResult_InvalidCertificateAuthorityPolicy:
404         case ChainValidationResult_UnknownCriticalExtension:
405         case ChainValidationResult_OtherErrors:
406             continue; // The above errors can't be ignored in the handshake
407         case ChainValidationResult_Untrusted:
408             if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateUntrusted))
409                 break;
410             continue;
411         case ChainValidationResult_Expired:
412             if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateExpired))
413                 break;
414             continue;
415         case ChainValidationResult_IncompleteChain:
416             if (ignoreAllSslErrors
417                     || ignoreErrors.contains(QSslError::InvalidCaCertificate)
418                     || ignoreErrors.contains(QSslError::UnableToVerifyFirstCertificate)
419                     || ignoreErrors.contains(QSslError::UnableToGetIssuerCertificate)) {
420                 break;
421             }
422             continue;
423         case ChainValidationResult_WrongUsage:
424             if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::InvalidPurpose))
425                 break;
426             continue;
427         case ChainValidationResult_InvalidName:
428             if (ignoreAllSslErrors
429                     || ignoreErrors.contains(QSslError::HostNameMismatch)
430                     || ignoreErrors.contains(QSslError::SubjectIssuerMismatch)) {
431                 break;
432             }
433             continue;
434         case ChainValidationResult_RevocationInformationMissing:
435         case ChainValidationResult_RevocationFailure:
436         default:
437             if (ignoreAllSslErrors)
438                 break;
439             continue;
440         }
441         hr = ignoreList->Append(static_cast<ChainValidationResult>(i));
442         Q_ASSERT_SUCCEEDED(hr);
443     }
444 
445     ComPtr<IAsyncAction> op;
446     hr = socket->UpgradeToSslAsync(protectionLevel, hostName.Get(), &op);
447     if (FAILED(hr)) {
448         setErrorAndEmit(QAbstractSocket::SslInternalError,
449                         QSslSocket::tr("Error creating SSL session: %1").arg(qt_error_string(hr)));
450         return;
451     }
452 
453     hr = QEventDispatcherWinRT::runOnXamlThread([this, op]() {
454         HRESULT hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(
455             this, &QSslSocketBackendPrivate::onSslUpgrade).Get());
456         return hr;
457     });
458     Q_ASSERT_SUCCEEDED(hr);
459 }
460 
onSslUpgrade(IAsyncAction * action,AsyncStatus)461 HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus)
462 {
463     Q_Q(QSslSocket);
464 
465     if (wasDeleted) {
466         qCWarning(lcSsl,
467                   "SSL upgrade callback received after the delegate was deleted. "
468                   "This may be indicative of an internal bug in the WinRT SSL implementation.");
469         return S_OK;
470     }
471 
472     HRESULT hr = action->GetResults();
473     QSet<QSslError> errors;
474     switch (hr) {
475     case SEC_E_INVALID_TOKEN: // Occurs when the server doesn't support the requested protocol
476         setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, qt_error_string(hr));
477         q->disconnectFromHost();
478         return S_OK;
479     default:
480         if (FAILED(hr))
481             qErrnoWarning(hr, "error"); // Unhandled error; let sslErrors take care of it
482         break;
483     }
484 
485     IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
486     if (qintptr(socket) == -1) {
487         qCWarning(lcSsl,
488                   "The underlying TCP socket used by the SSL socket is invalid. "
489                   "This may be indicative of an internal bug in the WinRT SSL implementation.");
490         return S_OK;
491     }
492 
493     ComPtr<IStreamSocketInformation> info;
494     hr = socket->get_Information(&info);
495     Q_ASSERT_SUCCEEDED(hr);
496     ComPtr<IStreamSocketInformation2> info2;
497     hr = info.As(&info2);
498     Q_ASSERT_SUCCEEDED(hr);
499 
500     // Cipher
501     QSsl::SslProtocol protocol;
502     SocketProtectionLevel protectionLevel;
503     hr = info->get_ProtectionLevel(&protectionLevel);
504     switch (protectionLevel) {
505     default:
506         protocol = QSsl::UnknownProtocol;
507         break;
508     case SocketProtectionLevel_Ssl:
509         protocol = QSsl::SslV3;
510         break;
511     case SocketProtectionLevel_Tls10:
512         protocol = QSsl::TlsV1_0;
513         break;
514     case SocketProtectionLevel_Tls11:
515         protocol = QSsl::TlsV1_1;
516         break;
517     case SocketProtectionLevel_Tls12:
518         protocol = QSsl::TlsV1_2;
519         break;
520     }
521     configuration.sessionCipher = QSslCipher(QStringLiteral("WINRT"), protocol); // The actual cipher name is not accessible
522 
523     // Certificate & chain
524     ComPtr<ICertificate> certificate;
525     hr = info2->get_ServerCertificate(&certificate);
526     Q_ASSERT_SUCCEEDED(hr);
527 
528     QList<QSslCertificate> peerCertificateChain;
529     if (certificate) {
530         ComPtr<IAsyncOperation<CertificateChain *>> op;
531         hr = certificate->BuildChainAsync(nullptr, &op);
532         Q_ASSERT_SUCCEEDED(hr);
533         ComPtr<ICertificateChain> certificateChain;
534         hr = QWinRTFunctions::await(op, certificateChain.GetAddressOf());
535         Q_ASSERT_SUCCEEDED(hr);
536 
537         ComPtr<IVectorView<Certificate *>> certificates;
538         hr = certificateChain->GetCertificates(true, &certificates);
539         Q_ASSERT_SUCCEEDED(hr);
540         quint32 certificatesLength;
541         hr = certificates->get_Size(&certificatesLength);
542         Q_ASSERT_SUCCEEDED(hr);
543         for (quint32 i = 0; i < certificatesLength; ++i) {
544             ComPtr<ICertificate> chainCertificate;
545             hr = certificates->GetAt(i, &chainCertificate);
546             Q_ASSERT_SUCCEEDED(hr);
547             peerCertificateChain.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(chainCertificate.Get()));
548         }
549     }
550 
551     configuration.peerCertificate = certificate ? QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get())
552                                                 : QSslCertificate();
553     configuration.peerCertificateChain = peerCertificateChain;
554 
555     // Errors
556     ComPtr<IVectorView<ChainValidationResult>> chainValidationResults;
557     hr = info2->get_ServerCertificateErrors(&chainValidationResults);
558     Q_ASSERT_SUCCEEDED(hr);
559     quint32 size;
560     hr = chainValidationResults->get_Size(&size);
561     Q_ASSERT_SUCCEEDED(hr);
562     for (quint32 i = 0; i < size; ++i) {
563         ChainValidationResult result;
564         hr = chainValidationResults->GetAt(i, &result);
565         Q_ASSERT_SUCCEEDED(hr);
566         switch (result) {
567         case ChainValidationResult_Success:
568             break;
569         case ChainValidationResult_Untrusted:
570             errors.insert(QSslError::CertificateUntrusted);
571             break;
572         case ChainValidationResult_Revoked:
573             errors.insert(QSslError::CertificateRevoked);
574             break;
575         case ChainValidationResult_Expired:
576             errors.insert(QSslError::CertificateExpired);
577             break;
578         case ChainValidationResult_IncompleteChain:
579             errors.insert(QSslError::UnableToGetIssuerCertificate);
580             break;
581         case ChainValidationResult_InvalidSignature:
582             errors.insert(QSslError::CertificateSignatureFailed);
583             break;
584         case ChainValidationResult_WrongUsage:
585             errors.insert(QSslError::InvalidPurpose);
586             break;
587         case ChainValidationResult_InvalidName:
588             errors.insert(QSslError::HostNameMismatch);
589             break;
590         case ChainValidationResult_InvalidCertificateAuthorityPolicy:
591             errors.insert(QSslError::InvalidCaCertificate);
592             break;
593         default:
594             errors.insert(QSslError::UnspecifiedError);
595             break;
596         }
597     }
598 
599     sslErrors = errors.toList();
600 
601     // Peer validation
602     if (!configuration.peerCertificate.isNull()) {
603         const QString peerName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
604         if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
605             // No matches in common names or alternate names.
606             const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
607             const int index = sslErrors.indexOf(QSslError::HostNameMismatch);
608             if (index >= 0) // Replace the existing error
609                 sslErrors[index] = error;
610             else
611                 sslErrors.append(error);
612             emit q->peerVerifyError(error);
613         }
614 
615     // Peer validation required, but no certificate is present
616     } else if (configuration.peerVerifyMode == QSslSocket::VerifyPeer
617                || configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer) {
618         QSslError error(QSslError::NoPeerCertificate);
619         sslErrors.append(error);
620         emit q->peerVerifyError(error);
621     }
622 
623     // Peer chain validation
624     for (const QSslCertificate &certificate : qAsConst(peerCertificateChain)) {
625         if (!QSslCertificatePrivate::isBlacklisted(certificate))
626             continue;
627 
628         QSslError error(QSslError::CertificateBlacklisted, certificate);
629         sslErrors.append(error);
630         emit q->peerVerifyError(error);
631     }
632 
633     if (!sslErrors.isEmpty()) {
634         emit q->sslErrors(sslErrors);
635         setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
636 
637         // Disconnect if there are any non-ignorable errors
638         for (const QSslError &error : qAsConst(sslErrors)) {
639             if (ignoreErrorsList.contains(error))
640                 continue;
641             q->disconnectFromHost();
642             return S_OK;
643         }
644     }
645 
646     if (readBufferMaxSize)
647         plainSocket->setReadBufferSize(readBufferMaxSize);
648 
649     connectionEncrypted = true;
650     emit q->encrypted();
651 
652     // The write buffer may already have data written to it, so we need to call transmit.
653     // This has to be done in 'q's thread, and not in the current thread (the XAML thread).
654     QMetaObject::invokeMethod(q, [this](){ transmit(); });
655 
656     if (pendingClose) {
657         pendingClose = false;
658         q->disconnectFromHost();
659     }
660 
661     return S_OK;
662 }
663 
verify(const QList<QSslCertificate> & certificateChain,const QString & hostName)664 QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain, const QString &hostName)
665 {
666     Q_UNIMPLEMENTED();
667     Q_UNUSED(certificateChain)
668     Q_UNUSED(hostName)
669     QList<QSslError> errors;
670 
671     return errors;
672 }
673 
importPkcs12(QIODevice * device,QSslKey * key,QSslCertificate * cert,QList<QSslCertificate> * caCertificates,const QByteArray & passPhrase)674 bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
675                          QSslKey *key, QSslCertificate *cert,
676                          QList<QSslCertificate> *caCertificates,
677                          const QByteArray &passPhrase)
678 {
679     Q_UNIMPLEMENTED();
680     Q_UNUSED(device)
681     Q_UNUSED(key)
682     Q_UNUSED(cert)
683     Q_UNUSED(caCertificates)
684     Q_UNUSED(passPhrase)
685     return false;
686 }
687 
688 QT_END_NAMESPACE
689