From ee89f3a6e39e53013f132f3721332d433817a546 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 14 Jan 2021 13:54:18 +0100 Subject: QSslSocket - introduce the API providing information about backends This API gives the names of available backends and provides a basic information about features/protocols supported by those backends. Also, it has the 'loadBackend' functions which allow to select a particular backend (which are becoming plugins). At the moment, the implementation is still 'hardcoded', the follow-up patch will allow to select different backends in runtime. Task-number: QTBUG-65922 Change-Id: I05877de9c02857594e76b24d52e7578bdb01df69 Reviewed-by: Timur Pocheptsov --- src/network/ssl/qssl.cpp | 49 ++++++- src/network/ssl/qssl.h | 22 +++- src/network/ssl/qsslsocket.cpp | 146 ++++++++++++++++++++- src/network/ssl/qsslsocket.h | 12 +- src/network/ssl/qsslsocket_mac.cpp | 87 ++++++++++++ src/network/ssl/qsslsocket_openssl.cpp | 108 ++++++++++++++- src/network/ssl/qsslsocket_p.h | 8 +- src/network/ssl/qsslsocket_schannel.cpp | 91 ++++++++++++- .../auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 46 ++++++- 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/ ** @@ -1546,6 +1546,150 @@ QString QSslSocket::sslLibraryBuildVersionString() return QSslSocketPrivate::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 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 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 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 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 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 availableBackends(); + static QString activeBackend(); + static bool loadBackend(const QString &backendName); + static QList supportedProtocols(const QString &backendName = {}); + static bool isProtocolSupported(QSsl::SslProtocol protocol, const QString &backendName = {}); + static QList implementedClasses(const QString &backendName = {}); + static bool isClassImplemented(QSsl::ImplementedClass cl, const QString &backendName = {}); + static QList supportedFeatures(const QString &backendName = {}); + static bool isFeatureSupported(QSsl::SupportedFeature feat, const QString &backendName = {}); + void ignoreSslErrors(const QList &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é ** Contact: https://www.qt.io/licensing/ ** @@ -1551,4 +1552,90 @@ bool QSslSocketBackendPrivate::startHandshake() } } +QList 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 QSslSocketPrivate::supportedProtocols(const QString &backendName) +{ + QList 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 QSslSocketPrivate::implementedClasses(const QString &backendName) +{ + QList 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 QSslSocketPrivate::supportedFeatures(const QString &backendName) +{ + QList 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 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 QSslSocketPrivate::supportedProtocols(const QString &backendName) +{ + QList 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 QSslSocketPrivate::implementedClasses(const QString &backendName) +{ + QList 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 QSslSocketPrivate::supportedFeatures(const QString &backendName) +{ + QList 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 availableBackends(); + static QString activeBackend(); + static bool loadBackend(const QString &backendName); + static QList supportedProtocols(const QString &backendName); + static QList implementedClasses(const QString &backendName); + static QList 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 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 QSslSocketPrivate::supportedProtocols(const QString &backendName) +{ + QList 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 QSslSocketPrivate::implementedClasses(const QString &backendName) +{ + QList 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 QSslSocketPrivate::supportedFeatures(const QString &backendName) +{ + QList 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()); + QCOMPARE(QSslSocket::implementedClasses(nonExistingBackend), QList()); + + 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() -- cgit v1.2.3