diff options
Diffstat (limited to 'src/network/ssl/qtlsbackend.cpp')
-rw-r--r-- | src/network/ssl/qtlsbackend.cpp | 2149 |
1 files changed, 2031 insertions, 118 deletions
diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp index 9e1f387e11..761ab33fbe 100644 --- a/src/network/ssl/qtlsbackend.cpp +++ b/src/network/ssl/qtlsbackend.cpp @@ -1,56 +1,22 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qtlsbackend_p.h" #if QT_CONFIG(ssl) +#include "qsslpresharedkeyauthenticator_p.h" +#include "qsslpresharedkeyauthenticator.h" #include "qsslsocket_p.h" +#include "qsslcipher_p.h" #include "qsslkey_p.h" #include "qsslkey.h" -#else -#include "qtlsbackend_cert_p.h" #endif #include "qssl_p.h" #include <QtCore/private/qfactoryloader_p.h> +#include "QtCore/qapplicationstatic.h" #include <QtCore/qbytearray.h> #include <QtCore/qmutex.h> @@ -59,8 +25,10 @@ QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, - (QTlsBackend_iid, QStringLiteral("/tlsbackends"))) +using namespace Qt::StringLiterals; + +Q_APPLICATION_STATIC(QFactoryLoader, qtlsbLoader, QTlsBackend_iid, + QStringLiteral("/tls")) namespace { @@ -86,30 +54,22 @@ public: bool tryPopulateCollection() { - if (!loader()) + if (!qtlsbLoader()) return false; - static QBasicMutex mutex; + Q_CONSTINIT static QBasicMutex mutex; const QMutexLocker locker(&mutex); - if (loaded) + if (backends.size()) return true; #if QT_CONFIG(library) - loader->update(); + qtlsbLoader->update(); #endif int index = 0; - while (loader->instance(index)) + while (qtlsbLoader->instance(index)) ++index; - // TLSTODO: obviously, these two below should - // disappear as soon as plugins are in place. -#if QT_CONFIG(ssl) - QSslSocketPrivate::registerAdHocFactory(); -#else - static QTlsBackendCertOnly certGenerator; -#endif // QT_CONFIG(ssl) - - return loaded = true; + return true; } QList<QString> backendNames() @@ -146,115 +106,240 @@ public: private: std::vector<QTlsBackend *> backends; QMutex collectionMutex; - bool loaded = false; }; } // Unnamed namespace Q_GLOBAL_STATIC(BackendCollection, backends); -namespace QSsl { +/*! + \class QTlsBackend + \internal (Network-private) + \brief QTlsBackend is a factory class, providing implementations + for the QSsl classes. -TlsKey::~TlsKey() = default; + The purpose of QTlsBackend is to enable and simplify the addition + of new TLS backends to be used by QSslSocket and related classes. + Starting from Qt 6.1, these backends have plugin-based design (and + thus can co-exist simultaneously, unlike pre 6.1 times), although + any given run of a program can only use one of them. -QByteArray TlsKey::pemHeader() const -{ - if (type() == QSsl::PublicKey) - return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----"); - else if (algorithm() == QSsl::Rsa) - return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----"); - else if (algorithm() == QSsl::Dsa) - return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----"); - else if (algorithm() == QSsl::Ec) - return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----"); - else if (algorithm() == QSsl::Dh) - return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----"); + Inheriting from QTlsBackend and creating an object of such + a class adds a new backend into the list of available TLS backends. - Q_UNREACHABLE(); - return {}; -} - -QByteArray TlsKey::pemFooter() const -{ - if (type() == QSsl::PublicKey) - return QByteArrayLiteral("-----END PUBLIC KEY-----"); - else if (algorithm() == QSsl::Rsa) - return QByteArrayLiteral("-----END RSA PRIVATE KEY-----"); - else if (algorithm() == QSsl::Dsa) - return QByteArrayLiteral("-----END DSA PRIVATE KEY-----"); - else if (algorithm() == QSsl::Ec) - return QByteArrayLiteral("-----END EC PRIVATE KEY-----"); - else if (algorithm() == QSsl::Dh) - return QByteArrayLiteral("-----END PRIVATE KEY-----"); + A new backend must provide a list of classes, features and protocols + it supports, and override the corresponding virtual functions that + create backend-specific implementations for these QSsl-classes. - Q_UNREACHABLE(); - return {}; -} + The base abstract class - QTlsBackend - provides, where possible, + default implementations of its virtual member functions. These + default implementations can be overridden by a derived backend + class, if needed. -X509Certificate::~X509Certificate() = default; + QTlsBackend also provides some auxiliary functions that a derived + backend class can use to interact with the internals of network-private classes. -TlsKey *X509Certificate::publicKey() const -{ - // 'no-ssl' build has no key support either. - return nullptr; -} + \sa QSslSocket::availableBackends(), supportedFeatures(), supportedProtocols(), implementedClasses() +*/ -#if QT_CONFIG(dtls) -DtlsBase::~DtlsBase() = default; -#endif // QT_CONFIG(dtls) +/*! + \fn QString QTlsBackend::backendName() const + \internal + Returns the name of this backend. The name will be reported by QSslSocket::availableBackends(). + Example of backend names: "openssl", "schannel", "securetransport". -} // namespace QSsl + \sa QSslSocket::availableBackends(), isValid() +*/ const QString QTlsBackend::builtinBackendNames[] = { QStringLiteral("schannel"), QStringLiteral("securetransport"), - QStringLiteral("openssl") + QStringLiteral("openssl"), + QStringLiteral("cert-only") }; +/*! + \internal + The default constructor, adds a new backend to the list of available backends. + + \sa ~QTlsBackend(), availableBackendNames(), QSslSocket::availableBackends() +*/ QTlsBackend::QTlsBackend() { if (backends()) backends->addBackend(this); + + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), &QCoreApplication::destroyed, this, [this] { + delete this; + }); + } } +/*! + \internal + Removes this backend from the list of available backends. + + \sa QTlsBackend(), availableBackendNames(), QSslSocket::availableBackends() +*/ QTlsBackend::~QTlsBackend() { if (backends()) backends->removeBackend(this); } +/*! + \internal + Returns \c true if this backend was initialised successfully. The default implementation + always returns \c true. + + \note This function must be overridden if a particular backend has a non-trivial initialization + that can fail. If reimplemented, returning \c false will exclude this backend from the list of + backends, reported as available by QSslSocket. + + \sa QSslSocket::availableBackends() +*/ + bool QTlsBackend::isValid() const { return true; } -QString QTlsBackend::backendName() const +/*! + \internal + Returns an implementations-specific integer value, representing the TLS library's + version, that is currently used by this backend (i.e. runtime library version). + The default implementation returns 0. + + \sa tlsLibraryBuildVersionNumber() +*/ +long QTlsBackend::tlsLibraryVersionNumber() const +{ + return 0; +} + +/*! + \internal + Returns an implementation-specific string, representing the TLS library's version, + that is currently used by this backend (i.e. runtime library version). The default + implementation returns an empty string. + + \sa tlsLibraryBuildVersionString() +*/ + +QString QTlsBackend::tlsLibraryVersionString() const +{ + return {}; +} + +/*! + \internal + Returns an implementation-specific integer value, representing the TLS library's + version that this backend was built against (i.e. compile-time library version). + The default implementation returns 0. + + \sa tlsLibraryVersionNumber() +*/ + +long QTlsBackend::tlsLibraryBuildVersionNumber() const +{ + return 0; +} + +/*! + \internal + Returns an implementation-specific string, representing the TLS library's version + that this backend was built against (i.e. compile-time version). The default + implementation returns an empty string. + + \sa tlsLibraryVersionString() +*/ +QString QTlsBackend::tlsLibraryBuildVersionString() const +{ + return {}; +} + +/*! + \internal + QSslSocket and related classes call this function to ensure that backend's internal + resources - e.g. CA certificates, or ciphersuites - were properly initialized. +*/ +void QTlsBackend::ensureInitialized() const { - return QStringLiteral("dummyTLS"); } #define REPORT_MISSING_SUPPORT(message) \ qCWarning(lcSsl) << "The backend" << backendName() << message -QSsl::TlsKey *QTlsBackend::createKey() const +/*! + \internal + If QSsl::ImplementedClass::Key is present in this backend's implementedClasses(), + the backend must reimplement this method to return a dynamically-allocated instance + of an implementation-specific type, inheriting from the class QTlsPrivate::TlsKey. + The default implementation of this function returns \nullptr. + + \sa QSslKey, implementedClasses(), QTlsPrivate::TlsKey +*/ +QTlsPrivate::TlsKey *QTlsBackend::createKey() const { REPORT_MISSING_SUPPORT("does not support QSslKey"); return nullptr; } -QSsl::X509Certificate *QTlsBackend::createCertificate() const +/*! + \internal + If QSsl::ImplementedClass::Certificate is present in this backend's implementedClasses(), + the backend must reimplement this method to return a dynamically-allocated instance of an + implementation-specific type, inheriting from the class QTlsPrivate::X509Certificate. + The default implementation of this function returns \nullptr. + + \sa QSslCertificate, QTlsPrivate::X509Certificate, implementedClasses() +*/ +QTlsPrivate::X509Certificate *QTlsBackend::createCertificate() const { REPORT_MISSING_SUPPORT("does not support QSslCertificate"); return nullptr; } -QSsl::TlsCryptograph *QTlsBackend::createTlsCryptograph() const +/*! + \internal + This function returns a list of system CA certificates - e.g. certificates, loaded + from a system store, if available. This function allows implementation of the class + QSslConfiguration. The default implementation of this function returns an empty list. + + \sa QSslCertificate, QSslConfiguration +*/ +QList<QSslCertificate> QTlsBackend::systemCaCertificates() const +{ + REPORT_MISSING_SUPPORT("does not provide system CA certificates"); + return {}; +} + +/*! + \internal + If QSsl::ImplementedClass::Socket is present in this backend's implementedClasses(), + the backend must reimplement this method to return a dynamically-allocated instance of an + implementation-specific type, inheriting from the class QTlsPrivate::TlsCryptograph. + The default implementation of this function returns \nullptr. + + \sa QSslSocket, QTlsPrivate::TlsCryptograph, implementedClasses() +*/ +QTlsPrivate::TlsCryptograph *QTlsBackend::createTlsCryptograph() const { REPORT_MISSING_SUPPORT("does not support QSslSocket"); return nullptr; } -QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph(QDtls *qObject, int mode) const +/*! + \internal + If QSsl::ImplementedClass::Dtls is present in this backend's implementedClasses(), + the backend must reimplement this method to return a dynamically-allocated instance of an + implementation-specific type, inheriting from the class QTlsPrivate::DtlsCryptograph. + The default implementation of this function returns \nullptr. + + \sa QDtls, QTlsPrivate::DtlsCryptograph, implementedClasses() +*/ +QTlsPrivate::DtlsCryptograph *QTlsBackend::createDtlsCryptograph(QDtls *qObject, int mode) const { Q_UNUSED(qObject); Q_UNUSED(mode); @@ -262,42 +347,104 @@ QSsl::DtlsCryptograph *QTlsBackend::createDtlsCryptograph(QDtls *qObject, int mo return nullptr; } -QSsl::DtlsCookieVerifier *QTlsBackend::createDtlsCookieVerifier() const +/*! + \internal + If QSsl::ImplementedClass::DtlsCookie is present in this backend's implementedClasses(), + the backend must reimplement this method to return a dynamically-allocated instance of an + implementation-specific type, inheriting from the class QTlsPrivate::DtlsCookieVerifier. The + default implementation returns \nullptr. + + \sa QDtlsClientVerifier, QTlsPrivate::DtlsCookieVerifier, implementedClasses() +*/ +QTlsPrivate::DtlsCookieVerifier *QTlsBackend::createDtlsCookieVerifier() const { REPORT_MISSING_SUPPORT("does not support DTLS cookies"); return nullptr; } -QSsl::X509ChainVerifyPtr QTlsBackend::X509Verifier() const +/*! + \internal + If QSsl::SupportedFeature::CertificateVerification is present in this backend's + supportedFeatures(), the backend must reimplement this method to return a pointer + to a function, that checks a certificate (or a chain of certificates) against available + CA certificates. The default implementation returns \nullptr. + + \sa supportedFeatures(), QSslCertificate +*/ + +QTlsPrivate::X509ChainVerifyPtr QTlsBackend::X509Verifier() const { REPORT_MISSING_SUPPORT("does not support (manual) certificate verification"); return nullptr; } -QSsl::X509PemReaderPtr QTlsBackend::X509PemReader() const +/*! + \internal + Returns a pointer to function, that reads certificates in PEM format. The + default implementation returns \nullptr. + + \sa QSslCertificate +*/ +QTlsPrivate::X509PemReaderPtr QTlsBackend::X509PemReader() const { REPORT_MISSING_SUPPORT("cannot read PEM format"); return nullptr; } -QSsl::X509DerReaderPtr QTlsBackend::X509DerReader() const +/*! + \internal + Returns a pointer to function, that can read certificates in DER format. + The default implementation returns \nullptr. + + \sa QSslCertificate +*/ +QTlsPrivate::X509DerReaderPtr QTlsBackend::X509DerReader() const { REPORT_MISSING_SUPPORT("cannot read DER format"); return nullptr; } -QSsl::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const +/*! + \internal + Returns a pointer to function, that can read certificates in PKCS 12 format. + The default implementation returns \nullptr. + + \sa QSslCertificate +*/ +QTlsPrivate::X509Pkcs12ReaderPtr QTlsBackend::X509Pkcs12Reader() const { REPORT_MISSING_SUPPORT("cannot read PKCS12 format"); return nullptr; } +/*! + \internal + If QSsl::ImplementedClass::EllipticCurve is present in this backend's implementedClasses(), + and the backend provides information about supported curves, it must reimplement this + method to return a list of unique identifiers of the supported elliptic curves. The default + implementation returns an empty list. + + \note The meaning of a curve identifier is implementation-specific. + + \sa implemenedClasses(), QSslEllipticCurve +*/ QList<int> QTlsBackend::ellipticCurvesIds() const { REPORT_MISSING_SUPPORT("does not support QSslEllipticCurve"); return {}; } +/*! + \internal + If this backend provides information about available elliptic curves, this + function should return a unique integer identifier for a curve named \a name, + which is a conventional short name for the curve. The default implementation + returns 0. + + \note The meaning of a curve identifier is implementation-specific. + + \sa QSslEllipticCurve::shortName() +*/ int QTlsBackend::curveIdFromShortName(const QString &name) const { Q_UNUSED(name); @@ -305,6 +452,17 @@ int QTlsBackend::curveIdFromShortName(const QString &name) const return 0; } +/*! + \internal + If this backend provides information about available elliptic curves, this + function should return a unique integer identifier for a curve named \a name, + which is a conventional long name for the curve. The default implementation + returns 0. + + \note The meaning of a curve identifier is implementation-specific. + + \sa QSslElliptiCurve::longName() +*/ int QTlsBackend::curveIdFromLongName(const QString &name) const { Q_UNUSED(name); @@ -312,6 +470,16 @@ int QTlsBackend::curveIdFromLongName(const QString &name) const return 0; } +/*! + \internal + If this backend provides information about available elliptic curves, + this function should return a conventional short name for a curve identified + by \a cid. The default implementation returns an empty string. + + \note The meaning of a curve identifier is implementation-specific. + + \sa ellipticCurvesIds(), QSslEllipticCurve::shortName() +*/ QString QTlsBackend::shortNameForId(int cid) const { Q_UNUSED(cid); @@ -319,6 +487,16 @@ QString QTlsBackend::shortNameForId(int cid) const return {}; } +/*! + \internal + If this backend provides information about available elliptic curves, + this function should return a conventional long name for a curve identified + by \a cid. The default implementation returns an empty string. + + \note The meaning of a curve identifier is implementation-specific. + + \sa ellipticCurvesIds(), QSslEllipticCurve::shortName() +*/ QString QTlsBackend::longNameForId(int cid) const { Q_UNUSED(cid); @@ -326,6 +504,14 @@ QString QTlsBackend::longNameForId(int cid) const return {}; } +/*! + \internal + Returns true if the elliptic curve identified by \a cid is one of the named + curves, that can be used in the key exchange when using an elliptic curve + cipher with TLS; false otherwise. The default implementation returns false. + + \note The meaning of curve identifier is implementation-specific. +*/ bool QTlsBackend::isTlsNamedCurve(int cid) const { Q_UNUSED(cid); @@ -333,6 +519,16 @@ bool QTlsBackend::isTlsNamedCurve(int cid) const return false; } +/*! + \internal + If this backend supports the class QSslDiffieHellmanParameters, this function is + needed for construction of a QSslDiffieHellmanParameters from DER encoded data. + This function is expected to return a value that matches an enumerator in + QSslDiffieHellmanParameters::Error enumeration. The default implementation of this + function returns 0 (equals to QSslDiffieHellmanParameters::NoError). + + \sa QSslDiffieHellmanParameters, implementedClasses() +*/ int QTlsBackend::dhParametersFromDer(const QByteArray &derData, QByteArray *data) const { Q_UNUSED(derData); @@ -341,6 +537,16 @@ int QTlsBackend::dhParametersFromDer(const QByteArray &derData, QByteArray *data return {}; } +/*! + \internal + If this backend supports the class QSslDiffieHellmanParameters, this function is + is needed for construction of a QSslDiffieHellmanParameters from PEM encoded data. + This function is expected to return a value that matches an enumerator in + QSslDiffieHellmanParameters::Error enumeration. The default implementation of this + function returns 0 (equals to QSslDiffieHellmanParameters::NoError). + + \sa QSslDiffieHellmanParameters, implementedClasses() +*/ int QTlsBackend::dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const { Q_UNUSED(pemData); @@ -349,6 +555,14 @@ int QTlsBackend::dhParametersFromPem(const QByteArray &pemData, QByteArray *data return {}; } +/*! + \internal + Returns a list of names of available backends. + + \note This list contains only properly initialized backends. + + \sa QTlsBackend(), isValid() +*/ QList<QString> QTlsBackend::availableBackendNames() { if (!backends()) @@ -357,26 +571,45 @@ QList<QString> QTlsBackend::availableBackendNames() return backends->backendNames(); } +/*! + \internal + Returns the name of the backend that QSslSocket() would use by default. If no + backend was found, the function returns an empty string. +*/ QString QTlsBackend::defaultBackendName() { - // We prefer native as default: + // We prefer OpenSSL as default: const auto names = availableBackendNames(); - auto name = builtinBackendNames[nameIndexSchannel]; + auto name = builtinBackendNames[nameIndexOpenSSL]; if (names.contains(name)) return name; - name = builtinBackendNames[nameIndexSecureTransport]; + name = builtinBackendNames[nameIndexSchannel]; if (names.contains(name)) return name; - name = builtinBackendNames[nameIndexOpenSSL]; + name = builtinBackendNames[nameIndexSecureTransport]; if (names.contains(name)) return name; + const auto pos = std::find_if(names.begin(), names.end(), [](const auto &name) { + return name != builtinBackendNames[nameIndexCertOnly]; + }); + + if (pos != names.end()) + return *pos; + if (names.size()) return names[0]; return {}; } +/*! + \internal + Returns a backend named \a backendName, if it exists. + Otherwise, it returns \nullptr. + + \sa backendName(), QSslSocket::availableBackends() +*/ QTlsBackend *QTlsBackend::findBackend(const QString &backendName) { if (!backends()) @@ -389,6 +622,13 @@ QTlsBackend *QTlsBackend::findBackend(const QString &backendName) return nullptr; } +/*! + \internal + Returns the backend that QSslSocket is using. If Qt was built without TLS support, + this function returns a minimal backend that only supports QSslCertificate. + + \sa defaultBackend() +*/ QTlsBackend *QTlsBackend::activeOrAnyBackend() { #if QT_CONFIG(ssl) @@ -398,6 +638,17 @@ QTlsBackend *QTlsBackend::activeOrAnyBackend() #endif // QT_CONFIG(ssl) } +/*! + \internal + Returns a list of TLS and DTLS protocol versions, that a backend named + \a backendName supports. + + \note This list is supposed to also include range-based versions, which + allows negotiation of protocols during the handshake, so that these versions + can be used when configuring QSslSocket (e.g. QSsl::TlsV1_2OrLater). + + \sa QSsl::SslProtocol +*/ QList<QSsl::SslProtocol> QTlsBackend::supportedProtocols(const QString &backendName) { if (!backends()) @@ -409,6 +660,15 @@ QList<QSsl::SslProtocol> QTlsBackend::supportedProtocols(const QString &backendN return {}; } +/*! + \internal + Returns a list of features that a backend named \a backendName supports. E.g. + a backend may support PSK (pre-shared keys, defined as QSsl::SupportedFeature::Psk) + or ALPN (application layer protocol negotiation, identified by + QSsl::SupportedFeature::ClientSideAlpn or QSsl::SupportedFeature::ServerSideAlpn). + + \sa QSsl::SupportedFeature +*/ QList<QSsl::SupportedFeature> QTlsBackend::supportedFeatures(const QString &backendName) { if (!backends()) @@ -420,6 +680,14 @@ QList<QSsl::SupportedFeature> QTlsBackend::supportedFeatures(const QString &back return {}; } +/*! + \internal + Returns a list of classes that a backend named \a backendName supports. E.g. a backend + may implement QSslSocket (QSsl::ImplementedClass::Socket), and QDtls + (QSsl::ImplementedClass::Dtls). + + \sa QSsl::ImplementedClass +*/ QList<QSsl::ImplementedClass> QTlsBackend::implementedClasses(const QString &backendName) { if (!backends()) @@ -431,14 +699,1659 @@ QList<QSsl::ImplementedClass> QTlsBackend::implementedClasses(const QString &bac return {}; } -void QTlsBackend::resetBackend(QSslKey &key, QSsl::TlsKey *keyBackend) +/*! + \internal + Auxiliary function. Initializes \a key to use \a keyBackend. +*/ +void QTlsBackend::resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend) { #if QT_CONFIG(ssl) - key.d->keyBackend.reset(keyBackend); + key.d->backend.reset(keyBackend); #else Q_UNUSED(key); Q_UNUSED(keyBackend); #endif // QT_CONFIG(ssl) } +/*! + \internal + Auxiliary function. Initializes client-side \a auth using the \a hint, \a hintLength, + \a maxIdentityLength and \a maxPskLen. +*/ +void QTlsBackend::setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint, + int hintLength, unsigned maxIdentityLen, unsigned maxPskLen) +{ + Q_ASSERT(auth); +#if QT_CONFIG(ssl) + if (hint) + auth->d->identityHint = QByteArray::fromRawData(hint, hintLength); // it's NUL terminated, but do not include the NUL + + auth->d->maximumIdentityLength = int(maxIdentityLen) - 1; // needs to be NUL terminated + auth->d->maximumPreSharedKeyLength = int(maxPskLen); +#else + Q_UNUSED(auth); + Q_UNUSED(hint); + Q_UNUSED(hintLength); + Q_UNUSED(maxIdentityLen); + Q_UNUSED(maxPskLen); +#endif +} + +/*! + \internal + Auxiliary function. Initializes server-side \a auth using the \a identity, \a identityHint and + \a maxPskLen. +*/ +void QTlsBackend::setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity, + const QByteArray &identityHint, unsigned int maxPskLen) +{ +#if QT_CONFIG(ssl) + Q_ASSERT(auth); + auth->d->identityHint = identityHint; + auth->d->identity = identity; + auth->d->maximumIdentityLength = 0; // user cannot set an identity + auth->d->maximumPreSharedKeyLength = int(maxPskLen); +#else + Q_UNUSED(auth); + Q_UNUSED(identity); + Q_UNUSED(identityHint); + Q_UNUSED(maxPskLen); +#endif +} + +#if QT_CONFIG(ssl) +/*! + \internal + Auxiliary function. Creates a new QSslCipher from \a descriptionOneLine, \a bits + and \a supportedBits. \a descriptionOneLine consists of several fields, separated by + whitespace. These include: cipher name, protocol version, key exchange method, + authentication method, encryption method, message digest (Mac). Example: + "ECDHE-RSA-AES256-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD" +*/ +QSslCipher QTlsBackend::createCiphersuite(const QString &descriptionOneLine, int bits, int supportedBits) +{ + QSslCipher ciph; + + const auto descriptionList = QStringView{descriptionOneLine}.split(u' ', Qt::SkipEmptyParts); + if (descriptionList.size() > 5) { + ciph.d->isNull = false; + ciph.d->name = descriptionList.at(0).toString(); + + QStringView protoString = descriptionList.at(1); + ciph.d->protocolString = protoString.toString(); + ciph.d->protocol = QSsl::UnknownProtocol; +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + if (protoString.startsWith(u"TLSv1")) { + QStringView tail = protoString.sliced(5); + if (tail.startsWith(u'.')) { + tail = tail.sliced(1); + if (tail == u"3") + ciph.d->protocol = QSsl::TlsV1_3; + else if (tail == u"2") + ciph.d->protocol = QSsl::TlsV1_2; + else if (tail == u"1") + ciph.d->protocol = QSsl::TlsV1_1; + } else if (tail.isEmpty()) { + ciph.d->protocol = QSsl::TlsV1_0; + } + } +QT_WARNING_POP + + if (descriptionList.at(2).startsWith("Kx="_L1)) + ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3).toString(); + if (descriptionList.at(3).startsWith("Au="_L1)) + ciph.d->authenticationMethod = descriptionList.at(3).mid(3).toString(); + if (descriptionList.at(4).startsWith("Enc="_L1)) + ciph.d->encryptionMethod = descriptionList.at(4).mid(4).toString(); + ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == "export"_L1); + + ciph.d->bits = bits; + ciph.d->supportedBits = supportedBits; + } + + return ciph; +} + +/*! + \internal + Auxiliary function. Creates a new QSslCipher from \a suiteName, \a protocol version and + \a protocolString. For example: + \code + createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, QSsl::TlsV1_2, "TLSv1.2"_L1); + \endcode +*/ +QSslCipher QTlsBackend::createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol, + const QString &protocolString) +{ + QSslCipher ciph; + + if (!suiteName.size()) + return ciph; + + ciph.d->isNull = false; + ciph.d->name = suiteName; + ciph.d->protocol = protocol; + ciph.d->protocolString = protocolString; + + const auto bits = QStringView{ciph.d->name}.split(u'-'); + if (bits.size() >= 2) { + if (bits.size() == 2 || bits.size() == 3) + ciph.d->keyExchangeMethod = "RSA"_L1; + else if (bits.front() == "DH"_L1 || bits.front() == "DHE"_L1) + ciph.d->keyExchangeMethod = "DH"_L1; + else if (bits.front() == "ECDH"_L1 || bits.front() == "ECDHE"_L1) + ciph.d->keyExchangeMethod = "ECDH"_L1; + else + qCWarning(lcSsl) << "Unknown Kx" << ciph.d->name; + + if (bits.size() == 2 || bits.size() == 3) + ciph.d->authenticationMethod = "RSA"_L1; + else if (ciph.d->name.contains("-ECDSA-"_L1)) + ciph.d->authenticationMethod = "ECDSA"_L1; + else if (ciph.d->name.contains("-RSA-"_L1)) + ciph.d->authenticationMethod = "RSA"_L1; + else + qCWarning(lcSsl) << "Unknown Au" << ciph.d->name; + + if (ciph.d->name.contains("RC4-"_L1)) { + ciph.d->encryptionMethod = "RC4(128)"_L1; + ciph.d->bits = 128; + ciph.d->supportedBits = 128; + } else if (ciph.d->name.contains("DES-CBC3-"_L1)) { + ciph.d->encryptionMethod = "3DES(168)"_L1; + ciph.d->bits = 168; + ciph.d->supportedBits = 168; + } else if (ciph.d->name.contains("AES128-"_L1)) { + ciph.d->encryptionMethod = "AES(128)"_L1; + ciph.d->bits = 128; + ciph.d->supportedBits = 128; + } else if (ciph.d->name.contains("AES256-GCM"_L1)) { + ciph.d->encryptionMethod = "AESGCM(256)"_L1; + ciph.d->bits = 256; + ciph.d->supportedBits = 256; + } else if (ciph.d->name.contains("AES256-"_L1)) { + ciph.d->encryptionMethod = "AES(256)"_L1; + ciph.d->bits = 256; + ciph.d->supportedBits = 256; + } else if (ciph.d->name.contains("CHACHA20-"_L1)) { + ciph.d->encryptionMethod = "CHACHA20"_L1; + ciph.d->bits = 256; + ciph.d->supportedBits = 256; + } else if (ciph.d->name.contains("NULL-"_L1)) { + ciph.d->encryptionMethod = "NULL"_L1; + } else { + qCWarning(lcSsl) << "Unknown Enc" << ciph.d->name; + } + } + return ciph; +} + +/*! + \internal + Auxiliary function. Creates a new QSslCipher from \a name, \a keyExchangeMethod, \a encryptionMethod, + \a authenticationMethod, \a bits, \a protocol version and \a protocolString. + For example: + \code + createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, "ECDH"_L1, "AES"_L1, "RSA"_L1, 256, + QSsl::TlsV1_2, "TLSv1.2"_L1); + \endcode +*/ +QSslCipher QTlsBackend::createCiphersuite(const QString &name, const QString &keyExchangeMethod, + const QString &encryptionMethod, + const QString &authenticationMethod, + int bits, QSsl::SslProtocol protocol, + const QString &protocolString) +{ + QSslCipher cipher; + cipher.d->isNull = false; + cipher.d->name = name; + cipher.d->bits = bits; + cipher.d->supportedBits = bits; + cipher.d->keyExchangeMethod = keyExchangeMethod; + cipher.d->encryptionMethod = encryptionMethod; + cipher.d->authenticationMethod = authenticationMethod; + cipher.d->protocol = protocol; + cipher.d->protocolString = protocolString; + return cipher; +} + +/*! + \internal + Returns an implementation-specific list of ciphersuites that can be used by QSslSocket. + + \sa QSslConfiguration::defaultCiphers() +*/ +QList<QSslCipher> QTlsBackend::defaultCiphers() +{ + return QSslSocketPrivate::defaultCiphers(); +} + +/*! + \internal + Returns an implementation-specific list of ciphersuites that can be used by QDtls. +*/ +QList<QSslCipher> QTlsBackend::defaultDtlsCiphers() +{ + return QSslSocketPrivate::defaultDtlsCiphers(); +} + +/*! + \internal + Sets \a ciphers as defaults ciphers that QSslSocket can use. + + \sa defaultCiphers() +*/ +void QTlsBackend::setDefaultCiphers(const QList<QSslCipher> &ciphers) +{ + QSslSocketPrivate::setDefaultCiphers(ciphers); +} + +/*! + \internal + Sets \a ciphers as defaults ciphers that QDtls can use. + + \sa defaultDtlsCiphers() +*/ +void QTlsBackend::setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers) +{ + QSslSocketPrivate::setDefaultDtlsCiphers(ciphers); +} + +/*! + \internal + Sets \a ciphers as a list of supported ciphers. + + \sa QSslConfiguration::supportedCiphers() +*/ +void QTlsBackend::setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers) +{ + QSslSocketPrivate::setDefaultSupportedCiphers(ciphers); +} + +/*! + \internal + Sets the list of QSslEllipticCurve objects, that QSslConfiguration::supportedEllipticCurves() + returns, to ones that are supported by this backend. +*/ +void QTlsBackend::resetDefaultEllipticCurves() +{ + QSslSocketPrivate::resetDefaultEllipticCurves(); +} + +/*! + Sets \a certs as a list of certificates, that QSslConfiguration::caCertificates() + reports. + + \sa QSslConfiguration::defaultConfiguration(), QSslConfiguration::caCertificates() +*/ +void QTlsBackend::setDefaultCaCertificates(const QList<QSslCertificate> &certs) +{ + QSslSocketPrivate::setDefaultCaCertificates(certs); +} + +/*! + \internal + Returns true if \a configuration allows loading root certificates on demand. +*/ +bool QTlsBackend::rootLoadingOnDemandAllowed(const QSslConfiguration &configuration) +{ + return configuration.d->allowRootCertOnDemandLoading; +} + +/*! + \internal + Stores \a peerCert in the \a configuration. +*/ +void QTlsBackend::storePeerCertificate(QSslConfiguration &configuration, + const QSslCertificate &peerCert) +{ + configuration.d->peerCertificate = peerCert; +} + +/*! + \internal + Stores \a peerChain in the \a configuration. +*/ +void QTlsBackend::storePeerCertificateChain(QSslConfiguration &configuration, + const QList<QSslCertificate> &peerChain) +{ + configuration.d->peerCertificateChain = peerChain; +} + +/*! + \internal + Clears the peer certificate chain in \a configuration. +*/ +void QTlsBackend::clearPeerCertificates(QSslConfiguration &configuration) +{ + configuration.d->peerCertificate.clear(); + configuration.d->peerCertificateChain.clear(); +} + +/*! + \internal + Clears the peer certificate chain in \a d. +*/ +void QTlsBackend::clearPeerCertificates(QSslSocketPrivate *d) +{ + Q_ASSERT(d); + d->configuration.peerCertificate.clear(); + d->configuration.peerCertificateChain.clear(); +} + +/*! + \internal + Updates the configuration in \a d with \a shared value. +*/ +void QTlsBackend::setPeerSessionShared(QSslSocketPrivate *d, bool shared) +{ + Q_ASSERT(d); + d->configuration.peerSessionShared = shared; +} + +/*! + \internal + Sets TLS session in \a d to \a asn1. +*/ +void QTlsBackend::setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1) +{ + Q_ASSERT(d); + d->configuration.sslSession = asn1; +} + +/*! + \internal + Sets TLS session lifetime hint in \a d to \a hint. +*/ +void QTlsBackend::setSessionLifetimeHint(QSslSocketPrivate *d, int hint) +{ + Q_ASSERT(d); + d->configuration.sslSessionTicketLifeTimeHint = hint; +} + +/*! + \internal + Sets application layer protocol negotiation status in \a d to \a st. +*/ +void QTlsBackend::setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st) +{ + Q_ASSERT(d); + d->configuration.nextProtocolNegotiationStatus = st; +} + +/*! + \internal + Sets \a protocol in \a d as a negotiated application layer protocol. +*/ +void QTlsBackend::setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol) +{ + Q_ASSERT(d); + d->configuration.nextNegotiatedProtocol = protocol; +} + +/*! + \internal + Stores \a peerCert in the TLS configuration of \a d. +*/ +void QTlsBackend::storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert) +{ + Q_ASSERT(d); + d->configuration.peerCertificate = peerCert; +} + +/*! + \internal + + Stores \a peerChain in the TLS configuration of \a d. + + \note This is a helper function that TlsCryptograph and DtlsCryptograph + call during a handshake. +*/ +void QTlsBackend::storePeerCertificateChain(QSslSocketPrivate *d, + const QList<QSslCertificate> &peerChain) +{ + Q_ASSERT(d); + d->configuration.peerCertificateChain = peerChain; +} + +/*! + \internal + + Adds \a rootCert to the list of trusted root certificates in \a d. + + \note In Qt 6.1 it's only used on Windows, during so called 'CA fetch'. +*/ +void QTlsBackend::addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert) +{ + Q_ASSERT(d); + if (!d->configuration.caCertificates.contains(rootCert)) + d->configuration.caCertificates += rootCert; +} + +/*! + \internal + + Saves ephemeral \a key in \a d. + + \sa QSslConfiguration::ephemeralKey() +*/ +void QTlsBackend::setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key) +{ + Q_ASSERT(d); + d->configuration.ephemeralServerKey = key; +} + +/*! + \internal + + Implementation-specific. Sets the security level suitable for Qt's + auto-tests. +*/ +void QTlsBackend::forceAutotestSecurityLevel() +{ +} + +#endif // QT_CONFIG(ssl) + +namespace QTlsPrivate { + +/*! + \internal (Network-private) + \namespace QTlsPrivate + \brief Namespace containing onternal types that TLS backends implement. + + This namespace is private to Qt and the backends that implement its TLS support. +*/ + +/*! + \class TlsKey + \internal (Network-private) + \brief TlsKey is an abstract class, that allows a TLS plugin to provide + an underlying implementation for the class QSslKey. + + Most functions in the class TlsKey are pure virtual and thus have to be + reimplemented by a TLS backend that supports QSslKey. In many cases an + empty implementation as an overrider is sufficient, albeit with some + of QSslKey's functionality missing. + + \sa QTlsBackend::createKey(), QTlsBackend::implementedClasses(), QSslKey +*/ + +/*! + \fn void TlsKey::decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der, const QByteArray &passPhrase, bool deepClear) + \internal + + If a support of public and private keys in DER format is required, this function + must be overridden and should initialize this key using the \a type, \a algorithm, \a der + and \a passPhrase. If this key was initialized previously, \a deepClear + has an implementation-specific meaning (e.g., if an implementation is using + reference-counting and can share internally some data structures, a value \c true may + trigger decrementing a reference counter on some implementation-specific object). + + \note An empty overrider is sufficient, but then reading keys in QSsl::Der format + will not be supported. + + \sa isNull(), QSsl::KeyType, QSsl::EncodingFormat, QSsl::KeyAlgorithm +*/ + +/*! + \fn void TlsKey::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem, const QByteArray &passPhrase, bool deepClear) + \internal + + If a support of public and private keys in PEM format is required, this function must + be overridden and should initialize this key using the \a type, \a algorithm, \a pem and + \a passPhrase. If this key was initialized previously, \a deepClear has an + implementation-specific meaning (e.g., in an implementation using reference-counting, + a value \c true may trigger decrementing a reference counter on some implementation-specific + object). + + \note An empty overrider is sufficient, but then reading keys in QSsl::Pem format + will not be supported. + + \sa isNull(), QSsl::KeyType, QSsl::EncodingFormat, QSsl::KeyAlgorithm +*/ + +/*! + \fn QByteArray TlsKey::toPem(const QByteArray &passPhrase) const + \internal + + This function must be overridden, if converting a key to PEM format, potentially with + encryption, is needed (e.g. to save a QSslKey into a file). If this key is + private and \a passPhrase is not empty, the key's data is expected to be encrypted using + some conventional encryption algorithm (e.g. DES or AES - the one that different tools + or even the class QSslKey can understand later). + + \note If this particular functionality is not needed, an overrider returning an + empty QByteArray is sufficient. + + \sa QSslKey::toPem() +*/ + +/*! + \fn QByteArray TlsKey::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const + \internal + + Converts \a pem to DER format, using this key's type and algorithm. The parameter \a headers + must be a valid, non-null pointer. When parsing \a pem, the headers found there will be saved + into \a headers. + + \note An overrider returning an empty QByteArray is sufficient, if QSslKey::toDer() is not + needed. + + \note This function is very implementation-specific. A backend, that already has this key's + non-empty DER data, may simply return this data. + + \sa QSslKey::toDer() +*/ + +/*! + \fn QByteArray TlsKey::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const + \internal + + If overridden, this function is expected to convert \a der, using \a headers, to PEM format. + + \note This function is very implementation-specific. As of now (Qt 6.1), it is only required by + Qt's own non-OpenSSL backends, that internally use DER and implement QSslKey::toPem() + via pemFromDer(). +*/ + +/*! + \fn void TlsKey::fromHandle(Qt::HANDLE handle, KeyType type) + \internal + + Initializes this key using the \a handle and \a type, taking the ownership + of the \a handle. + + \note The meaning of the \a handle is implementation-specific. + + \note If a TLS backend does not support such keys, it must provide an + empty implementation. + + \sa handle(), QSslKey::QSslKey(), QSslKet::handle() +*/ + +/*! + \fn TlsKey::handle() const + \internal + + If a TLS backend supports opaque keys, returns a native handle that + this key was initialized with. + + \sa fromHandle(), QSslKey::handle() +*/ + +/*! + \fn bool TlsKey::isNull() const + \internal + + Returns \c true if this is a null key, \c false otherwise. + + \note A null key corresponds to the default-constructed + QSslKey or the one, that was cleared via QSslKey::clear(). + + \sa QSslKey::isNull() +*/ + +/*! + \fn QSsl::KeyType TlsKey::type() const + \internal + + Returns the type of this key (public or private). +*/ + +/*! + \fn QSsl::KeyAlgorithm TlsKey::algorithm() const + \internal + + Return this key's algorithm. +*/ + +/*! + \fn int TlsKey::length() const + \internal + + Returns the length of the key in bits, or -1 if the key is null. +*/ + +/*! + \fn void TlsKey::clear(bool deep) + \internal + + Clears the contents of this key, making it a null key. The meaning + of \a deep is implementation-specific (e.g. if some internal objects + representing a key can be shared using reference counting, \a deep equal + to \c true would imply decrementing a reference count). + + \sa isNull() +*/ + +/*! + \fn bool TlsKey::isPkcs8() const + \internal + + This function is internally used only by Qt's own TLS plugins and affects + the way PEM file is generated by TlsKey. It's sufficient to override it + and return \c false in case a new TLS backend is not using Qt's plugin + as a base. +*/ + +/*! + \fn QByteArray TlsKey::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &passPhrase, const QByteArray &iv) const + \internal + + This function allows to decrypt \a data (for example, a private key read from a file), using + \a passPhrase, initialization vector \a iv. \a cipher is describing a block cipher and its + mode (for example, AES256 + CBC). decrypt() is needed to implement QSslKey's constructor. + + \note A TLS backend may provide an empty implementation, but as a result QSslKey will not be able + to work with private encrypted keys. + + \sa QSslKey +*/ + +/*! + \fn QByteArray TlsKey::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &passPhrase, const QByteArray &iv) const + \internal + + This function is needed to implement QSslKey::toPem() with encryption (for a private + key). \a cipher names a block cipher to use to encrypt \a data, using + \a passPhrase and initialization vector \a iv. + + \note An empty implementation is sufficient, but QSslKey::toPem() will fail for + a private key and non-empty passphrase. + + \sa QSslKey +*/ + +/*! + \internal + + Destroys this key. +*/ +TlsKey::~TlsKey() = default; + +/*! + \internal + + A convenience function that returns a string, corresponding to the + key type or algorithm, which can be used as a header in a PEM file. +*/ +QByteArray TlsKey::pemHeader() const +{ + if (type() == QSsl::PublicKey) + return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----"); + else if (algorithm() == QSsl::Rsa) + return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----"); + else if (algorithm() == QSsl::Dsa) + return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----"); + else if (algorithm() == QSsl::Ec) + return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----"); + else if (algorithm() == QSsl::Dh) + return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----"); + + Q_UNREACHABLE_RETURN({}); +} + +/*! + \internal + A convenience function that returns a string, corresponding to the + key type or algorithm, which can be used as a footer in a PEM file. +*/ +QByteArray TlsKey::pemFooter() const +{ + if (type() == QSsl::PublicKey) + return QByteArrayLiteral("-----END PUBLIC KEY-----"); + else if (algorithm() == QSsl::Rsa) + return QByteArrayLiteral("-----END RSA PRIVATE KEY-----"); + else if (algorithm() == QSsl::Dsa) + return QByteArrayLiteral("-----END DSA PRIVATE KEY-----"); + else if (algorithm() == QSsl::Ec) + return QByteArrayLiteral("-----END EC PRIVATE KEY-----"); + else if (algorithm() == QSsl::Dh) + return QByteArrayLiteral("-----END PRIVATE KEY-----"); + + Q_UNREACHABLE_RETURN({}); +} + +/*! + \class X509Certificate + \internal (Network-private) + \brief X509Certificate is an abstract class that allows a TLS backend to + provide an implementation of the QSslCertificate class. + + This class provides an interface that must be reimplemented by a TLS plugin, + that supports QSslCertificate. Most functions are pure virtual, and thus + have to be overridden. For some of them, an empty overrider is acceptable, + though a part of functionality in QSslCertificate will be missing. + + \sa QTlsBackend::createCertificate(), QTlsBackend::X509PemReader(), QTlsBackend::X509DerReader() +*/ + +/*! + \fn bool X509Certificate::isEqual(const X509Certificate &other) const + \internal + + This function is expected to return \c true if this certificate is the same as + the \a other, \c false otherwise. Used by QSslCertificate's comparison operators. +*/ + +/*! + \fn bool X509Certificate::isNull() const + \internal + + Returns true if this certificate was default-constructed and not initialized yet. + This function is called by QSslCertificate::isNull(). + + \sa QSslCertificate::isNull() +*/ + +/*! + \fn bool X509Certificate::isSelfSigned() const + \internal + + This function is needed to implement QSslCertificate::isSelfSigned() + + \sa QSslCertificate::isSelfSigned() +*/ + +/*! + \fn QByteArray X509Certificate::version() const + \internal + + Implements QSslCertificate::version(). + + \sa QSslCertificate::version() +*/ + +/*! + \fn QByteArray X509Certificate::serialNumber() const + \internal + + This function is expected to return the certificate's serial number string in + hexadecimal format. + + \sa QSslCertificate::serialNumber() +*/ + +/*! + \fn QStringList X509Certificate::issuerInfo(QSslCertificate::SubjectInfo subject) const + \internal + + This function is expected to return the issuer information for the \a subject + from the certificate, or an empty list if there is no information for subject + in the certificate. There can be more than one entry of each type. + + \sa QSslCertificate::issuerInfo(). +*/ + +/*! + \fn QStringList X509Certificate::issuerInfo(const QByteArray &attribute) const + \internal + + This function is expected to return the issuer information for attribute from + the certificate, or an empty list if there is no information for \a attribute + in the certificate. There can be more than one entry for an attribute. + + \sa QSslCertificate::issuerInfo(). +*/ + +/*! + \fn QStringList X509Certificate::subjectInfo(QSslCertificate::SubjectInfo subject) const + \internal + + This function is expected to return the information for the \a subject, or an empty list + if there is no information for subject in the certificate. There can be more than one + entry of each type. + + \sa QSslCertificate::subjectInfo(). +*/ + +/*! + \fn QStringList X509Certificate::subjectInfo(const QByteArray &attribute) const + \internal + + This function is expected to return the subject information for \a attribute, or + an empty list if there is no information for attribute in the certificate. + There can be more than one entry for an attribute. + + \sa QSslCertificate::subjectInfo(). +*/ + +/*! + \fn QList<QByteArray> X509Certificate::subjectInfoAttributes() const + \internal + + This function is expected to return a list of the attributes that have values + in the subject information of this certificate. The information associated + with a given attribute can be accessed using the subjectInfo() method. Note + that this list may include the OIDs for any elements that are not known by + the TLS backend. + + \note This function is needed for QSslCertificate:::subjectInfoAttributes(). + + \sa subjectInfo() +*/ + +/*! + \fn QList<QByteArray> X509Certificate::issuerInfoAttributes() const + \internal + + This function is expected to return a list of the attributes that have + values in the issuer information of this certificate. The information + associated with a given attribute can be accessed using the issuerInfo() + method. Note that this list may include the OIDs for any + elements that are not known by the TLS backend. + + \note This function implements QSslCertificate::issuerInfoAttributes(). + + \sa issuerInfo() +*/ + +/*! + \fn QMultiMap<QSsl::AlternativeNameEntryType, QString> X509Certificate::subjectAlternativeNames() const + \internal + + This function is expected to return the list of alternative subject names for + this certificate. The alternative names typically contain host names, optionally + with wildcards, that are valid for this certificate. + + \sa subjectInfo() +*/ + +/*! + \fn QDateTime X509Certificate::effectiveDate() const + \internal + + This function is expected to return the date-time that the certificate + becomes valid, or an empty QDateTime if this is a null certificate. + + \sa expiryDate() +*/ + +/*! + \fn QDateTime X509Certificate::expiryDate() const + \internal + + This function is expected to return the date-time that the certificate expires, + or an empty QDateTime if this is a null certificate. + + \sa effectiveDate() +*/ + +/*! + \fn qsizetype X509Certificate::numberOfExtensions() const + \internal + + This function is expected to return the number of X509 extensions of + this certificate. +*/ + +/*! + \fn QString X509Certificate::oidForExtension(qsizetype i) const + \internal + + This function is expected to return the ASN.1 OID for the extension + with index \a i. + + \sa numberOfExtensions() +*/ + +/*! + \fn QString X509Certificate::nameForExtension(qsizetype i) const + \internal + + This function is expected to return the name for the extension + with index \a i. If no name is known for the extension then the + OID will be returned. + + \sa numberOfExtensions(), oidForExtension() +*/ + +/*! + \fn QVariant X509Certificate::valueForExtension(qsizetype i) const + \internal + + This function is expected to return the value of the extension + with index \a i. The structure of the value returned depends on + the extension type + + \sa numberOfExtensions() +*/ + +/*! + \fn bool X509Certificate::isExtensionCritical(qsizetype i) const + \internal + + This function is expected to return the criticality of the extension + with index \a i. + + \sa numberOfExtensions() +*/ + +/*! + \fn bool X509Certificate::isExtensionSupported(qsizetype i) const + \internal + + This function is expected to return \c true if this extension is supported. + In this case, supported simply means that the structure of the QVariant returned + by the valueForExtension() accessor will remain unchanged between versions. + + \sa numberOfExtensions() +*/ + +/*! + \fn QByteArray X509Certificate::toPem() const + \internal + + This function is expected to return this certificate converted to a PEM (Base64) + encoded representation. +*/ + +/*! + \fn QByteArray X509Certificate::toDer() const + \internal + + This function is expected to return this certificate converted to a DER (binary) + encoded representation. +*/ + +/*! + \fn QString X509Certificate::toText() const + \internal + + This function is expected to return this certificate converted to a human-readable + text representation. +*/ + +/*! + \fn Qt::HANDLE X509Certificate::handle() const + \internal + + This function is expected to return a pointer to the native certificate handle, + if there is one, else nullptr. +*/ + +/*! + \fn size_t X509Certificate::hash(size_t seed) const + \internal + + This function is expected to return the hash value for this certificate, + using \a seed to seed the calculation. +*/ + +/*! + \internal + + Destroys this certificate. +*/ +X509Certificate::~X509Certificate() = default; + +/*! + \internal + + Returns the certificate subject's public key. +*/ +TlsKey *X509Certificate::publicKey() const +{ + return nullptr; +} + +#if QT_CONFIG(ssl) + +/*! + \class TlsCryptograph + \internal (Network-private) + \brief TlsCryptograph is an abstract class, that allows a TLS plugin to implement QSslSocket. + + This abstract base class provides an interface that must be reimplemented by a TLS plugin, + that supports QSslSocket. A class, implementing TlsCryptograph's interface, is responsible + for TLS handshake, reading and writing encryped application data; it is expected + to work with QSslSocket and it's private implementation - QSslSocketPrivate. + QSslSocketPrivate provides access to its read/write buffers, QTcpSocket it + internally uses for connecting, reading and writing. QSslSocketPrivate + can also be used for reporting errors and storing the certificates received + during the handshake phase. + + \note Most of the functions in this class are pure virtual and have no actual implementation + in the QtNetwork module. This documentation is mostly conceptual and only describes what those + functions are expected to do, but not how they must be implemented. + + \sa QTlsBackend::createTlsCryptograph() +*/ + +/*! + \fn void TlsCryptograph::init(QSslSocket *q, QSslSocketPrivate *d) + \internal + + When initializing this TlsCryptograph, QSslSocket will pass a pointer to self and + its d-object using this function. +*/ + +/*! + \fn QList<QSslError> TlsCryptograph::tlsErrors() const + \internal + + Returns a list of QSslError, describing errors encountered during + the TLS handshake. + + \sa QSslSocket::sslHandshakeErrors() +*/ + +/*! + \fn void TlsCryptograph::startClientEncryption() + \internal + + A client-side QSslSocket calls this function after its internal TCP socket + establishes a connection with a remote host, or from QSslSocket::startClientEncryption(). + This TlsCryptograph is expected to initialize some implementation-specific TLS context, + if needed, and then start the client side of the TLS handshake (for example, by calling + transmit()), using TCP socket from QSslSocketPrivate. + + \sa init(), transmit(), QSslSocket::startClientEncryption(), QSslSocket::connectToHostEncrypted() +*/ + +/*! + \fn void TlsCryptograph::startServerEncryption() + \internal + + This function is called by QSslSocket::startServerEncryption(). The TlsCryptograph + is expected to initialize some implementation-specific TLS context, if needed, + and then try to read the ClientHello message and continue the TLS handshake + (for example, by calling transmit()). + + \sa transmit(), QSslSocket::startServerEncryption() +*/ + +/*! + \fn void TlsCryptograph::continueHandshake() + \internal + + QSslSocket::resume() calls this function if its pause mode is QAbstractSocket::PauseOnSslErrors, + and errors, found during the handshake, were ignored. If implemented, this function is expected + to emit QSslSocket::encrypted(). + + \sa QAbstractSocket::pauseMode(), QSslSocket::sslHandshakeErrors(), QSslSocket::ignoreSslErrors(), QSslSocket::resume() +*/ + +/*! + \fn void TlsCryptograph::disconnectFromHost() + \internal + + This function is expected to call disconnectFromHost() on the TCP socket + that can be obtained from QSslSocketPrivate. Any additional actions + are implementation-specific (e.g., sending shutdown alert message). + +*/ + +/*! + \fn void TlsCryptograph::disconnected() + \internal + + This function is called when the remote has disconnected. If there + is data left to be read you may ignore the maxReadBufferSize restriction + and read it all now. +*/ + +/*! + \fn QSslCipher TlsCryptograph::sessionCipher() const + \internal + + This function returns a QSslCipher object describing the ciphersuite negotiated + during the handshake. +*/ + +/*! + \fn QSsl::SslProtocol TlsCryptograph::sessionProtocol() const + \internal + + This function returns the version of TLS (or DTLS) protocol negotiated during the handshake. +*/ + +/*! + \fn void TlsCryptograph::transmit() + \internal + + This function is responsible for reading and writing data. The meaning of these I/O + operations depends on an implementation-specific TLS state machine. These read and write + operations can be reading and writing parts of a TLS handshake (e.g. by calling handshake-specific + functions), or reading and writing application data (if encrypted connection was already + established). transmit() is expected to use the QSslSocket's TCP socket (accessible via + QSslSocketPrivate) to read the incoming data and write the outgoing data. When in encrypted + state, transmit() is also using QSslSocket's internal read and write buffers: the read buffer + to fill with decrypted incoming data; the write buffer - for the data to encrypt and send. + This TlsCryptograph can also use QSslSocketPrivate to check which TLS errors were ignored during + the handshake. + + \note This function is responsible for emitting QSslSocket's signals, that occur during the + handshake (e.g. QSslSocket::sslErrors() or QSslSocket::encrypted()), and also read/write signals, + e.g. QSslSocket::bytesWritten() and QSslSocket::readyRead(). + + \sa init() +*/ + +/*! + \internal + + Destroys this object. +*/ +TlsCryptograph::~TlsCryptograph() = default; + +/*! + \internal + + This function allows to share QSslContext between several QSslSocket objects. + The default implementation does nothing. + + \note The definition of the class QSslContext is implementation-specific. + + \sa sslContext() +*/ +void TlsCryptograph::checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext) +{ + Q_UNUSED(tlsContext); +} + +/*! + \internal + + Returns the context previously set by checkSettingSslContext() or \nullptr, + if no context was set. The default implementation returns \nullptr. + + \sa checkSettingSslContext() +*/ +std::shared_ptr<QSslContext> TlsCryptograph::sslContext() const +{ + return {}; +} + +/*! + \internal + + If this TLS backend supports reporting errors before handshake is finished, + e.g. from a verification callback function, enableHandshakeContinuation() + allows this object to continue handshake. The default implementation does + nothing. + + \sa QSslSocket::handshakeInterruptedOnError(), QSslConfiguration::setHandshakeMustInterruptOnError() +*/ +void TlsCryptograph::enableHandshakeContinuation() +{ +} + +/*! + \internal + + Windows and OpenSSL-specific, only used internally by Qt's OpenSSL TLS backend. + + \note The default empty implementation is sufficient. +*/ +void TlsCryptograph::cancelCAFetch() +{ +} + +/*! + \internal + + Windows and Schannel-specific, only used by Qt's Schannel TLS backend, in + general, if a backend has its own buffer where it stores undecrypted data + then it must report true if it contains any data through this function. + + \note The default empty implementation, returning \c false is sufficient. +*/ +bool TlsCryptograph::hasUndecryptedData() const +{ + return false; +} + +/*! + \internal + + Returns the list of OCSP (Online Certificate Status Protocol) responses, + received during the handshake. The default implementation returns an empty + list. +*/ +QList<QOcspResponse> TlsCryptograph::ocsps() const +{ + return {}; +} + +/*! + \internal + + A helper function that can be used during a handshake. Returns \c true if the \a peerName + matches one of subject alternative names or common names found in the \a certificate. +*/ +bool TlsCryptograph::isMatchingHostname(const QSslCertificate &certificate, const QString &peerName) +{ + return QSslSocketPrivate::isMatchingHostname(certificate, peerName); +} + +/*! + \internal + Calls QAbstractSocketPrivate::setErrorAndEmit() for \a d, passing \a errorCode and + \a errorDescription as parameters. +*/ +void TlsCryptograph::setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode, + const QString &errorDescription) const +{ + Q_ASSERT(d); + d->setErrorAndEmit(errorCode, errorDescription); +} + +#if QT_CONFIG(dtls) +/*! + \class DtlsBase + \internal (Network-private) + \brief DtlsBase is a base class for the classes DtlsCryptograph and DtlsCookieVerifier. + + DtlsBase is the base class for the classes DtlsCryptograph and DtlsCookieVerifier. It's + an abstract class, an interface that these before-mentioned classes share. It allows to + set, get and clear the last error that occurred, set and get cookie generation parameters, + set and get QSslConfiguration. + + \note This class is not supposed to be inherited directly, it's only needed by DtlsCryptograph + and DtlsCookieVerifier. + + \sa QDtls, QDtlsClientVerifier, DtlsCryptograph, DtlsCookieVerifier +*/ + +/*! + \fn void DtlsBase::setDtlsError(QDtlsError code, const QString &description) + \internal + + Sets the last error to \a code and its textual description to \a description. + + \sa QDtlsError, error(), errorString() +*/ + +/*! + \fn QDtlsError DtlsBase::error() const + \internal + + This function, when overridden, is expected to return the code for the last error that occurred. + If no error occurred it should return QDtlsError::NoError. + + \sa QDtlsError, errorString(), setDtlsError() +*/ + +/*! + \fn QDtlsError DtlsBase::errorString() const + \internal + + This function, when overridden, is expected to return the textual description for the last error + that occurred or an empty string if no error occurred. + + \sa QDtlsError, error(), setDtlsError() +*/ + +/*! + \fn void DtlsBase::clearDtlsError() + \internal + + This function is expected to set the error code for the last error to QDtlsError::NoError and + its textual description to an empty string. + + \sa QDtlsError, setDtlsError(), error(), errorString() +*/ + +/*! + \fn void DtlsBase::setConfiguration(const QSslConfiguration &configuration) + \internal + + Sets a TLS configuration that an object of a class inheriting from DtlsCookieVerifier or + DtlsCryptograph will use, to \a configuration. + + \sa configuration() +*/ + +/*! + \fn QSslConfiguration DtlsBase::configuration() const + \internal + + Returns TLS configuration this object is using (either set by setConfiguration() + previously, or the default DTLS configuration). + + \sa setConfiguration(), QSslConfiguration::defaultDtlsConfiguration() +*/ + +/*! + \fn bool DtlsBase::setCookieGeneratorParameters(const QDtlsClientVerifier::GeneratorParameters ¶ms) + \internal + + Sets the DTLS cookie generation parameters that DtlsCookieVerifier or DtlsCryptograph will use to + \a params. + + \note This function returns \c false if parameters were invalid - if the secret was empty. Otherwise, + this function must return true. + + \sa QDtlsClientVerifier::GeneratorParameters, cookieGeneratorParameters() +*/ + +/*! + \fn QDtlsClientVerifier::GeneratorParameters DtlsBase::cookieGeneratorParameters() const + \internal + + Returns DTLS cookie generation parameters that were either previously set by setCookieGeneratorParameters(), + or default parameters. + + \sa setCookieGeneratorParameters() +*/ + +/*! + \internal + + Destroys this object. +*/ +DtlsBase::~DtlsBase() = default; + +/*! + \class DtlsCookieVerifier + \internal (Network-private) + \brief DtlsCookieVerifier is an interface that allows a TLS plugin to support the class QDtlsClientVerifier. + + DtlsCookieVerifier is an interface, an abstract class, that has to be implemented by + a TLS plugin that supports DTLS cookie verification. + + \sa QDtlsClientVerifier +*/ + +/*! + \fn bool DtlsCookieVerifier::verifyClient(QUdpSocket *socket, const QByteArray &dgram, const QHostAddress &address, quint16 port) + \internal + + This function is expected to verify a ClientHello message, found in \a dgram, using \a address, + \a port, and cookie generator parameters. The function returns \c true if such cookie was found + and \c false otherwise. If no valid cookie was found in the \a dgram, this verifier should use + \a socket to send a HelloVerifyRequest message, using \a address and \a port as the destination + and a source material for cookie generation, see also + \l {RFC 6347, section 4.2.1} + + \sa QDtlsClientVerifier +*/ + +/*! + \fn QByteArray DtlsCookieVerifier::verifiedHello() const + \internal + + Returns the last ClientHello message containing the DTLS cookie that this verifier was + able to verify as correct, or an empty byte array. + + \sa verifyClient() +*/ + +/*! + \class DtlsCryptograph + \internal (Network-private) + \brief DtlsCryptograph is an interface that allows a TLS plugin to implement the class QDtls. + + DtlsCryptograph is an abstract class; a TLS plugin can provide a class, inheriting from + DtlsCryptograph and implementing its pure virtual functions, thus implementing the class + QDtls and enabling DTLS over UDP. + + To write DTLS datagrams, a class, inheriting DtlsCryptograph, is expected to use + QUdpSocket. In general, all reading is done externally, so DtlsCryptograph is + expected to only write into QUdpSocket, check possible socket errors, change socket + options if needed. + + \note All functions in this class are pure virtual and have no actual implementation + in the QtNetwork module. This documentation is mostly conceptual and only describes + what those functions are expected to do, but not how they must be implemented. + + \sa QDtls, QUdpSocket +*/ + +/*! + \fn QSslSocket::SslMode DtlsCryptograph::cryptographMode() const + \internal + + Returns the mode (client or server) this object operates in. + + \note This mode is set once when a new DtlsCryptograph is created + by QTlsBackend and cannot change. + + \sa QTlsBackend::createDtlsCryptograph() +*/ + +/*! + \fn void DtlsCryptograph::setPeer(const QHostAddress &addr, quint16 port, const QString &name) + \internal + + Sets the remote peer's address to \a addr and remote port to \a port. \a name, + if not empty, is to be used when validating the peer's certificate. + + \sa peerAddress(), peerPort(), peerVerificationName() +*/ + +/*! + \fn QHostAddress DtlsCryptograph::peerAddress() const + \internal + + Returns the remote peer's address previously set by setPeer() or, + if no address was set, an empty address. + + \sa setPeer() +*/ + +/*! + \fn quint16 DtlsCryptograph::peerPort() const + \internal + + Returns the remote peer's port previously set by setPeer() or + 0 if no port was set. + + \sa setPeer(), peerAddress() +*/ + +/*! + \fn void DtlsCryptograph::setPeerVerificationName(const QString &name) + \internal + + Sets the host name to use during certificate validation to \a name. + + \sa peerVerificationName(), setPeer() +*/ + +/*! + \fn QString DtlsCryptograph::peerVerificationName() const + \internal + + Returns the name that this object is using during the certificate validation, + previously set by setPeer() or setPeerVerificationName(). Returns an empty string + if no peer verification name was set. + + \sa setPeer(), setPeerVerificationName() +*/ + +/*! + \fn void DtlsCryptograph::setDtlsMtuHint(quint16 mtu) + \internal + + Sets the maximum transmission unit (MTU), if it is supported by a TLS implementation, to \a mtu. + + \sa dtlsMtuHint() +*/ + +/*! + \fn quint16 DtlsCryptograph::dtlsMtuHint() const + \internal + + Returns the value of the maximum transmission unit either previously set by setDtlsMtuHint(), + or some implementation-specific value (guessed or somehow known to this DtlsCryptograph). + + \sa setDtlsMtuHint() +*/ + +/*! + \fn QDtls::HandshakeState DtlsCryptograph::state() const + \internal + + Returns the current handshake state for this DtlsCryptograph (not started, in progress, + peer verification error found, complete). + + \sa isConnectionEncrypted(), startHandshake() +*/ + +/*! + \fn bool DtlsCryptograph::isConnectionEncrypted() const + \internal + + Returns \c true if this DtlsCryptograph has completed a handshake without validation + errors (or these errors were ignored). Returns \c false otherwise. +*/ + +/*! + \fn bool DtlsCryptograph::startHandshake(QUdpSocket *socket, const QByteArray &dgram) + \internal + + This function is expected to initialize some implementation-specific context and to start a DTLS + handshake, using \a socket to write datagrams (but not to read them). If this object is operating + as a server, \a dgram is non-empty and contains the ClientHello message. This function returns + \c true if no error occurred (and this DtlsCryptograph's state switching to + QDtls::HandshakeState::HandshakeInProgress), \c false otherwise. + + \sa continueHandshake(), handleTimeout(), resumeHandshake(), abortHandshake(), state() +*/ + +/*! + \fn bool DtlsCryptograph::handleTimeout(QUdpSocket *socket) + \internal + + In case a timeout occurred during the handshake, allows to re-transmit the last message, + using \a socket to write the datagram. Returns \c true if no error occurred, \c false otherwise. + + \sa QDtls::handshakeTimeout(), QDtls::handleTimeout() +*/ + +/*! + \fn bool DtlsCryptograph::continueHandshake(QUdpSocket *socket, const QByteArray &dgram) + \internal + + Continues the handshake, using \a socket to write datagrams (a handshake-specific message). + \a dgram contains the peer's handshake-specific message. Returns \c false in case some error + was encountered (this can include socket-related errors and errors found during the certificate + validation). Returns \c true if the handshake was complete successfully, or is still in progress. + + This function, depending on the implementation-specific state machine, may leave the handshake + state in QDtls::HandshakeState::HandshakeInProgress, or switch to QDtls::HandshakeState::HandshakeComplete + or QDtls::HandshakeState::PeerVerificationFailed. + + This function may store the peer's certificate (or chain of certificates), extract and store + the information about the negotiated session protocol and ciphersuite. + + \sa startHandshake() +*/ + +/*! + \fn bool DtlsCryptograph::resumeHandshake(QUdpSocket *socket) + \internal + + If peer validation errors were found duing the handshake, this function tries to + continue and complete the handshake. If errors were ignored, the function switches + this object's state to QDtls::HandshakeState::HandshakeComplete and returns \c true. + + \sa abortHandshake() +*/ + +/*! + \fn void DtlsCryptograph::abortHandshake(QUdpSocket *socket) + \internal + + Aborts the handshake if it's in progress or in the state QDtls::HandshakeState::PeerVerificationFailed. + The use of \a socket is implementation-specific (for example, this DtlsCryptograph may send + ShutdownAlert message). + + \sa resumeHandshake() +*/ + +/*! + \fn void DtlsCryptograph::sendShutdownAlert(QUdpSocket *socket) + \internal + + If the underlying TLS library provides the required functionality, this function + may sent ShutdownAlert message using \a socket. +*/ + +/*! + \fn QList<QSslError> DtlsCryptograph::peerVerificationErrors() const + \internal + + Returns the list of errors that this object encountered during DTLS handshake + and certificate validation. + + \sa ignoreVerificationErrors() +*/ + +/*! + \fn void DtlsCryptograph::ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) + \internal + + Tells this object to ignore errors from \a errorsToIgnore when they are found during + DTLS handshake. + + \sa peerVerificationErrors() +*/ + +/*! + \fn QSslCipher DtlsCryptograph::dtlsSessionCipher() const + \internal + + If such information is available, returns the ciphersuite, negotiated during + the handshake. + + \sa continueHandshake(), dtlsSessionProtocol() +*/ + +/*! + \fn QSsl::SslProtocol DtlsCryptograph::dtlsSessionProtocol() const + \internal + + Returns the version of the session protocol that was negotiated during the handshake or + QSsl::UnknownProtocol if the handshake is incomplete or no information about the session + protocol is available. + + \sa continueHandshake(), dtlsSessionCipher() +*/ + +/*! + \fn qint64 DtlsCryptograph::writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) + \internal + + If this DtlsCryptograph is in the QDtls::HandshakeState::HandshakeComplete state, this function + encrypts \a dgram and writes this encrypted data into \a socket. + + Returns the number of bytes (of \a dgram) written, or -1 in case of error. This function should + set the error code and description if some error was encountered. + + \sa decryptDatagram() +*/ + +/*! + \fn QByteArray DtlsCryptograph::decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) + \internal + + If this DtlsCryptograph is in the QDtls::HandshakeState::HandshakeComplete state, decrypts \a dgram. + The use of \a socket is implementation-specific. This function should return an empty byte array + and set the error code and description if some error was encountered. +*/ + +#endif // QT_CONFIG(dtls) +#endif // QT_CONFIG(ssl) + +} // namespace QTlsPrivate + +#if QT_CONFIG(ssl) +/*! + \internal +*/ +Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel() +{ + if (auto *backend = QSslSocketPrivate::tlsBackendInUse()) + backend->forceAutotestSecurityLevel(); +} + +#endif // QT_CONFIG(ssl) + QT_END_NAMESPACE + +#include "moc_qtlsbackend_p.cpp" |