summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/ssl/qssl.cpp49
-rw-r--r--src/network/ssl/qssl.h22
-rw-r--r--src/network/ssl/qsslsocket.cpp146
-rw-r--r--src/network/ssl/qsslsocket.h12
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp87
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp108
-rw-r--r--src/network/ssl/qsslsocket_p.h8
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp91
-rw-r--r--tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp46
9 files changed, 561 insertions, 8 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index ffa211630e..fffb30fafb 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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.
@@ -243,4 +243,51 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value UnknownAlertMessage
*/
+/*!
+ \enum QSsl::ImplementedClass
+ \brief Enumerates classes that a TLS backend implements
+ \relates QSslSocket
+ \since 6.1
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ In QtNetwork, some classes have backend-specific implementation and thus
+ can be left unimplemented. Enumerators in this enum indicate, which class
+ has a working implementation in the backend.
+
+ \value Key Class QSslKey.
+ \value Certificate Class QSslCertificate.
+ \value Socket Class QSslSocket.
+ \value DiffieHellman Class QSslDiffieHellmanParameters
+ \value EllipticCurve Class QSslEllipticCurve
+ \value Dtls Classes QDtls and QDtlsClientVerifier
+*/
+
+/*!
+ \enum QSsl::SupportedFeature
+ \brief Enumerates possible features that a TLS backend supports
+ \relates QSslSocket
+ \since 6.1
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ In QtNetwork TLS-related classes have public API, that may be left unimplemented
+ by some backend, for example, our SecureTransport backend does not support
+ server-side ALPN. Enumerators from SupportedFeature enum indicate that a particular
+ feature is supported.
+
+ \value CertificateVerification Indicates that QSslCertificate::verify() is
+ implemented by the backend.
+ \value ClientSideAlpn Client-side ALPN (Application Layer Protocol Negotiation).
+ \value ServerSideAlpn Server-side ALPN.
+ \value Ocsp OCSP stapling (Online Certificate Status Protocol).
+ \value Psk Pre-shared keys.
+ \value SessionTicket Session tickets.
+ \value Alerts Information about alert messages sent and received.
+*/
+
QT_END_NAMESPACE
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index 3c0415a2e4..56727564b2 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** 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.
@@ -149,6 +149,26 @@ namespace QSsl {
UnknownAlertMessage = 255
};
+ enum class ImplementedClass
+ {
+ Key = 0x1,
+ Certificate = 0x2,
+ Socket = 0x4,
+ DiffieHellman = 0x8,
+ EllipticCurve = 0x10,
+ Dtls = 0x20
+ };
+
+ enum class SupportedFeature
+ {
+ CertificateVerification = 0x1,
+ ClientSideAlpn = 0x2,
+ ServerSideAlpn = 0x4,
+ Ocsp = 0x8,
+ Psk = 0x10,
+ SessionTicket = 0x20,
+ Alerts = 040
+ };
}
Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions)
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index a7c6b16b19..644e3771dd 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: https://www.qt.io/licensing/
**
@@ -1547,6 +1547,150 @@ QString QSslSocket::sslLibraryBuildVersionString()
}
/*!
+ \since 6.1
+ Returns the names of the currently available backends. These names
+ are in lower case, e.g. "openssl", "securetransport", "schannel"
+ (similar to the already existing feature names for TLS backends in Qt).
+
+ \sa activeBackend()
+*/
+QList<QString> QSslSocket::availableBackends()
+{
+ return QSslSocketPrivate::availableBackends();
+}
+
+/*!
+ \since 6.1
+ Returns the name of the backend that was loaded (implicitly by QSslSocket
+ or by an application via loadBackend() call). If no backend was loaded yet,
+ this function returns the name of the backend that will be loaded by QSslSocket.
+
+ \note When selecting a default backend implicitly from the list of available
+ backends, QSslSocket prefers native backends, such as SecureTransport on Darwin,
+ or Schannel on Windows.
+
+ \sa loadBackend(), availableBackends()
+*/
+QString QSslSocket::activeBackend()
+{
+ return QSslSocketPrivate::activeBackend();
+}
+
+/*!
+ \since 6.1
+ Returns true if a backend with name \a backendName was loaded
+ and was made the current active backend. \a backendName must
+ be one of names returned by availableBackends().
+
+ \note An application can switch from the default backend,
+ that will be implicitly loaded by QSslSocket, to a different backend
+ only once. It cannot mix several backends simultaneously. A non-default
+ backend must be selected prior to any use of QSslSocket or related classes
+ (like QSslCertificate or QSslKey).
+
+ \sa activeBackend(), availableBackends()
+*/
+bool QSslSocket::loadBackend(const QString &backendName)
+{
+ return QSslSocketPrivate::loadBackend(backendName);
+}
+
+/*!
+ \since 6.1
+ If a backend with name \a backendName is available, this function returns the
+ list of TLS protocol versions supported by this backend. An empty \a backendName
+ is understood as a query about the currently active backend. Otherwise, this
+ function returns an empty list.
+
+ \sa availableBackends(), activeBackend(), isProtocolSupported()
+*/
+QList<QSsl::SslProtocol> QSslSocket::supportedProtocols(const QString &backendName)
+{
+ if (Q_UNLIKELY(backendName.size() && !availableBackends().contains(backendName))) {
+ qCWarning(lcSsl) << "Cannot provide the list of supported protocols for the backend"
+ << backendName;
+ return {};
+ }
+
+ return QSslSocketPrivate::supportedProtocols(backendName);
+}
+
+/*!
+ \since 6.1
+ Returns true if \a protocol is supported by a backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa supportedProtocols()
+*/
+bool QSslSocket::isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName)
+{
+ const auto versions = supportedProtocols(backendName);
+ return versions.contains(protocol);
+}
+
+/*!
+ \since 6.1
+ This function returns backend-specific classes implemented by the backend named
+ \a backendName. An empty \a backendName is understood as a query about the
+ currently active backend.
+
+ \sa QSsl::ImplementedClass, activeBackend(), isClassImplemented()
+*/
+QList<QSsl::ImplementedClass> QSslSocket::implementedClasses(const QString &backendName)
+{
+ if (Q_UNLIKELY(backendName.size() && !availableBackends().contains(backendName))) {
+ qCWarning(lcSsl) << "Cannot provide information about supported classes for"
+ << "backend" << backendName;
+ return {};
+ }
+
+ return QSslSocketPrivate::implementedClasses(backendName);
+}
+
+/*!
+ \since 6.1
+ Returns true if a class \cl is implemented by the backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa implementedClasses()
+*/
+
+bool QSslSocket::isClassImplemented(QSsl::ImplementedClass cl, const QString &backendName)
+{
+ return implementedClasses(backendName).contains(cl);
+}
+
+/*!
+ \since 6.1
+ This function returns features supported by a backend named \a backendName.
+ An empty \a backendName is understood as a query about the currently active backend.
+
+ \sa QSsl::SupportedFeature, activeBackend()
+*/
+QList<QSsl::SupportedFeature> QSslSocket::supportedFeatures(const QString &backendName)
+{
+ if (Q_UNLIKELY(backendName.size() && !availableBackends().contains(backendName))) {
+ qCWarning(lcSsl) << "Cannot provide information about supported features for"
+ << "backend" << backendName;
+ return {};
+ }
+
+ return QSslSocketPrivate::supportedFeatures(backendName);
+}
+
+/*!
+ \since 6.1
+ Returns true if a feature \a ft is supported by a backend named \a backendName. An empty
+ \a backendName is understood as a query about the currently active backend.
+
+ \sa QSsl::SupportedFeature, supportedFeatures()
+*/
+bool QSslSocket::isFeatureSupported(QSsl::SupportedFeature ft, const QString &backendName)
+{
+ return supportedFeatures(backendName).contains(ft);
+}
+
+/*!
Starts a delayed SSL handshake for a client connection. This
function can be called when the socket is in the \l ConnectedState
but still in the \l UnencryptedMode. If it is not yet connected,
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index a808efbfdf..9bc90fad32 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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.
@@ -163,6 +163,16 @@ public:
static long sslLibraryBuildVersionNumber();
static QString sslLibraryBuildVersionString();
+ static QList<QString> availableBackends();
+ static QString activeBackend();
+ static bool loadBackend(const QString &backendName);
+ static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName = {});
+ static bool isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName = {});
+ static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName = {});
+ static bool isClassImplemented(QSsl::ImplementedClass cl, const QString &backendName = {});
+ static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName = {});
+ static bool isFeatureSupported(QSsl::SupportedFeature feat, const QString &backendName = {});
+
void ignoreSslErrors(const QList<QSslError> &errors);
void continueInterruptedHandshake();
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index 9eb9609315..9f1d8d1e54 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
** Contact: https://www.qt.io/licensing/
**
@@ -1551,4 +1552,90 @@ bool QSslSocketBackendPrivate::startHandshake()
}
}
+QList<QString> QSslSocketPrivate::availableBackends()
+{
+ return {QStringLiteral("securetransport")};
+}
+
+QString QSslSocketPrivate::activeBackend()
+{
+ 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
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 7a237ee7db..cab18d3147 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2014 Governikus GmbH & Co. KG
** Contact: https://www.qt.io/licensing/
**
@@ -2510,5 +2510,111 @@ bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device,
return true;
}
+QList<QString> QSslSocketPrivate::availableBackends()
+{
+ return {QStringLiteral("openssl")};
+}
+
+QString QSslSocketPrivate::activeBackend()
+{
+ 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
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 31b8b79302..a98f833b0c 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** 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.
@@ -204,6 +204,12 @@ public:
Q_AUTOTEST_EXPORT static bool rootCertOnDemandLoadingSupported();
+ static QList<QString> availableBackends();
+ static QString activeBackend();
+ static bool loadBackend(const QString &backendName);
+ static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName);
+ static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName);
+ static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName);
private:
static bool ensureLibraryLoaded();
static void ensureCiphersAndCertsLoaded();
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
index 65642719c3..f0e9e9c9d2 100644
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ b/src/network/ssl/qsslsocket_schannel.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** 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.
@@ -2144,4 +2144,93 @@ bool QSslSocketBackendPrivate::rootCertOnDemandLoadingAllowed()
return allowRootCertOnDemandLoading && s_loadRootCertsOnDemand;
}
+QList<QString> QSslSocketPrivate::availableBackends()
+{
+ return {QStringLiteral("schannel")};
+}
+
+QString QSslSocketPrivate::activeBackend()
+{
+ 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
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
index 1fce9df3fc..df35d93a63 100644
--- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2014 Governikus GmbH & Co. KG.
** Contact: https://www.qt.io/licensing/
**
@@ -435,6 +435,50 @@ void tst_QSslSocket::initTestCase()
QSKIP("No network test server available");
#endif // QT_TEST_SERVER
#endif // QT_NO_SSL
+
+ // Since a backend can be loaded only once by an application (this test in our case),
+ // we do backend testing here:
+ const QString nonExistingBackend = QStringLiteral("TheQtTLS");
+ QCOMPARE(QSslSocket::loadBackend(nonExistingBackend), false);
+ QCOMPARE(QSslSocket::supportedProtocols(nonExistingBackend).size(), 0);
+ QCOMPARE(QSslSocket::supportedFeatures(nonExistingBackend), QList<QSsl::SupportedFeature>());
+ QCOMPARE(QSslSocket::implementedClasses(nonExistingBackend), QList<QSsl::ImplementedClass>());
+
+ const QString backendName = QSslSocket::activeBackend();
+ // Implemented by all our existing backends:
+ const auto implemented = QSsl::ImplementedClass::Socket;
+ const auto supportedFt = QSsl::SupportedFeature::ClientSideAlpn;
+
+ QVERIFY(QSslSocket::availableBackends().contains(backendName));
+ QCOMPARE(QSslSocket::loadBackend(backendName), true);
+ QCOMPARE(QSslSocket::activeBackend(), backendName);
+ QCOMPARE(QSslSocket::loadBackend(backendName), true); // Already loaded, but not a fail.
+ QCOMPARE(QSslSocket::activeBackend(), backendName);
+
+ const auto protocols = QSslSocket::supportedProtocols();
+ QVERIFY(protocols.size() > 0);
+ // 'Any' and 'Secure', since they are always present:
+ QVERIFY(protocols.contains(QSsl::AnyProtocol));
+ QVERIFY(protocols.contains(QSsl::SecureProtocols));
+
+ const auto protocolsForNamed = QSslSocket::supportedProtocols(backendName);
+ QCOMPARE(protocols, protocolsForNamed);
+ // Any and secure, new versions are coming, old
+ // go away, nothing more specific.
+ QVERIFY(protocolsForNamed.contains(QSsl::AnyProtocol));
+ QVERIFY(protocolsForNamed.contains(QSsl::SecureProtocols));
+ QCOMPARE(QSslSocket::isProtocolSupported(QSsl::SecureProtocols), true);
+ QCOMPARE(QSslSocket::isProtocolSupported(QSsl::SecureProtocols, backendName), true);
+
+ const auto classes = QSslSocket::implementedClasses();
+ QVERIFY(classes.contains(implemented));
+ QVERIFY(QSslSocket::isClassImplemented(implemented));
+ QVERIFY(QSslSocket::isClassImplemented(implemented, backendName));
+
+ const auto features = QSslSocket::supportedFeatures();
+ QVERIFY(features.contains(QSsl::SupportedFeature(supportedFt)));
+ QVERIFY(QSslSocket::isFeatureSupported(QSsl::SupportedFeature(supportedFt)));
+ QVERIFY(QSslSocket::isFeatureSupported(QSsl::SupportedFeature(supportedFt), backendName));
}
void tst_QSslSocket::init()