summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/ssl/qsslsocket_winrt.cpp582
-rw-r--r--src/network/ssl/qsslsocket_winrt_p.h48
2 files changed, 562 insertions, 68 deletions
diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp
index da4cf91f49..c9ddd9ec1b 100644
--- a/src/network/ssl/qsslsocket_winrt.cpp
+++ b/src/network/ssl/qsslsocket_winrt.cpp
@@ -39,39 +39,132 @@
**
****************************************************************************/
-/****************************************************************************
-**
-** In addition, as a special exception, the copyright holders listed above give
-** permission to link the code of its release of Qt with the OpenSSL project's
-** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
-** same license as the original version), and distribute the linked executables.
-**
-** You must comply with the GNU General Public License version 2 in all
-** respects for all of the code used other than the "OpenSSL" code. If you
-** modify this file, you may extend this exception to your version of the file,
-** but you are not obligated to do so. If you do not wish to do so, delete
-** this exception statement from your version of this file.
-**
-****************************************************************************/
-
-//#define QSSLSOCKET_DEBUG
-//#define QT_DECRYPT_SSL_TRAFFIC
-
#include "qsslsocket_winrt_p.h"
#include "qsslsocket.h"
#include "qsslcertificate_p.h"
+#include "qsslcipher_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QSysInfo>
+#include <QtCore/qfunctions_winrt.h>
+#include <private/qnativesocketengine_winrt_p.h>
+
+#include <windows.networking.h>
+#include <windows.networking.sockets.h>
+#include <windows.security.cryptography.certificates.h>
+#include <robuffer.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Networking;
+using namespace ABI::Windows::Networking::Sockets;
+using namespace ABI::Windows::Security::Cryptography::Certificates;
+using namespace ABI::Windows::Storage::Streams;
QT_BEGIN_NAMESPACE
-bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
+// For QSet<QSslError>
+inline uint qHash(const QSslError &error, uint seed)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(error)))
+{ return (qHash(error.error()) ^ seed); }
+
+// For QSet<QSslCertificate>
+inline uint qHash(const QSslCertificate &certificate, uint seed)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(certificate)))
+{ return (qHash(certificate.handle()) ^ seed); }
+
+bool QSslSocketPrivate::s_libraryLoaded = true;
+bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
+bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
+
+struct SslSocketGlobal
+{
+ SslSocketGlobal()
+ {
+ HRESULT hr;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
+ &hostNameFactory);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<ICertificateStoresStatics> certificateStores;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Certificates_CertificateStores).Get(),
+ &certificateStores);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = certificateStores->get_TrustedRootCertificationAuthorities(&rootStore);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IAsyncOperation<IVectorView<Certificate *> *>> op;
+ hr = certificateStores->FindAllAsync(&op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IVectorView<Certificate *>> certificates;
+ hr = QWinRTFunctions::await(op, certificates.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 size;
+ hr = certificates->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < size; ++i) {
+ ComPtr<ICertificate> certificate;
+ hr = certificates->GetAt(i, &certificate);
+ Q_ASSERT_SUCCEEDED(hr);
+ systemCaCertificates.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get()));
+ }
+ }
+
+ void syncCaCertificates(const QSet<QSslCertificate> &add, const QSet<QSslCertificate> &remove)
+ {
+ QMutexLocker locker(&certificateMutex);
+ foreach (const QSslCertificate &certificate, add) {
+ QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
+ if (it != additionalCertificates.end()) {
+ it.value().ref(); // Add a reference
+ } else {
+ // install certificate
+ HRESULT hr;
+ hr = rootStore->Add(static_cast<ICertificate *>(certificate.handle()));
+ Q_ASSERT_SUCCEEDED(hr);
+ additionalCertificates.insert(certificate, 1);
+ }
+ }
+ foreach (const QSslCertificate &certificate, remove) {
+ QHash<QSslCertificate, QAtomicInt>::iterator it = additionalCertificates.find(certificate);
+ if (it != additionalCertificates.end() && !it.value().deref()) {
+ // no more references, remove certificate
+ HRESULT hr;
+ hr = rootStore->Delete(static_cast<ICertificate *>(certificate.handle()));
+ Q_ASSERT_SUCCEEDED(hr);
+ additionalCertificates.erase(it);
+ }
+ }
+ }
+
+ ComPtr<IHostNameFactory> hostNameFactory;
+ QList<QSslCertificate> systemCaCertificates;
+
+private:
+ QMutex certificateMutex;
+ ComPtr<ICertificateStore> rootStore;
+ QHash<QSslCertificate, QAtomicInt> additionalCertificates;
+};
+Q_GLOBAL_STATIC(SslSocketGlobal, g)
+
+// Called on the socket's thread to avoid cross-thread deletion
+void QSslSocketConnectionHelper::disconnectSocketFromHost()
+{
+ if (d->plainSocket)
+ d->plainSocket->disconnectFromHost();
+}
QSslSocketBackendPrivate::QSslSocketBackendPrivate()
+ : connectionHelper(new QSslSocketConnectionHelper(this))
{
- ensureInitialized();
}
QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
{
+ g->syncCaCertificates(QSet<QSslCertificate>(), previousCaCertificates);
}
void QSslSocketPrivate::deinitialize()
@@ -84,31 +177,28 @@ bool QSslSocketPrivate::supportsSsl()
return true;
}
-bool QSslSocketPrivate::ensureLibraryLoaded()
-{
- return true;
-}
-
-void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
-{
- Q_UNIMPLEMENTED();
-}
-
void QSslSocketPrivate::ensureInitialized()
{
+ if (s_loadedCiphersAndCerts)
+ return;
+ s_loadedCiphersAndCerts = true;
+ resetDefaultCiphers();
}
long QSslSocketPrivate::sslLibraryVersionNumber()
{
- Q_UNIMPLEMENTED();
- return 0;
+ return QSysInfo::windowsVersion();
}
-
QString QSslSocketPrivate::sslLibraryVersionString()
{
- Q_UNIMPLEMENTED();
- return QString::number(sslLibraryVersionNumber());
+ switch (QSysInfo::windowsVersion()) {
+ case QSysInfo::WV_WINDOWS8_1:
+ return QStringLiteral("Windows Runtime 8.1 SSL library");
+ default:
+ break;
+ }
+ return QStringLiteral("Windows Runtime SSL library");
}
long QSslSocketPrivate::sslLibraryBuildVersionNumber()
@@ -125,20 +215,68 @@ QString QSslSocketPrivate::sslLibraryBuildVersionString()
void QSslSocketPrivate::resetDefaultCiphers()
{
- Q_UNIMPLEMENTED();
+ setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
+ setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
+}
+
+
+QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
+{
+ QList<QSslCipher> ciphers;
+ const QString protocolStrings[] = { QStringLiteral("SSLv3"), QStringLiteral("TLSv1"),
+ QStringLiteral("TLSv1.1"), QStringLiteral("TLSv1.2") };
+ const QSsl::SslProtocol protocols[] = { QSsl::SslV3, QSsl::TlsV1_0, QSsl::TlsV1_1, QSsl::TlsV1_2 };
+ for (int i = 0; i < ARRAYSIZE(protocols); ++i) {
+ QSslCipher cipher;
+ cipher.d->isNull = false;
+ cipher.d->name = QStringLiteral("WINRT");
+ cipher.d->protocol = protocols[i];
+ cipher.d->protocolString = protocolStrings[i];
+ ciphers.append(cipher);
+ }
+ return ciphers;
}
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
{
- Q_UNIMPLEMENTED();
- ensureInitialized();
- QList<QSslCertificate> systemCerts;
- return systemCerts;
+ return g->systemCaCertificates;
}
void QSslSocketBackendPrivate::startClientEncryption()
{
- Q_UNIMPLEMENTED();
+ Q_Q(QSslSocket);
+
+ QSsl::SslProtocol protocol = q->protocol();
+ switch (q->protocol()) {
+ case QSsl::AnyProtocol:
+ case QSsl::SslV3:
+ protectionLevel = SocketProtectionLevel_Ssl; // Only use this value if weak cipher support is required
+ break;
+ case QSsl::SecureProtocols:
+ case QSsl::TlsV1SslV3:
+ case QSsl::TlsV1_0:
+ protectionLevel = SocketProtectionLevel_Tls10;
+ break;
+ case QSsl::TlsV1_1:
+ protectionLevel = SocketProtectionLevel_Tls11;
+ break;
+ case QSsl::TlsV1_2:
+ protectionLevel = SocketProtectionLevel_Tls12;
+ break;
+ default:
+ protectionLevel = SocketProtectionLevel_Tls12; // default to highest
+ protocol = QSsl::TlsV1_2;
+ break;
+ }
+
+ // Sync custom certificates
+ const QSet<QSslCertificate> caCertificates = configuration.caCertificates.toSet();
+ const QSet<QSslCertificate> newCertificates = caCertificates - previousCaCertificates;
+ const QSet<QSslCertificate> oldCertificates = previousCaCertificates - caCertificates;
+ g->syncCaCertificates(newCertificates, oldCertificates);
+ previousCaCertificates = caCertificates;
+
+ continueHandshake();
}
void QSslSocketBackendPrivate::startServerEncryption()
@@ -148,33 +286,379 @@ void QSslSocketBackendPrivate::startServerEncryption()
void QSslSocketBackendPrivate::transmit()
{
- Q_UNIMPLEMENTED();
+ Q_Q(QSslSocket);
+
+ if (connectionEncrypted && !writeBuffer.isEmpty()) {
+ qint64 totalBytesWritten = 0;
+ int nextDataBlockSize;
+ while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
+ int writtenBytes = plainSocket->write(writeBuffer.readPointer(), nextDataBlockSize);
+ writtenBytes = nextDataBlockSize;
+
+ writeBuffer.free(writtenBytes);
+ totalBytesWritten += writtenBytes;
+
+ if (writtenBytes < nextDataBlockSize)
+ break;
+ }
+
+ if (totalBytesWritten > 0) {
+ // Don't emit bytesWritten() recursively.
+ if (!emittedBytesWritten) {
+ emittedBytesWritten = true;
+ emit q->bytesWritten(totalBytesWritten);
+ emittedBytesWritten = false;
+ }
+ }
+ }
+
+ // Check if we've got any data to be read from the socket.
+ int pendingBytes;
+ bool bytesRead = false;
+ while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
+ char *ptr = buffer.reserve(pendingBytes);
+ int readBytes = plainSocket->read(ptr, pendingBytes);
+ buffer.chop(pendingBytes - readBytes);
+ bytesRead = true;
+ }
+
+ if (bytesRead) {
+ if (readyReadEmittedPointer)
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ }
+
+ if (pendingClose) {
+ pendingClose = false;
+ q->disconnectFromHost();
+ }
}
void QSslSocketBackendPrivate::disconnectFromHost()
{
- Q_UNIMPLEMENTED();
+ QMetaObject::invokeMethod(connectionHelper.data(), "disconnectSocketFromHost", Qt::QueuedConnection);
}
void QSslSocketBackendPrivate::disconnected()
{
- Q_UNIMPLEMENTED();
}
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
{
- Q_UNIMPLEMENTED();
- return QSslCipher();
+ return configuration.sessionCipher;
}
QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
{
- Q_UNIMPLEMENTED();
- return QSsl::UnknownProtocol;
+ return configuration.sessionCipher.protocol();
}
+
void QSslSocketBackendPrivate::continueHandshake()
{
- Q_UNIMPLEMENTED();
+ Q_Q(QSslSocket);
+
+ IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
+ if (qintptr(socket) == -1) {
+ q->setErrorString(QStringLiteral("At attempt was made to continue the handshake on an invalid socket."));
+ q->setSocketError(QAbstractSocket::SslInternalError);
+ emit q->error(QAbstractSocket::SslInternalError);
+ return;
+ }
+
+ HRESULT hr;
+ ComPtr<IHostName> hostName;
+ const QString host = verificationPeerName.isEmpty() ? plainSocket->peerName()
+ : verificationPeerName;
+ if (host.isEmpty()) {
+ ComPtr<IStreamSocketInformation> info;
+ hr = socket->get_Information(&info);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = info->get_RemoteAddress(&hostName);
+ } else {
+ HStringReference hostRef(reinterpret_cast<LPCWSTR>(host.utf16()), host.length());
+ hr = g->hostNameFactory->CreateHostName(hostRef.Get(), &hostName);
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ if (FAILED(hr)) {
+ q->setErrorString(qt_error_string(hr));
+ q->setSocketError(QAbstractSocket::SslInvalidUserDataError);
+ emit q->error(QAbstractSocket::SslInvalidUserDataError);
+ return;
+ }
+
+ ComPtr<IStreamSocketControl> control;
+ hr = socket->get_Control(&control);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IStreamSocketControl2> control2;
+ hr = control.As(&control2);
+ ComPtr<IVector<ChainValidationResult>> ignoreList;
+ hr = control2->get_IgnorableServerCertificateErrors(&ignoreList);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ QSet<QSslError> ignoreErrors = ignoreErrorsList.toSet();
+ for (int i = ChainValidationResult_Untrusted; i < ChainValidationResult_OtherErrors + 1; ++i) {
+ // Populate the native ignore list - break to add, continue to skip
+ switch (i) {
+ case ChainValidationResult_Revoked:
+ case ChainValidationResult_InvalidSignature:
+ case ChainValidationResult_BasicConstraintsError:
+ case ChainValidationResult_InvalidCertificateAuthorityPolicy:
+ case ChainValidationResult_UnknownCriticalExtension:
+ case ChainValidationResult_OtherErrors:
+ continue; // The above errors can't be ignored in the handshake
+ case ChainValidationResult_Untrusted:
+ if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateUntrusted))
+ break;
+ continue;
+ case ChainValidationResult_Expired:
+ if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::CertificateExpired))
+ break;
+ continue;
+ case ChainValidationResult_IncompleteChain:
+ if (ignoreAllSslErrors
+ || ignoreErrors.contains(QSslError::InvalidCaCertificate)
+ || ignoreErrors.contains(QSslError::UnableToVerifyFirstCertificate)
+ || ignoreErrors.contains(QSslError::UnableToGetIssuerCertificate)) {
+ break;
+ }
+ continue;
+ case ChainValidationResult_WrongUsage:
+ if (ignoreAllSslErrors || ignoreErrors.contains(QSslError::InvalidPurpose))
+ break;
+ continue;
+ case ChainValidationResult_InvalidName:
+ if (ignoreAllSslErrors
+ || ignoreErrors.contains(QSslError::HostNameMismatch)
+ || ignoreErrors.contains(QSslError::SubjectIssuerMismatch)) {
+ break;
+ }
+ continue;
+ case ChainValidationResult_RevocationInformationMissing:
+ case ChainValidationResult_RevocationFailure:
+ default:
+ if (ignoreAllSslErrors)
+ break;
+ continue;
+ }
+ hr = ignoreList->Append(static_cast<ChainValidationResult>(i));
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+
+ ComPtr<IAsyncAction> op;
+ hr = socket->UpgradeToSslAsync(protectionLevel, hostName.Get(), &op);
+ if (FAILED(hr)) {
+ q->setErrorString(QSslSocket::tr("Error creating SSL session: %1")
+ .arg(qt_error_string(hr)));
+ q->setSocketError(QAbstractSocket::SslInternalError);
+ emit q->error(QAbstractSocket::SslInternalError);
+ return;
+ }
+
+ hr = op->put_Completed(Callback<IAsyncActionCompletedHandler>(
+ this, &QSslSocketBackendPrivate::onSslUpgrade).Get());
+ Q_ASSERT_SUCCEEDED(hr);
+}
+
+HRESULT QSslSocketBackendPrivate::onSslUpgrade(IAsyncAction *action, AsyncStatus)
+{
+ Q_Q(QSslSocket);
+
+ if (wasDeleted) {
+ qWarning("SSL upgrade callback received after the delegate was deleted. "
+ "This may be indicative of an internal bug in the WinRT SSL implementation.");
+ return S_OK;
+ }
+
+ HRESULT hr = action->GetResults();
+ QSet<QSslError> errors;
+ switch (hr) {
+ case SEC_E_INVALID_TOKEN: // Occurs when the server doesn't support the requested protocol
+ q->setErrorString(qt_error_string(hr));
+ q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
+ emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ q->disconnectFromHost();
+ return S_OK;
+ default:
+ if (FAILED(hr))
+ qErrnoWarning(hr, "error"); // Unhandled error; let sslErrors take care of it
+ break;
+ }
+
+ IStreamSocket *socket = reinterpret_cast<IStreamSocket *>(plainSocket->socketDescriptor());
+ if (qintptr(socket) == -1) {
+ qWarning("The underlying TCP socket used by the SSL socket is invalid. "
+ "This may be indicative of an internal bug in the WinRT SSL implementation.");
+ return S_OK;
+ }
+
+ ComPtr<IStreamSocketInformation> info;
+ hr = socket->get_Information(&info);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IStreamSocketInformation2> info2;
+ hr = info.As(&info2);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ // Cipher
+ QSsl::SslProtocol protocol;
+ SocketProtectionLevel protectionLevel;
+ hr = info->get_ProtectionLevel(&protectionLevel);
+ switch (protectionLevel) {
+ default:
+ protocol = QSsl::UnknownProtocol;
+ break;
+ case SocketProtectionLevel_Ssl:
+ protocol = QSsl::SslV3;
+ break;
+ case SocketProtectionLevel_Tls10:
+ protocol = QSsl::TlsV1_0;
+ break;
+ case SocketProtectionLevel_Tls11:
+ protocol = QSsl::TlsV1_1;
+ break;
+ case SocketProtectionLevel_Tls12:
+ protocol = QSsl::TlsV1_2;
+ break;
+ }
+ configuration.sessionCipher = QSslCipher(QStringLiteral("WINRT"), protocol); // The actual cipher name is not accessible
+
+ // Certificate & chain
+ ComPtr<ICertificate> certificate;
+ hr = info2->get_ServerCertificate(&certificate);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ QList<QSslCertificate> peerCertificateChain;
+ if (certificate) {
+ ComPtr<IAsyncOperation<CertificateChain *>> op;
+ hr = certificate->BuildChainAsync(Q_NULLPTR, &op);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<ICertificateChain> certificateChain;
+ hr = QWinRTFunctions::await(op, certificateChain.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IVectorView<Certificate *>> certificates;
+ hr = certificateChain->GetCertificates(true, &certificates);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 certificatesLength;
+ hr = certificates->get_Size(&certificatesLength);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < certificatesLength; ++i) {
+ ComPtr<ICertificate> chainCertificate;
+ hr = certificates->GetAt(i, &chainCertificate);
+ Q_ASSERT_SUCCEEDED(hr);
+ peerCertificateChain.append(QSslCertificatePrivate::QSslCertificate_from_Certificate(chainCertificate.Get()));
+ }
+ }
+
+ configuration.peerCertificate = certificate ? QSslCertificatePrivate::QSslCertificate_from_Certificate(certificate.Get())
+ : QSslCertificate();
+ configuration.peerCertificateChain = peerCertificateChain;
+
+ // Errors
+ ComPtr<IVectorView<ChainValidationResult>> chainValidationResults;
+ hr = info2->get_ServerCertificateErrors(&chainValidationResults);
+ Q_ASSERT_SUCCEEDED(hr);
+ quint32 size;
+ hr = chainValidationResults->get_Size(&size);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint32 i = 0; i < size; ++i) {
+ ChainValidationResult result;
+ hr = chainValidationResults->GetAt(i, &result);
+ Q_ASSERT_SUCCEEDED(hr);
+ switch (result) {
+ case ChainValidationResult_Success:
+ break;
+ case ChainValidationResult_Untrusted:
+ errors.insert(QSslError::CertificateUntrusted);
+ break;
+ case ChainValidationResult_Revoked:
+ errors.insert(QSslError::CertificateRevoked);
+ break;
+ case ChainValidationResult_Expired:
+ errors.insert(QSslError::CertificateExpired);
+ break;
+ case ChainValidationResult_IncompleteChain:
+ errors.insert(QSslError::UnableToGetIssuerCertificate);
+ break;
+ case ChainValidationResult_InvalidSignature:
+ errors.insert(QSslError::CertificateSignatureFailed);
+ break;
+ case ChainValidationResult_WrongUsage:
+ errors.insert(QSslError::InvalidPurpose);
+ break;
+ case ChainValidationResult_InvalidName:
+ errors.insert(QSslError::HostNameMismatch);
+ break;
+ case ChainValidationResult_InvalidCertificateAuthorityPolicy:
+ errors.insert(QSslError::InvalidCaCertificate);
+ break;
+ default:
+ errors.insert(QSslError::UnspecifiedError);
+ break;
+ }
+ }
+
+ sslErrors = errors.toList();
+
+ // Peer validation
+ if (!configuration.peerCertificate.isNull()) {
+ const QString peerName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
+ if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
+ // No matches in common names or alternate names.
+ const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
+ const int index = sslErrors.indexOf(QSslError::HostNameMismatch);
+ if (index >= 0) // Replace the existing error
+ sslErrors[index] = error;
+ else
+ sslErrors.append(error);
+ emit q->peerVerifyError(error);
+ }
+
+ // Peer validation required, but no certificate is present
+ } else if (configuration.peerVerifyMode == QSslSocket::VerifyPeer
+ || configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer) {
+ QSslError error(QSslError::NoPeerCertificate);
+ sslErrors.append(error);
+ emit q->peerVerifyError(error);
+ }
+
+ // Peer chain validation
+ foreach (const QSslCertificate &certificate, peerCertificateChain) {
+ if (!QSslCertificatePrivate::isBlacklisted(certificate))
+ continue;
+
+ QSslError error(QSslError::CertificateBlacklisted, certificate);
+ sslErrors.append(error);
+ emit q->peerVerifyError(error);
+ }
+
+ if (!sslErrors.isEmpty()) {
+ emit q->sslErrors(sslErrors);
+ q->setErrorString(sslErrors.first().errorString());
+ q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
+ emit q->error(QAbstractSocket::SslHandshakeFailedError);
+
+ // Disconnect if there are any non-ignorable errors
+ foreach (const QSslError &error, sslErrors) {
+ if (ignoreErrorsList.contains(error))
+ continue;
+ q->disconnectFromHost();
+ return S_OK;
+ }
+ }
+
+ if (readBufferMaxSize)
+ plainSocket->setReadBufferSize(readBufferMaxSize);
+
+ connectionEncrypted = true;
+ emit q->encrypted();
+
+ if (pendingClose) {
+ pendingClose = false;
+ q->disconnectFromHost();
+ }
+
+ return S_OK;
}
QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
diff --git a/src/network/ssl/qsslsocket_winrt_p.h b/src/network/ssl/qsslsocket_winrt_p.h
index 791330a6fd..aa31c85d6e 100644
--- a/src/network/ssl/qsslsocket_winrt_p.h
+++ b/src/network/ssl/qsslsocket_winrt_p.h
@@ -39,30 +39,15 @@
**
****************************************************************************/
-/****************************************************************************
-**
-** In addition, as a special exception, the copyright holders listed above give
-** permission to link the code of its release of Qt with the OpenSSL project's
-** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
-** same license as the original version), and distribute the linked executables.
-**
-** You must comply with the GNU General Public License version 2 in all
-** respects for all of the code used other than the "OpenSSL" code. If you
-** modify this file, you may extend this exception to your version of the file,
-** but you are not obligated to do so. If you do not wish to do so, delete
-** this exception statement from your version of this file.
-**
-****************************************************************************/
-
-#ifndef QSSLSOCKET_OPENSSL_P_H
-#define QSSLSOCKET_OPENSSL_P_H
+#ifndef QSSLSOCKET_WINRT_P_H
+#define QSSLSOCKET_WINRT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
-// of the QLibrary class. This header file may change from
+// of the QtNetwork library. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
@@ -70,8 +55,24 @@
#include "qsslsocket_p.h"
+#include <wrl.h>
+#include <windows.networking.sockets.h>
+
QT_BEGIN_NAMESPACE
+class QSslSocketConnectionHelper : public QObject
+{
+ Q_OBJECT
+public:
+ QSslSocketConnectionHelper(QSslSocketBackendPrivate *d)
+ : d(d) { }
+
+ Q_INVOKABLE void disconnectSocketFromHost();
+
+private:
+ QSslSocketBackendPrivate *d;
+};
+
class QSslSocketBackendPrivate : public QSslSocketPrivate
{
Q_DECLARE_PUBLIC(QSslSocket)
@@ -89,13 +90,22 @@ public:
QSsl::SslProtocol sessionProtocol() const Q_DECL_OVERRIDE;
void continueHandshake() Q_DECL_OVERRIDE;
+ static QList<QSslCipher> defaultCiphers();
static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName);
static bool importPKCS12(QIODevice *device,
QSslKey *key, QSslCertificate *cert,
QList<QSslCertificate> *caCertificates,
const QByteArray &passPhrase);
+
+private:
+ HRESULT onSslUpgrade(ABI::Windows::Foundation::IAsyncAction *,
+ ABI::Windows::Foundation::AsyncStatus);
+
+ QScopedPointer<QSslSocketConnectionHelper> connectionHelper;
+ ABI::Windows::Networking::Sockets::SocketProtectionLevel protectionLevel;
+ QSet<QSslCertificate> previousCaCertificates;
};
QT_END_NAMESPACE
-#endif
+#endif // QSSLSOCKET_WINRT_P_H