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