QSsl: add a new private API
This is an abstraction for TLS backend and its factory, preparing to transition to plugin-based design. Task-number: QTBUG-65922 Change-Id: Ibe810e77fd1b715a6bea66cd3f44312b015ac274 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
946facb1ae
commit
7cf8e5ada9
@ -326,6 +326,7 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
|
|||||||
ssl/qsslkey.h ssl/qsslkey_p.cpp ssl/qsslkey_p.h
|
ssl/qsslkey.h ssl/qsslkey_p.cpp ssl/qsslkey_p.h
|
||||||
ssl/qsslpresharedkeyauthenticator.cpp ssl/qsslpresharedkeyauthenticator.h ssl/qsslpresharedkeyauthenticator_p.h
|
ssl/qsslpresharedkeyauthenticator.cpp ssl/qsslpresharedkeyauthenticator.h ssl/qsslpresharedkeyauthenticator_p.h
|
||||||
ssl/qsslsocket.cpp ssl/qsslsocket.h ssl/qsslsocket_p.h
|
ssl/qsslsocket.cpp ssl/qsslsocket.h ssl/qsslsocket_p.h
|
||||||
|
ssl/qtlsbackend.cpp ssl/qtlsbackend_p.h
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
|
qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
|
||||||
|
@ -385,6 +385,7 @@
|
|||||||
#include "qsslsocket.h"
|
#include "qsslsocket.h"
|
||||||
#include "qsslcipher.h"
|
#include "qsslcipher.h"
|
||||||
#include "qocspresponse.h"
|
#include "qocspresponse.h"
|
||||||
|
#include "qtlsbackend_p.h"
|
||||||
#ifndef QT_NO_OPENSSL
|
#ifndef QT_NO_OPENSSL
|
||||||
#include "qsslsocket_openssl_p.h"
|
#include "qsslsocket_openssl_p.h"
|
||||||
#endif
|
#endif
|
||||||
@ -1556,43 +1557,68 @@ QString QSslSocket::sslLibraryBuildVersionString()
|
|||||||
*/
|
*/
|
||||||
QList<QString> QSslSocket::availableBackends()
|
QList<QString> QSslSocket::availableBackends()
|
||||||
{
|
{
|
||||||
return QSslSocketPrivate::availableBackends();
|
return QTlsBackendFactory::availableBackendNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\since 6.1
|
\since 6.1
|
||||||
Returns the name of the backend that was loaded (implicitly by QSslSocket
|
Returns the name of the backend that QSslSocket and related classes
|
||||||
or by an application via loadBackend() call). If no backend was loaded yet,
|
use. If the active backend was not set explicitly, this function
|
||||||
this function returns the name of the backend that will be loaded by QSslSocket.
|
returns the name of a default backend that QSslSocket selects implicitly
|
||||||
|
from the list of available backends.
|
||||||
|
|
||||||
\note When selecting a default backend implicitly from the list of available
|
\note When selecting a default backend implicitly, QSslSocket prefers
|
||||||
backends, QSslSocket prefers native backends, such as SecureTransport on Darwin,
|
native backends, such as SecureTransport on Darwin, or Schannel on Windows.
|
||||||
or Schannel on Windows.
|
|
||||||
|
|
||||||
\sa loadBackend(), availableBackends()
|
\sa setActiveBackend(), availableBackends()
|
||||||
*/
|
*/
|
||||||
QString QSslSocket::activeBackend()
|
QString QSslSocket::activeBackend()
|
||||||
{
|
{
|
||||||
return QSslSocketPrivate::activeBackend();
|
const QMutexLocker locker(&QSslSocketPrivate::backendMutex);
|
||||||
|
|
||||||
|
if (!QSslSocketPrivate::activeBackendName.size())
|
||||||
|
QSslSocketPrivate::activeBackendName = QTlsBackendFactory::defaultBackendName();
|
||||||
|
|
||||||
|
return QSslSocketPrivate::activeBackendName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\since 6.1
|
\since 6.1
|
||||||
Returns true if a backend with name \a backendName was loaded
|
Returns true if a backend with name \a backendName was set as
|
||||||
and was made the current active backend. \a backendName must
|
active backend. \a backendName must be one of names returned
|
||||||
be one of names returned by availableBackends().
|
by availableBackends().
|
||||||
|
|
||||||
\note An application can switch from the default backend,
|
\note An application cannot mix different backends simultaneously.
|
||||||
that will be implicitly loaded by QSslSocket, to a different backend
|
This implies that a non-default backend must be selected prior
|
||||||
only once. It cannot mix several backends simultaneously. A non-default
|
to any use of QSslSocket or related classes, e.g. QSslCertificate
|
||||||
backend must be selected prior to any use of QSslSocket or related classes
|
or QSslKey.
|
||||||
(like QSslCertificate or QSslKey).
|
|
||||||
|
|
||||||
\sa activeBackend(), availableBackends()
|
\sa activeBackend(), availableBackends()
|
||||||
*/
|
*/
|
||||||
bool QSslSocket::loadBackend(const QString &backendName)
|
bool QSslSocket::setActiveBackend(const QString &backendName)
|
||||||
{
|
{
|
||||||
return QSslSocketPrivate::loadBackend(backendName);
|
if (!backendName.size()) {
|
||||||
|
qCWarning(lcSsl, "Invalid parameter (backend name cannot be an empty string)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutexLocker locker(&QSslSocketPrivate::backendMutex);
|
||||||
|
if (QSslSocketPrivate::tlsBackend.get()) {
|
||||||
|
qCWarning(lcSsl) << "Cannot set backend named" << backendName
|
||||||
|
<< "as active, another backend is already in use";
|
||||||
|
locker.unlock();
|
||||||
|
return activeBackend() == backendName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QTlsBackendFactory::availableBackendNames().contains(backendName)) {
|
||||||
|
qCWarning(lcSsl) << "Cannot set unavailable backend named" << backendName
|
||||||
|
<< "as active";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSslSocketPrivate::activeBackendName = backendName;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1606,13 +1632,7 @@ bool QSslSocket::loadBackend(const QString &backendName)
|
|||||||
*/
|
*/
|
||||||
QList<QSsl::SslProtocol> QSslSocket::supportedProtocols(const QString &backendName)
|
QList<QSsl::SslProtocol> QSslSocket::supportedProtocols(const QString &backendName)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(backendName.size() && !availableBackends().contains(backendName))) {
|
return QTlsBackendFactory::supportedProtocols(backendName.size() ? backendName : activeBackend());
|
||||||
qCWarning(lcSsl) << "Cannot provide the list of supported protocols for the backend"
|
|
||||||
<< backendName;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return QSslSocketPrivate::supportedProtocols(backendName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1638,13 +1658,7 @@ bool QSslSocket::isProtocolSupported(QSsl::SslProtocol protocol, const QString &
|
|||||||
*/
|
*/
|
||||||
QList<QSsl::ImplementedClass> QSslSocket::implementedClasses(const QString &backendName)
|
QList<QSsl::ImplementedClass> QSslSocket::implementedClasses(const QString &backendName)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(backendName.size() && !availableBackends().contains(backendName))) {
|
return QTlsBackendFactory::implementedClasses(backendName.size() ? backendName : activeBackend());
|
||||||
qCWarning(lcSsl) << "Cannot provide information about supported classes for"
|
|
||||||
<< "backend" << backendName;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return QSslSocketPrivate::implementedClasses(backendName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1669,13 +1683,7 @@ bool QSslSocket::isClassImplemented(QSsl::ImplementedClass cl, const QString &ba
|
|||||||
*/
|
*/
|
||||||
QList<QSsl::SupportedFeature> QSslSocket::supportedFeatures(const QString &backendName)
|
QList<QSsl::SupportedFeature> QSslSocket::supportedFeatures(const QString &backendName)
|
||||||
{
|
{
|
||||||
if (Q_UNLIKELY(backendName.size() && !availableBackends().contains(backendName))) {
|
return QTlsBackendFactory::supportedFeatures(backendName.size() ? backendName : activeBackend());
|
||||||
qCWarning(lcSsl) << "Cannot provide information about supported features for"
|
|
||||||
<< "backend" << backendName;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return QSslSocketPrivate::supportedFeatures(backendName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -165,7 +165,7 @@ public:
|
|||||||
|
|
||||||
static QList<QString> availableBackends();
|
static QList<QString> availableBackends();
|
||||||
static QString activeBackend();
|
static QString activeBackend();
|
||||||
static bool loadBackend(const QString &backendName);
|
static bool setActiveBackend(const QString &backendName);
|
||||||
static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName = {});
|
static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName = {});
|
||||||
static bool isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName = {});
|
static bool isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName = {});
|
||||||
static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName = {});
|
static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName = {});
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "qsslsocket_mac_p.h"
|
#include "qsslsocket_mac_p.h"
|
||||||
#include "qasn1element_p.h"
|
#include "qasn1element_p.h"
|
||||||
#include "qsslcertificate_p.h"
|
#include "qsslcertificate_p.h"
|
||||||
|
#include "qtlsbackend_p.h"
|
||||||
#include "qsslcipher_p.h"
|
#include "qsslcipher_p.h"
|
||||||
#include "qsslkey_p.h"
|
#include "qsslkey_p.h"
|
||||||
|
|
||||||
@ -75,6 +76,67 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// These two classes are ad-hoc temporary solution, to be replaced
|
||||||
|
// by the real things soon.
|
||||||
|
class SecureTransportBackend : public QTlsBackend
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return QTlsBackendFactory::builtinBackendNames[QTlsBackendFactory::nameIndexSecureTransport];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SecureTransportBackendFactory : public QTlsBackendFactory
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return QTlsBackendFactory::builtinBackendNames[QTlsBackendFactory::nameIndexSecureTransport];
|
||||||
|
}
|
||||||
|
QTlsBackend *create() const override
|
||||||
|
{
|
||||||
|
return new SecureTransportBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SslProtocol> supportedProtocols() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::SslProtocol> protocols;
|
||||||
|
|
||||||
|
protocols << QSsl::AnyProtocol;
|
||||||
|
protocols << QSsl::SecureProtocols;
|
||||||
|
protocols << QSsl::TlsV1_0;
|
||||||
|
protocols << QSsl::TlsV1_0OrLater;
|
||||||
|
protocols << QSsl::TlsV1_1;
|
||||||
|
protocols << QSsl::TlsV1_1OrLater;
|
||||||
|
protocols << QSsl::TlsV1_2;
|
||||||
|
protocols << QSsl::TlsV1_2OrLater;
|
||||||
|
|
||||||
|
return protocols;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SupportedFeature> supportedFeatures() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::SupportedFeature> features;
|
||||||
|
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::ImplementedClass> implementedClasses() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::ImplementedClass> classes;
|
||||||
|
classes << QSsl::ImplementedClass::Socket;
|
||||||
|
classes << QSsl::ImplementedClass::Certificate;
|
||||||
|
classes << QSsl::ImplementedClass::Key;
|
||||||
|
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC(SecureTransportBackendFactory, factory)
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -1552,90 +1614,12 @@ bool QSslSocketBackendPrivate::startHandshake()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QString> QSslSocketPrivate::availableBackends()
|
void QSslSocketPrivate::registerAdHocFactory()
|
||||||
{
|
{
|
||||||
return {QStringLiteral("securetransport")};
|
// TLSTODO: this is a temporary solution, waiting for
|
||||||
}
|
// backends to move to ... plugins.
|
||||||
|
if (!factory())
|
||||||
QString QSslSocketPrivate::activeBackend()
|
qCWarning(lcSsl, "Failed to create backend factory");
|
||||||
{
|
|
||||||
return availableBackends().first();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSslSocketPrivate::loadBackend(const QString &backendName)
|
|
||||||
{
|
|
||||||
if (backendName.size() && !availableBackends().contains(backendName)) {
|
|
||||||
qCWarning(lcSsl) << "A TLS backend with name" << backendName << "is not available";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool loaded = false;
|
|
||||||
static QBasicMutex mutex;
|
|
||||||
const QMutexLocker locker(&mutex);
|
|
||||||
if (loaded) {
|
|
||||||
qCWarning(lcSsl) << "You have already loaded the backend named:" << activeBackend();
|
|
||||||
if (backendName.size())
|
|
||||||
qCWarning(lcSsl) << "Cannot load:" << backendName;
|
|
||||||
else
|
|
||||||
qCWarning(lcSsl) << "Cannot load the default backend (securetransport)";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// This code to be placed in qsslsocket.cpp and there
|
|
||||||
// the actual plugin to be loaded (so the result can be
|
|
||||||
// false if we, for example, failed to resolve OpenSSL
|
|
||||||
// symbols).
|
|
||||||
return loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::SslProtocol> QSslSocketPrivate::supportedProtocols(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::SslProtocol> protocols;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about protocols supported can be found";
|
|
||||||
return protocols;
|
|
||||||
}
|
|
||||||
|
|
||||||
protocols << QSsl::AnyProtocol;
|
|
||||||
protocols << QSsl::SecureProtocols;
|
|
||||||
protocols << QSsl::TlsV1_0;
|
|
||||||
protocols << QSsl::TlsV1_0OrLater;
|
|
||||||
protocols << QSsl::TlsV1_1;
|
|
||||||
protocols << QSsl::TlsV1_1OrLater;
|
|
||||||
protocols << QSsl::TlsV1_2;
|
|
||||||
protocols << QSsl::TlsV1_2OrLater;
|
|
||||||
|
|
||||||
return protocols;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::ImplementedClass> QSslSocketPrivate::implementedClasses(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::ImplementedClass> classes;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about classes implemented can be found";
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
classes << QSsl::ImplementedClass::Key;
|
|
||||||
classes << QSsl::ImplementedClass::Certificate;
|
|
||||||
classes << QSsl::ImplementedClass::Socket;
|
|
||||||
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::SupportedFeature> QSslSocketPrivate::supportedFeatures(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::SupportedFeature> features;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about classes implemented can be found";
|
|
||||||
return features;
|
|
||||||
}
|
|
||||||
|
|
||||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
|
||||||
|
|
||||||
return features;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -101,6 +101,89 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// These two classes are ad-hoc temporary solution, to be replaced
|
||||||
|
// by the real things soon.
|
||||||
|
class OpenSSLBackend : public QTlsBackend
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return QTlsBackendFactory::builtinBackendNames[QTlsBackendFactory::nameIndexOpenSSL];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenSSLBackendFactory : public QTlsBackendFactory
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return QTlsBackendFactory::builtinBackendNames[QTlsBackendFactory::nameIndexOpenSSL];
|
||||||
|
}
|
||||||
|
QTlsBackend *create() const override
|
||||||
|
{
|
||||||
|
return new OpenSSLBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SslProtocol> supportedProtocols() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::SslProtocol> protocols;
|
||||||
|
|
||||||
|
protocols << QSsl::AnyProtocol;
|
||||||
|
protocols << QSsl::SecureProtocols;
|
||||||
|
protocols << QSsl::TlsV1_0;
|
||||||
|
protocols << QSsl::TlsV1_0OrLater;
|
||||||
|
protocols << QSsl::TlsV1_1;
|
||||||
|
protocols << QSsl::TlsV1_1OrLater;
|
||||||
|
protocols << QSsl::TlsV1_2;
|
||||||
|
protocols << QSsl::TlsV1_2OrLater;
|
||||||
|
|
||||||
|
#ifdef TLS1_3_VERSION
|
||||||
|
protocols << QSsl::TlsV1_3;
|
||||||
|
protocols << QSsl::TlsV1_3OrLater;
|
||||||
|
#endif // TLS1_3_VERSION
|
||||||
|
|
||||||
|
#if QT_CONFIG(dtls)
|
||||||
|
protocols << QSsl::DtlsV1_0;
|
||||||
|
protocols << QSsl::DtlsV1_0OrLater;
|
||||||
|
protocols << QSsl::DtlsV1_2;
|
||||||
|
protocols << QSsl::DtlsV1_2OrLater;
|
||||||
|
#endif // dtls
|
||||||
|
|
||||||
|
return protocols;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SupportedFeature> supportedFeatures() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::SupportedFeature> features;
|
||||||
|
|
||||||
|
features << QSsl::SupportedFeature::CertificateVerification;
|
||||||
|
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||||
|
features << QSsl::SupportedFeature::ServerSideAlpn;
|
||||||
|
features << QSsl::SupportedFeature::Ocsp;
|
||||||
|
features << QSsl::SupportedFeature::Psk;
|
||||||
|
features << QSsl::SupportedFeature::SessionTicket;
|
||||||
|
features << QSsl::SupportedFeature::Alerts;
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::ImplementedClass> implementedClasses() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::ImplementedClass> classes;
|
||||||
|
|
||||||
|
classes << QSsl::ImplementedClass::Key;
|
||||||
|
classes << QSsl::ImplementedClass::Certificate;
|
||||||
|
classes << QSsl::ImplementedClass::Socket;
|
||||||
|
classes << QSsl::ImplementedClass::Dtls;
|
||||||
|
classes << QSsl::ImplementedClass::EllipticCurve;
|
||||||
|
classes << QSsl::ImplementedClass::DiffieHellman;
|
||||||
|
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC(OpenSSLBackendFactory, factory)
|
||||||
|
|
||||||
QSsl::AlertLevel tlsAlertLevel(int value)
|
QSsl::AlertLevel tlsAlertLevel(int value)
|
||||||
{
|
{
|
||||||
using QSsl::AlertLevel;
|
using QSsl::AlertLevel;
|
||||||
@ -2510,111 +2593,12 @@ bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QString> QSslSocketPrivate::availableBackends()
|
void QSslSocketPrivate::registerAdHocFactory()
|
||||||
{
|
{
|
||||||
return {QStringLiteral("openssl")};
|
// TLSTODO: this is a temporary solution, waiting for
|
||||||
}
|
// backends to move to ... plugins.
|
||||||
|
if (!factory())
|
||||||
QString QSslSocketPrivate::activeBackend()
|
qCWarning(lcSsl, "Failed to create backend factory");
|
||||||
{
|
|
||||||
return availableBackends().first();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSslSocketPrivate::loadBackend(const QString &backendName)
|
|
||||||
{
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "A TLS backend with name" << backendName << "is not available";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool loaded = false;
|
|
||||||
static QBasicMutex mutex;
|
|
||||||
const QMutexLocker locker(&mutex);
|
|
||||||
if (loaded) {
|
|
||||||
qCWarning(lcSsl) << "You have already loaded the backend named:" << activeBackend();
|
|
||||||
if (backendName.size())
|
|
||||||
qCWarning(lcSsl) << "Cannot load:" << backendName;
|
|
||||||
else
|
|
||||||
qCWarning(lcSsl) << "Cannot load the default backend (openssl)";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// This code to be placed in qsslsocket.cpp and there
|
|
||||||
// the actual plugin to be loaded (so the result can be
|
|
||||||
// false if we, for example, failed to resolve OpenSSL
|
|
||||||
// symbols).
|
|
||||||
return loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::SslProtocol> QSslSocketPrivate::supportedProtocols(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::SslProtocol> protocols;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about protocols supported can be found";
|
|
||||||
return protocols;
|
|
||||||
}
|
|
||||||
|
|
||||||
protocols << QSsl::AnyProtocol;
|
|
||||||
protocols << QSsl::SecureProtocols;
|
|
||||||
protocols << QSsl::TlsV1_0;
|
|
||||||
protocols << QSsl::TlsV1_0OrLater;
|
|
||||||
protocols << QSsl::TlsV1_1;
|
|
||||||
protocols << QSsl::TlsV1_1OrLater;
|
|
||||||
protocols << QSsl::TlsV1_2;
|
|
||||||
protocols << QSsl::TlsV1_2OrLater;
|
|
||||||
|
|
||||||
#ifdef TLS1_3_VERSION
|
|
||||||
protocols << QSsl::TlsV1_3;
|
|
||||||
protocols << QSsl::TlsV1_3OrLater;
|
|
||||||
#endif // TLS1_3_VERSION
|
|
||||||
|
|
||||||
#if QT_CONFIG(dtls)
|
|
||||||
protocols << QSsl::DtlsV1_0;
|
|
||||||
protocols << QSsl::DtlsV1_0OrLater;
|
|
||||||
protocols << QSsl::DtlsV1_2;
|
|
||||||
protocols << QSsl::DtlsV1_2OrLater;
|
|
||||||
#endif // dtls
|
|
||||||
|
|
||||||
return protocols;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::ImplementedClass> QSslSocketPrivate::implementedClasses(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::ImplementedClass> classes;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about classes implemented can be found";
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
classes << QSsl::ImplementedClass::Key;
|
|
||||||
classes << QSsl::ImplementedClass::Certificate;
|
|
||||||
classes << QSsl::ImplementedClass::Socket;
|
|
||||||
classes << QSsl::ImplementedClass::Dtls;
|
|
||||||
classes << QSsl::ImplementedClass::EllipticCurve;
|
|
||||||
classes << QSsl::ImplementedClass::DiffieHellman;
|
|
||||||
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::SupportedFeature> QSslSocketPrivate::supportedFeatures(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::SupportedFeature> features;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about classes implemented can be found";
|
|
||||||
return features;
|
|
||||||
}
|
|
||||||
|
|
||||||
features << QSsl::SupportedFeature::CertificateVerification;
|
|
||||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
|
||||||
features << QSsl::SupportedFeature::ServerSideAlpn;
|
|
||||||
features << QSsl::SupportedFeature::Ocsp;
|
|
||||||
features << QSsl::SupportedFeature::Psk;
|
|
||||||
features << QSsl::SupportedFeature::SessionTicket;
|
|
||||||
features << QSsl::SupportedFeature::Alerts;
|
|
||||||
|
|
||||||
return features;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#include "qsslkey.h"
|
#include "qsslkey.h"
|
||||||
#include "qsslconfiguration_p.h"
|
#include "qsslconfiguration_p.h"
|
||||||
#include "qocspresponse.h"
|
#include "qocspresponse.h"
|
||||||
|
#include "qtlsbackend_p.h"
|
||||||
#ifndef QT_NO_OPENSSL
|
#ifndef QT_NO_OPENSSL
|
||||||
#include <private/qsslcontext_openssl_p.h>
|
#include <private/qsslcontext_openssl_p.h>
|
||||||
#else
|
#else
|
||||||
@ -67,6 +68,8 @@ class QSslContext;
|
|||||||
|
|
||||||
#include <QtCore/qlist.h>
|
#include <QtCore/qlist.h>
|
||||||
#include <QtCore/qstringlist.h>
|
#include <QtCore/qstringlist.h>
|
||||||
|
#include <QtCore/qmutex.h>
|
||||||
|
|
||||||
#include <private/qringbuffer_p.h>
|
#include <private/qringbuffer_p.h>
|
||||||
|
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
@ -81,6 +84,8 @@ class QSslContext;
|
|||||||
#endif // !HCRYPTPROV_LEGACY
|
#endif // !HCRYPTPROV_LEGACY
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
@ -91,7 +96,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
|
||||||
// Those are needed by both OpenSSL and SChannel back-ends on Windows:
|
// Those are needed by both OpenSSL and Schannel back-ends on Windows:
|
||||||
struct QHCertStoreDeleter {
|
struct QHCertStoreDeleter {
|
||||||
void operator()(HCERTSTORE store)
|
void operator()(HCERTSTORE store)
|
||||||
{
|
{
|
||||||
@ -204,12 +209,9 @@ public:
|
|||||||
|
|
||||||
Q_AUTOTEST_EXPORT static bool rootCertOnDemandLoadingSupported();
|
Q_AUTOTEST_EXPORT static bool rootCertOnDemandLoadingSupported();
|
||||||
|
|
||||||
static QList<QString> availableBackends();
|
|
||||||
static QString activeBackend();
|
|
||||||
static bool loadBackend(const QString &backendName);
|
static bool loadBackend(const QString &backendName);
|
||||||
static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName);
|
static void registerAdHocFactory();
|
||||||
static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName);
|
|
||||||
static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName);
|
|
||||||
private:
|
private:
|
||||||
static bool ensureLibraryLoaded();
|
static bool ensureLibraryLoaded();
|
||||||
static void ensureCiphersAndCertsLoaded();
|
static void ensureCiphersAndCertsLoaded();
|
||||||
@ -228,6 +230,10 @@ protected:
|
|||||||
bool handshakeInterrupted = false;
|
bool handshakeInterrupted = false;
|
||||||
bool fetchAuthorityInformation = false;
|
bool fetchAuthorityInformation = false;
|
||||||
QSslCertificate caToFetch;
|
QSslCertificate caToFetch;
|
||||||
|
|
||||||
|
static inline QMutex backendMutex;
|
||||||
|
static inline QString activeBackendName;
|
||||||
|
static inline std::unique_ptr<QTlsBackend> tlsBackend;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
|
#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
|
||||||
|
@ -157,6 +157,75 @@
|
|||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class SchannelBackend : public QTlsBackend
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return QTlsBackendFactory::builtinBackendNames[QTlsBackendFactory::nameIndexSchannel];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SchannelBackendBackendFactory : public QTlsBackendFactory
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return QTlsBackendFactory::builtinBackendNames[QTlsBackendFactory::nameIndexSchannel];
|
||||||
|
}
|
||||||
|
QTlsBackend *create() const override
|
||||||
|
{
|
||||||
|
return new SchannelBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SslProtocol> supportedProtocols() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::SslProtocol> protocols;
|
||||||
|
|
||||||
|
protocols << QSsl::AnyProtocol;
|
||||||
|
protocols << QSsl::SecureProtocols;
|
||||||
|
protocols << QSsl::TlsV1_0;
|
||||||
|
protocols << QSsl::TlsV1_0OrLater;
|
||||||
|
protocols << QSsl::TlsV1_1;
|
||||||
|
protocols << QSsl::TlsV1_1OrLater;
|
||||||
|
protocols << QSsl::TlsV1_2;
|
||||||
|
protocols << QSsl::TlsV1_2OrLater;
|
||||||
|
|
||||||
|
bool supportsTls13();
|
||||||
|
if (supportsTls13()) {
|
||||||
|
protocols << QSsl::TlsV1_3;
|
||||||
|
protocols << QSsl::TlsV1_3OrLater;
|
||||||
|
}
|
||||||
|
|
||||||
|
return protocols;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SupportedFeature> supportedFeatures() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::SupportedFeature> features;
|
||||||
|
|
||||||
|
features << QSsl::SupportedFeature::ClientSideAlpn;
|
||||||
|
features << QSsl::SupportedFeature::ServerSideAlpn;
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::ImplementedClass> implementedClasses() const override
|
||||||
|
{
|
||||||
|
QList<QSsl::ImplementedClass> classes;
|
||||||
|
|
||||||
|
classes << QSsl::ImplementedClass::Socket;
|
||||||
|
classes << QSsl::ImplementedClass::Certificate;
|
||||||
|
classes << QSsl::ImplementedClass::Key;
|
||||||
|
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC(SchannelBackendFactory, factory)
|
||||||
|
|
||||||
|
|
||||||
SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
|
SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
|
||||||
{
|
{
|
||||||
return SecBuffer{ length, bufferType, ptr };
|
return SecBuffer{ length, bufferType, ptr };
|
||||||
@ -2144,93 +2213,12 @@ bool QSslSocketBackendPrivate::rootCertOnDemandLoadingAllowed()
|
|||||||
return allowRootCertOnDemandLoading && s_loadRootCertsOnDemand;
|
return allowRootCertOnDemandLoading && s_loadRootCertsOnDemand;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QString> QSslSocketPrivate::availableBackends()
|
void QSslSocketPrivate::registerAdHocFactory()
|
||||||
{
|
{
|
||||||
return {QStringLiteral("schannel")};
|
// TLSTODO: this is a temporary solution, waiting for
|
||||||
}
|
// backends to move to ... plugins.
|
||||||
|
if (!factory())
|
||||||
QString QSslSocketPrivate::activeBackend()
|
qCWarning(lcSsl, "Failed to create backend factory");
|
||||||
{
|
|
||||||
return availableBackends().first();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QSslSocketPrivate::loadBackend(const QString &backendName)
|
|
||||||
{
|
|
||||||
if (backendName.size() && !availableBackends().contains(backendName)) {
|
|
||||||
qCWarning(lcSsl) << "A TLS backend with name" << backendName << "is not available";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool loaded = false;
|
|
||||||
static QBasicMutex mutex;
|
|
||||||
const QMutexLocker locker(&mutex);
|
|
||||||
if (loaded) {
|
|
||||||
qCWarning(lcSsl) << "You have already loaded the backend named:" << activeBackend();
|
|
||||||
qCWarning(lcSsl) << "Cannot load:" << backendName;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// This code to be placed in qsslsocket.cpp and there
|
|
||||||
// the actual plugin to be loaded (so the result can be
|
|
||||||
// false if we, for example, failed to resolve OpenSSL
|
|
||||||
// symbols).
|
|
||||||
return loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::SslProtocol> QSslSocketPrivate::supportedProtocols(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::SslProtocol> protocols;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about protocols supported can be found";
|
|
||||||
return protocols;
|
|
||||||
}
|
|
||||||
|
|
||||||
protocols << QSsl::AnyProtocol;
|
|
||||||
protocols << QSsl::SecureProtocols;
|
|
||||||
protocols << QSsl::TlsV1_0;
|
|
||||||
protocols << QSsl::TlsV1_0OrLater;
|
|
||||||
protocols << QSsl::TlsV1_1;
|
|
||||||
protocols << QSsl::TlsV1_1OrLater;
|
|
||||||
protocols << QSsl::TlsV1_2;
|
|
||||||
protocols << QSsl::TlsV1_2OrLater;
|
|
||||||
|
|
||||||
if (supportsTls13()) {
|
|
||||||
protocols << QSsl::TlsV1_3;
|
|
||||||
protocols << QSsl::TlsV1_3OrLater;
|
|
||||||
}
|
|
||||||
|
|
||||||
return protocols;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::ImplementedClass> QSslSocketPrivate::implementedClasses(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::ImplementedClass> classes;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about classes implemented can be found";
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
classes << QSsl::ImplementedClass::Key;
|
|
||||||
classes << QSsl::ImplementedClass::Certificate;
|
|
||||||
classes << QSsl::ImplementedClass::Socket;
|
|
||||||
|
|
||||||
return classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QSsl::SupportedFeature> QSslSocketPrivate::supportedFeatures(const QString &backendName)
|
|
||||||
{
|
|
||||||
QList<QSsl::SupportedFeature> features;
|
|
||||||
if (backendName.size() && backendName != activeBackend()) {
|
|
||||||
qCWarning(lcSsl) << "Unexpected backend name" << backendName
|
|
||||||
<< "no information about classes implemented can be found";
|
|
||||||
return features;
|
|
||||||
}
|
|
||||||
|
|
||||||
features << QSsl::SupportedFeature::ClientSideAlpn;
|
|
||||||
features << QSsl::SupportedFeature::ServerSideAlpn;
|
|
||||||
|
|
||||||
return features;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
299
src/network/ssl/qtlsbackend.cpp
Normal file
299
src/network/ssl/qtlsbackend.cpp
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qtlsbackend_p.h"
|
||||||
|
#include "qsslsocket_p.h"
|
||||||
|
#include "qssl_p.h"
|
||||||
|
|
||||||
|
#include <QtCore/private/qfactoryloader_p.h>
|
||||||
|
|
||||||
|
#include <QtCore/qmutex.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
|
||||||
|
(QTlsBackendFactory_iid, QStringLiteral("/tlsbackends")))
|
||||||
|
|
||||||
|
const QString QTlsBackendFactory::builtinBackendNames[] = {
|
||||||
|
QStringLiteral("schannel"),
|
||||||
|
QStringLiteral("securetransport"),
|
||||||
|
QStringLiteral("openssl")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
QTlsBackend::QTlsBackend() = default;
|
||||||
|
QTlsBackend::~QTlsBackend() = default;
|
||||||
|
|
||||||
|
const QString dummyName = QStringLiteral("dummyTLS");
|
||||||
|
|
||||||
|
QString QTlsBackend::backendName() const
|
||||||
|
{
|
||||||
|
return dummyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::TlsKey *QTlsBackend::createKey() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot generate a key");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::X509Certificate *QTlsBackend::createCertificate() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot create a certificate");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot create TLS session");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot create DTLS session");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::DtlsCookieVerifier *QTlsBackend::createDtlsCookieVerifier() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot create DTLS cookie generator/verifier");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::X509ChainVerifyPtr QTlsBackend::X509Verifier() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot verify X509 chain");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::X509PemReaderPtr QTlsBackend::X509PemReader() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot read PEM format");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::X509DerReaderPtr QTlsBackend::X509DerReader() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, don't know how to read DER");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSsl::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const
|
||||||
|
{
|
||||||
|
qCWarning(lcSsl, "Dummy TLS backend, cannot read PKCS12");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class BackEndFactoryCollection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void addFactory(QTlsBackendFactory *newFactory)
|
||||||
|
{
|
||||||
|
Q_ASSERT(newFactory);
|
||||||
|
Q_ASSERT(std::find(backendFactories.begin(), backendFactories.end(), newFactory) == backendFactories.end());
|
||||||
|
const QMutexLocker locker(&collectionMutex);
|
||||||
|
backendFactories.push_back(newFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFactory(QTlsBackendFactory *factory)
|
||||||
|
{
|
||||||
|
Q_ASSERT(factory);
|
||||||
|
const QMutexLocker locker(&collectionMutex);
|
||||||
|
const auto it = std::find(backendFactories.begin(), backendFactories.end(), factory);
|
||||||
|
Q_ASSERT(it != backendFactories.end());
|
||||||
|
backendFactories.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tryPopulateCollection()
|
||||||
|
{
|
||||||
|
if (!loader())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static QBasicMutex mutex;
|
||||||
|
const QMutexLocker locker(&mutex);
|
||||||
|
if (loaded)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#if QT_CONFIG(library)
|
||||||
|
loader->update();
|
||||||
|
#endif
|
||||||
|
int index = 0;
|
||||||
|
while (loader->instance(index))
|
||||||
|
++index;
|
||||||
|
|
||||||
|
// TLSTODO: obviously, this one should go away:
|
||||||
|
QSslSocketPrivate::registerAdHocFactory();
|
||||||
|
|
||||||
|
return loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> backendNames()
|
||||||
|
{
|
||||||
|
QList<QString> names;
|
||||||
|
if (!tryPopulateCollection())
|
||||||
|
return names;
|
||||||
|
|
||||||
|
const QMutexLocker locker(&collectionMutex);
|
||||||
|
if (!backendFactories.size())
|
||||||
|
return names;
|
||||||
|
|
||||||
|
names.reserve(backendFactories.size());
|
||||||
|
for (const auto *factory : backendFactories)
|
||||||
|
names.append(factory->backendName());
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTlsBackendFactory *factory(const QString &name)
|
||||||
|
{
|
||||||
|
if (!tryPopulateCollection())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const QMutexLocker locker(&collectionMutex);
|
||||||
|
const auto it = std::find_if(backendFactories.begin(), backendFactories.end(),
|
||||||
|
[&name](const auto *fct) {return fct->backendName() == name;});
|
||||||
|
|
||||||
|
return it == backendFactories.end() ? nullptr : *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<QTlsBackendFactory *> backendFactories;
|
||||||
|
QMutex collectionMutex;
|
||||||
|
bool loaded = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC(BackEndFactoryCollection, factories);
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
QTlsBackendFactory::QTlsBackendFactory()
|
||||||
|
{
|
||||||
|
if (factories())
|
||||||
|
factories->addFactory(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTlsBackendFactory::~QTlsBackendFactory()
|
||||||
|
{
|
||||||
|
if (factories())
|
||||||
|
factories->removeFactory(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QTlsBackendFactory::backendName() const
|
||||||
|
{
|
||||||
|
return dummyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> QTlsBackendFactory::availableBackendNames()
|
||||||
|
{
|
||||||
|
if (!factories())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return factories->backendNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString QTlsBackendFactory::defaultBackendName()
|
||||||
|
{
|
||||||
|
// We prefer native as default:
|
||||||
|
const auto names = availableBackendNames();
|
||||||
|
auto name = builtinBackendNames[nameIndexSchannel];
|
||||||
|
if (names.contains(name))
|
||||||
|
return name;
|
||||||
|
name = builtinBackendNames[nameIndexSecureTransport];
|
||||||
|
if (names.contains(name))
|
||||||
|
return name;
|
||||||
|
name = builtinBackendNames[nameIndexOpenSSL];
|
||||||
|
if (names.contains(name))
|
||||||
|
return name;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QTlsBackend *QTlsBackendFactory::create(const QString &backendName)
|
||||||
|
{
|
||||||
|
if (!factories())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (const auto *fct = factories->factory(backendName))
|
||||||
|
return fct->create();
|
||||||
|
|
||||||
|
qCWarning(lcSsl) << "Cannot create unknown backend named" << backendName;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SslProtocol> QTlsBackendFactory::supportedProtocols(const QString &backendName)
|
||||||
|
{
|
||||||
|
if (!factories())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (const auto *fct = factories->factory(backendName))
|
||||||
|
return fct->supportedProtocols();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SupportedFeature> QTlsBackendFactory::supportedFeatures(const QString &backendName)
|
||||||
|
{
|
||||||
|
if (!factories())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (const auto *fct = factories->factory(backendName))
|
||||||
|
return fct->supportedFeatures();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::ImplementedClass> QTlsBackendFactory::implementedClasses(const QString &backendName)
|
||||||
|
{
|
||||||
|
if (!factories())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (const auto *fct = factories->factory(backendName))
|
||||||
|
return fct->implementedClasses();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
177
src/network/ssl/qtlsbackend_p.h
Normal file
177
src/network/ssl/qtlsbackend_p.h
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2021 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTLSBACKEND_P_H
|
||||||
|
#define QTLSBACKEND_P_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G
|
||||||
|
// -------------
|
||||||
|
//
|
||||||
|
// This file is not part of the Qt API. It exists purely as an
|
||||||
|
// implementation detail. This header file may change from version to
|
||||||
|
// version without notice, or even be removed.
|
||||||
|
//
|
||||||
|
// We mean it.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
|
#include <QtNetwork/qsslcertificate.h>
|
||||||
|
#include <QtNetwork/qsslerror.h>
|
||||||
|
#include <QtNetwork/qsslkey.h>
|
||||||
|
#include <QtNetwork/qssl.h>
|
||||||
|
|
||||||
|
#include <QtCore/qobject.h>
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
#include <QtCore/qstring.h>
|
||||||
|
#include <QtCore/qlist.h>
|
||||||
|
#include <QtCore/qmap.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
QT_REQUIRE_CONFIG(ssl);
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QByteArray;
|
||||||
|
class QIODevice;
|
||||||
|
|
||||||
|
namespace QSsl {
|
||||||
|
|
||||||
|
// Encapsulates key's data or backend-specific
|
||||||
|
// data-structure, like RSA/DSA/DH structs in OpenSSL.
|
||||||
|
class TlsKey;
|
||||||
|
|
||||||
|
// Abstraction above OpenSSL's X509, or our generic
|
||||||
|
// 'derData'-based code.
|
||||||
|
class X509Certificate;
|
||||||
|
|
||||||
|
// X509-related auxiliary functions, previously static
|
||||||
|
// member-functions in different classes.
|
||||||
|
using X509ChainVerifyPtr = QList<QSslError> (*)(const QList<QSslCertificate> &chain,
|
||||||
|
const QString &hostName);
|
||||||
|
using X509PemReaderPtr = QList<QSslCertificate> (*)(const QByteArray &pem, int count);
|
||||||
|
using X509DerReaderPtr = X509PemReaderPtr;
|
||||||
|
using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertificate *cert,
|
||||||
|
QList<QSslCertificate> *caCertificates,
|
||||||
|
const QByteArray &passPhrase);
|
||||||
|
|
||||||
|
// TLS over TCP. Handshake, encryption/decryption.
|
||||||
|
class TlsCryptograph;
|
||||||
|
|
||||||
|
// TLS over UDP. Handshake, encryption/decryption.
|
||||||
|
class DtlsCryptograph;
|
||||||
|
|
||||||
|
// DTLS cookie: generation and verification.
|
||||||
|
class DtlsCookieVerifier;
|
||||||
|
|
||||||
|
} // namespace QSsl
|
||||||
|
|
||||||
|
// Factory, creating back-end specific implementations of
|
||||||
|
// different entities QSslSocket is using.
|
||||||
|
// TLSTODO: consider merging with ... it's own factory
|
||||||
|
// below, no real benefit in having this split.
|
||||||
|
class Q_NETWORK_EXPORT QTlsBackend : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QTlsBackend();
|
||||||
|
~QTlsBackend() override;
|
||||||
|
|
||||||
|
virtual QString backendName() const;
|
||||||
|
|
||||||
|
// X509 and keys:
|
||||||
|
virtual QSsl::TlsKey *createKey() const;
|
||||||
|
virtual QSsl::X509Certificate *createCertificate() const;
|
||||||
|
|
||||||
|
// TLS and DTLS:
|
||||||
|
virtual QSsl::TlsCryptograph *createTlsCryptograph() const;
|
||||||
|
virtual QSsl::DtlsCryptograph *createDtlsCryptograph() const;
|
||||||
|
virtual QSsl::DtlsCookieVerifier *createDtlsCookieVerifier() const;
|
||||||
|
|
||||||
|
// X509 machinery:
|
||||||
|
virtual QSsl::X509ChainVerifyPtr X509Verifier() const;
|
||||||
|
virtual QSsl::X509PemReaderPtr X509PemReader() const;
|
||||||
|
virtual QSsl::X509DerReaderPtr X509DerReader() const;
|
||||||
|
virtual QSsl::X509Pkcs12ReaderPtr X509Pkcs12Reader() const;
|
||||||
|
|
||||||
|
Q_DISABLE_COPY_MOVE(QTlsBackend)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Factory for a backend.
|
||||||
|
class Q_NETWORK_EXPORT QTlsBackendFactory : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QTlsBackendFactory();
|
||||||
|
~QTlsBackendFactory() override;
|
||||||
|
|
||||||
|
virtual QString backendName() const = 0;
|
||||||
|
virtual QTlsBackend *create() const = 0;
|
||||||
|
virtual QList<QSsl::SslProtocol> supportedProtocols() const = 0;
|
||||||
|
virtual QList<QSsl::SupportedFeature> supportedFeatures() const = 0;
|
||||||
|
virtual QList<QSsl::ImplementedClass> implementedClasses() const = 0;
|
||||||
|
|
||||||
|
static QList<QString> availableBackendNames();
|
||||||
|
static QString defaultBackendName();
|
||||||
|
static QTlsBackend *create(const QString &backendName);
|
||||||
|
|
||||||
|
static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName);
|
||||||
|
static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName);
|
||||||
|
static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName);
|
||||||
|
|
||||||
|
// Built-in, this is what Qt provides out of the box (depending on OS):
|
||||||
|
static constexpr const int nameIndexSchannel = 0;
|
||||||
|
static constexpr const int nameIndexSecureTransport = 1;
|
||||||
|
static constexpr const int nameIndexOpenSSL = 2;
|
||||||
|
|
||||||
|
static const QString builtinBackendNames[];
|
||||||
|
|
||||||
|
Q_DISABLE_COPY_MOVE(QTlsBackendFactory)
|
||||||
|
};
|
||||||
|
|
||||||
|
#define QTlsBackendFactory_iid "org.qt-project.Qt.QTlsBackendFactory"
|
||||||
|
Q_DECLARE_INTERFACE(QTlsBackendFactory, QTlsBackendFactory_iid);
|
||||||
|
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QTLSBACKEND_P_H
|
@ -56,6 +56,8 @@
|
|||||||
|
|
||||||
#ifndef QT_NO_SSL
|
#ifndef QT_NO_SSL
|
||||||
|
|
||||||
|
#include "private/qtlsbackend_p.h"
|
||||||
|
|
||||||
#ifndef QT_NO_OPENSSL
|
#ifndef QT_NO_OPENSSL
|
||||||
#include "private/qsslsocket_openssl_p.h"
|
#include "private/qsslsocket_openssl_p.h"
|
||||||
#include "private/qsslsocket_openssl_symbols_p.h"
|
#include "private/qsslsocket_openssl_symbols_p.h"
|
||||||
@ -163,6 +165,7 @@ public slots:
|
|||||||
|
|
||||||
#ifndef QT_NO_SSL
|
#ifndef QT_NO_SSL
|
||||||
private slots:
|
private slots:
|
||||||
|
void backends();
|
||||||
void constructing();
|
void constructing();
|
||||||
void configNoOnDemandLoad();
|
void configNoOnDemandLoad();
|
||||||
void simpleConnect();
|
void simpleConnect();
|
||||||
@ -437,9 +440,13 @@ void tst_QSslSocket::initTestCase()
|
|||||||
#endif // QT_NO_SSL
|
#endif // QT_NO_SSL
|
||||||
|
|
||||||
// Since a backend can be loaded only once by an application (this test in our case),
|
// Since a backend can be loaded only once by an application (this test in our case),
|
||||||
// we do backend testing here:
|
// we do backend testing here.
|
||||||
|
|
||||||
|
// Before we tried to load anything, the active is the same thing as the default one:
|
||||||
|
QCOMPARE(QSslSocket::activeBackend(), QTlsBackendFactory::defaultBackendName());
|
||||||
|
|
||||||
const QString nonExistingBackend = QStringLiteral("TheQtTLS");
|
const QString nonExistingBackend = QStringLiteral("TheQtTLS");
|
||||||
QCOMPARE(QSslSocket::loadBackend(nonExistingBackend), false);
|
QCOMPARE(QSslSocket::setActiveBackend(nonExistingBackend), false);
|
||||||
QCOMPARE(QSslSocket::supportedProtocols(nonExistingBackend).size(), 0);
|
QCOMPARE(QSslSocket::supportedProtocols(nonExistingBackend).size(), 0);
|
||||||
QCOMPARE(QSslSocket::supportedFeatures(nonExistingBackend), QList<QSsl::SupportedFeature>());
|
QCOMPARE(QSslSocket::supportedFeatures(nonExistingBackend), QList<QSsl::SupportedFeature>());
|
||||||
QCOMPARE(QSslSocket::implementedClasses(nonExistingBackend), QList<QSsl::ImplementedClass>());
|
QCOMPARE(QSslSocket::implementedClasses(nonExistingBackend), QList<QSsl::ImplementedClass>());
|
||||||
@ -450,9 +457,9 @@ void tst_QSslSocket::initTestCase()
|
|||||||
const auto supportedFt = QSsl::SupportedFeature::ClientSideAlpn;
|
const auto supportedFt = QSsl::SupportedFeature::ClientSideAlpn;
|
||||||
|
|
||||||
QVERIFY(QSslSocket::availableBackends().contains(backendName));
|
QVERIFY(QSslSocket::availableBackends().contains(backendName));
|
||||||
QCOMPARE(QSslSocket::loadBackend(backendName), true);
|
QCOMPARE(QSslSocket::setActiveBackend(backendName), true);
|
||||||
QCOMPARE(QSslSocket::activeBackend(), backendName);
|
QCOMPARE(QSslSocket::activeBackend(), backendName);
|
||||||
QCOMPARE(QSslSocket::loadBackend(backendName), true); // Already loaded, but not a fail.
|
QCOMPARE(QSslSocket::setActiveBackend(backendName), true); // We can do it again.
|
||||||
QCOMPARE(QSslSocket::activeBackend(), backendName);
|
QCOMPARE(QSslSocket::activeBackend(), backendName);
|
||||||
|
|
||||||
const auto protocols = QSslSocket::supportedProtocols();
|
const auto protocols = QSslSocket::supportedProtocols();
|
||||||
@ -557,6 +564,131 @@ void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthent
|
|||||||
|
|
||||||
#ifndef QT_NO_SSL
|
#ifndef QT_NO_SSL
|
||||||
|
|
||||||
|
struct MockTlsBackend : QTlsBackend
|
||||||
|
{
|
||||||
|
MockTlsBackend(const QString &n) : name(n) {}
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MockTlsFactory : QTlsBackendFactory
|
||||||
|
{
|
||||||
|
MockTlsFactory(const QString &mockName) : name(mockName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
QString backendName() const override
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QSsl::SupportedFeature> supportedFeatures() const override
|
||||||
|
{
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
QList<QSsl::SslProtocol> supportedProtocols() const override
|
||||||
|
{
|
||||||
|
return protocols;
|
||||||
|
}
|
||||||
|
QList<QSsl::ImplementedClass> implementedClasses() const override
|
||||||
|
{
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
QTlsBackend *create() const override
|
||||||
|
{
|
||||||
|
auto tls = new MockTlsBackend(name);
|
||||||
|
return tls;
|
||||||
|
}
|
||||||
|
QString name;
|
||||||
|
QList<QSsl::ImplementedClass> classes;
|
||||||
|
QList<QSsl::SupportedFeature> features;
|
||||||
|
QList<QSsl::SslProtocol> protocols;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QSslSocket::backends()
|
||||||
|
{
|
||||||
|
QFETCH_GLOBAL(const bool, setProxy);
|
||||||
|
if (setProxy)
|
||||||
|
QSKIP("Proxy is not interesting for backend test");
|
||||||
|
|
||||||
|
// We are here, protected by !QT_NO_SSL. Some backend must be pre-existing.
|
||||||
|
// Let's test the 'real' backend:
|
||||||
|
auto backendNames = QTlsBackendFactory::availableBackendNames();
|
||||||
|
const auto sizeBefore = backendNames.size();
|
||||||
|
QVERIFY(sizeBefore > 0);
|
||||||
|
|
||||||
|
const auto builtinBackend = backendNames.first();
|
||||||
|
const auto builtinProtocols = QSslSocket::supportedProtocols(builtinBackend);
|
||||||
|
QVERIFY(builtinProtocols.contains(QSsl::SecureProtocols));
|
||||||
|
// Socket and ALPN are supported by all our backends:
|
||||||
|
const auto builtinClasses = QSslSocket::implementedClasses(builtinBackend);
|
||||||
|
QVERIFY(builtinClasses.contains(QSsl::ImplementedClass::Socket));
|
||||||
|
const auto builtinFeatures = QSslSocket::supportedFeatures(builtinBackend);
|
||||||
|
QVERIFY(builtinFeatures.contains(QSsl::SupportedFeature::ClientSideAlpn));
|
||||||
|
|
||||||
|
{
|
||||||
|
// Verify that non-dummy backend can be created (and delete it):
|
||||||
|
const std::unique_ptr<QTlsBackend> systemBackend(QTlsBackendFactory::create(backendNames.first()));
|
||||||
|
QVERIFY(systemBackend.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto protocols = QList<QSsl::SslProtocol>{QSsl::SecureProtocols};
|
||||||
|
const auto classes = QList<QSsl::ImplementedClass>{QSsl::ImplementedClass::Socket};
|
||||||
|
const auto features = QList<QSsl::SupportedFeature>{QSsl::SupportedFeature::CertificateVerification};
|
||||||
|
|
||||||
|
const QString nameA = QStringLiteral("backend A");
|
||||||
|
const QString nameB = QStringLiteral("backend B");
|
||||||
|
const QString nonExisting = QStringLiteral("non-existing backend");
|
||||||
|
|
||||||
|
QVERIFY(!backendNames.contains(nameA));
|
||||||
|
QVERIFY(!backendNames.contains(nameB));
|
||||||
|
QVERIFY(!backendNames.contains(nonExisting));
|
||||||
|
{
|
||||||
|
MockTlsFactory factoryA(nameA);
|
||||||
|
backendNames = QTlsBackendFactory::availableBackendNames();
|
||||||
|
QVERIFY(backendNames.contains(nameA));
|
||||||
|
QVERIFY(!backendNames.contains(nameB));
|
||||||
|
QVERIFY(!backendNames.contains(nonExisting));
|
||||||
|
|
||||||
|
QCOMPARE(factoryA.supportedFeatures().size(), 0);
|
||||||
|
QCOMPARE(factoryA.supportedProtocols().size(), 0);
|
||||||
|
QCOMPARE(factoryA.implementedClasses().size(), 0);
|
||||||
|
|
||||||
|
factoryA.protocols = protocols;
|
||||||
|
factoryA.classes = classes;
|
||||||
|
factoryA.features = features;
|
||||||
|
|
||||||
|
// It's an overrider in some re-implemented factory:
|
||||||
|
QCOMPARE(factoryA.supportedProtocols(), protocols);
|
||||||
|
QCOMPARE(factoryA.supportedFeatures(), features);
|
||||||
|
QCOMPARE(factoryA.implementedClasses(), classes);
|
||||||
|
|
||||||
|
// That's a helper function (static member function):
|
||||||
|
QCOMPARE(QTlsBackendFactory::supportedProtocols(nameA), protocols);
|
||||||
|
QCOMPARE(QTlsBackendFactory::supportedFeatures(nameA), features);
|
||||||
|
QCOMPARE(QTlsBackendFactory::implementedClasses(nameA), classes);
|
||||||
|
|
||||||
|
MockTlsFactory factoryB(nameB);
|
||||||
|
QVERIFY(QTlsBackendFactory::availableBackendNames().contains(nameA));
|
||||||
|
QVERIFY(QTlsBackendFactory::availableBackendNames().contains(nameB));
|
||||||
|
QVERIFY(!QTlsBackendFactory::availableBackendNames().contains(nonExisting));
|
||||||
|
|
||||||
|
const std::unique_ptr<QTlsBackend> backendA(QTlsBackendFactory::create(nameA));
|
||||||
|
QVERIFY(backendA.get());
|
||||||
|
QCOMPARE(backendA->backendName(), nameA);
|
||||||
|
|
||||||
|
const std::unique_ptr<QTlsBackend> nullBackend(QTlsBackendFactory::create(nonExisting));
|
||||||
|
QCOMPARE(nullBackend.get(), nullptr);
|
||||||
|
}
|
||||||
|
backendNames = QTlsBackendFactory::availableBackendNames();
|
||||||
|
QCOMPARE(backendNames.size(), sizeBefore);
|
||||||
|
// Check we cleaned up our factories:
|
||||||
|
QVERIFY(!backendNames.contains(nameA));
|
||||||
|
QVERIFY(!backendNames.contains(nameB));
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QSslSocket::constructing()
|
void tst_QSslSocket::constructing()
|
||||||
{
|
{
|
||||||
const char readNotOpenMessage[] = "QIODevice::read (QSslSocket): device not open";
|
const char readNotOpenMessage[] = "QIODevice::read (QSslSocket): device not open";
|
||||||
|
Loading…
Reference in New Issue
Block a user