diff options
Diffstat (limited to 'src/network/ssl')
-rw-r--r-- | src/network/ssl/qpassworddigestor.cpp | 98 | ||||
-rw-r--r-- | src/network/ssl/qssl.cpp | 2 | ||||
-rw-r--r-- | src/network/ssl/qssl.h | 13 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate.cpp | 72 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate_p.h | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslconfiguration.cpp | 33 | ||||
-rw-r--r-- | src/network/ssl/qssldiffiehellmanparameters.cpp | 13 | ||||
-rw-r--r-- | src/network/ssl/qsslpresharedkeyauthenticator.h | 1 | ||||
-rw-r--r-- | src/network/ssl/qsslserver.cpp | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 34 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket.h | 2 | ||||
-rw-r--r-- | src/network/ssl/qtlsbackend.cpp | 22 | ||||
-rw-r--r-- | src/network/ssl/qtlsbackend_p.h | 17 |
13 files changed, 239 insertions, 76 deletions
diff --git a/src/network/ssl/qpassworddigestor.cpp b/src/network/ssl/qpassworddigestor.cpp index a08702e7b6..94de14abd4 100644 --- a/src/network/ssl/qpassworddigestor.cpp +++ b/src/network/ssl/qpassworddigestor.cpp @@ -6,9 +6,20 @@ #include <QtCore/QDebug> #include <QtCore/QMessageAuthenticationCode> #include <QtCore/QtEndian> +#include <QtCore/QList> + +#include "qtcore-config_p.h" #include <limits> +#if QT_CONFIG(opensslv30) && QT_CONFIG(openssl_linked) +#define USING_OPENSSL30 +#include <openssl/core_names.h> +#include <openssl/kdf.h> +#include <openssl/params.h> +#include <openssl/provider.h> +#endif + QT_BEGIN_NAMESPACE namespace QPasswordDigestor { @@ -86,6 +97,85 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf1(QCryptographicHash::Algorithm algori return key.left(dkLen); } +#ifdef USING_OPENSSL30 +// Copied from QCryptographicHashPrivate +static constexpr const char * methodToName(QCryptographicHash::Algorithm method) noexcept +{ + switch (method) { +#define CASE(Enum, Name) \ + case QCryptographicHash:: Enum : \ + return Name \ + /*end*/ + CASE(Sha1, "SHA1"); + CASE(Md4, "MD4"); + CASE(Md5, "MD5"); + CASE(Sha224, "SHA224"); + CASE(Sha256, "SHA256"); + CASE(Sha384, "SHA384"); + CASE(Sha512, "SHA512"); + CASE(RealSha3_224, "SHA3-224"); + CASE(RealSha3_256, "SHA3-256"); + CASE(RealSha3_384, "SHA3-384"); + CASE(RealSha3_512, "SHA3-512"); + CASE(Keccak_224, "SHA3-224"); + CASE(Keccak_256, "SHA3-256"); + CASE(Keccak_384, "SHA3-384"); + CASE(Keccak_512, "SHA3-512"); + CASE(Blake2b_512, "BLAKE2B512"); + CASE(Blake2s_256, "BLAKE2S256"); +#undef CASE + default: return nullptr; + } +} + +static QByteArray opensslDeriveKeyPbkdf2(QCryptographicHash::Algorithm algorithm, + const QByteArray &data, const QByteArray &salt, + uint64_t iterations, quint64 dkLen) +{ + EVP_KDF *kdf = EVP_KDF_fetch(nullptr, "PBKDF2", nullptr); + + if (!kdf) + return QByteArray(); + + auto cleanUpKdf = qScopeGuard([kdf] { + EVP_KDF_free(kdf); + }); + + EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf); + + if (!ctx) + return QByteArray(); + + auto cleanUpCtx = qScopeGuard([ctx] { + EVP_KDF_CTX_free(ctx); + }); + + // Do not enable SP800-132 compliance check, otherwise we will require: + // - the iteration count is at least 1000 + // - the salt length is at least 128 bits + // - the derived key length is at least 112 bits + // This would be a different behavior from the original implementation. + int checkDisabled = 1; + QList<OSSL_PARAM> params; + params.append(OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast<char*>(methodToName(algorithm)), 0)); + params.append(OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, const_cast<char*>(salt.data()), salt.size())); + params.append(OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, const_cast<char*>(data.data()), data.size())); + params.append(OSSL_PARAM_construct_uint64(OSSL_KDF_PARAM_ITER, &iterations)); + params.append(OSSL_PARAM_construct_int(OSSL_KDF_PARAM_PKCS5, &checkDisabled)); + params.append(OSSL_PARAM_construct_end()); + + if (EVP_KDF_CTX_set_params(ctx, params.data()) <= 0) + return QByteArray(); + + QByteArray derived(dkLen, '\0'); + + if (!EVP_KDF_derive(ctx, reinterpret_cast<unsigned char*>(derived.data()), derived.size(), nullptr)) + return QByteArray(); + + return derived; +} +#endif + /*! \since 5.12 @@ -107,8 +197,6 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algori const QByteArray &data, const QByteArray &salt, int iterations, quint64 dkLen) { - // https://tools.ietf.org/html/rfc8018#section-5.2 - // The RFC recommends checking that 'dkLen' is not greater than '(2^32 - 1) * hLen' int hashLen = QCryptographicHash::hashLength(algorithm); const quint64 maxLen = quint64(std::numeric_limits<quint32>::max() - 1) * hashLen; @@ -122,6 +210,12 @@ Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algori if (iterations < 1 || dkLen < 1) return QByteArray(); +#ifdef USING_OPENSSL30 + if (methodToName(algorithm)) + return opensslDeriveKeyPbkdf2(algorithm, data, salt, iterations, dkLen); +#endif + + // https://tools.ietf.org/html/rfc8018#section-5.2 QByteArray key; quint32 currentIteration = 1; QMessageAuthenticationCode hmac(algorithm, data); diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index 7525df8c87..dfd3745d3e 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -256,3 +256,5 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl"); */ QT_END_NAMESPACE + +#include "moc_qssl.cpp" diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h index 3d01168172..e52b8c6361 100644 --- a/src/network/ssl/qssl.h +++ b/src/network/ssl/qssl.h @@ -10,21 +10,26 @@ #endif #include <QtNetwork/qtnetworkglobal.h> +#include <QtCore/qobjectdefs.h> #include <QtCore/QFlags> QT_BEGIN_NAMESPACE namespace QSsl { + Q_NAMESPACE_EXPORT(Q_NETWORK_EXPORT) + enum KeyType { PrivateKey, PublicKey }; + Q_ENUM_NS(KeyType) enum EncodingFormat { Pem, Der }; + Q_ENUM_NS(EncodingFormat) enum KeyAlgorithm { Opaque, @@ -33,12 +38,14 @@ namespace QSsl { Ec, Dh, }; + Q_ENUM_NS(KeyAlgorithm) enum AlternativeNameEntryType { EmailEntry, DnsEntry, IpAddressEntry }; + Q_ENUM_NS(AlternativeNameEntryType) enum SslProtocol { TlsV1_0 QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."), @@ -61,6 +68,7 @@ namespace QSsl { UnknownProtocol = -1 }; + Q_ENUM_NS(SslProtocol) enum SslOption { SslOptionDisableEmptyFragments = 0x01, @@ -72,6 +80,7 @@ namespace QSsl { SslOptionDisableSessionPersistence = 0x40, SslOptionDisableServerCipherPreference = 0x80 }; + Q_ENUM_NS(SslOption) Q_DECLARE_FLAGS(SslOptions, SslOption) enum class AlertLevel { @@ -79,6 +88,7 @@ namespace QSsl { Fatal, Unknown }; + Q_ENUM_NS(AlertLevel) enum class AlertType { CloseNotify, @@ -116,6 +126,7 @@ namespace QSsl { NoApplicationProtocol = 120, UnknownAlertMessage = 255 }; + Q_ENUM_NS(AlertType) enum class ImplementedClass { @@ -127,6 +138,7 @@ namespace QSsl { Dtls, DtlsCookie }; + Q_ENUM_NS(ImplementedClass) enum class SupportedFeature { @@ -138,6 +150,7 @@ namespace QSsl { SessionTicket, Alerts }; + Q_ENUM_NS(SupportedFeature) } Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions) diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index 0f851ec7c9..9878c603b6 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -110,7 +110,7 @@ #endif #include <QtCore/qdir.h> -#include <QtCore/qdiriterator.h> +#include <QtCore/qdirlisting.h> #include <QtCore/qfile.h> QT_BEGIN_NAMESPACE @@ -186,7 +186,7 @@ QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat fo return; } - QList<QSslCertificate> certs = X509Reader(data, 1); + const QList<QSslCertificate> certs = X509Reader(data, 1); if (!certs.isEmpty()) d = certs.first().d; } @@ -624,7 +624,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path, QString sourcePath = QDir::fromNativeSeparators(path); // Find the path without the filename - QString pathPrefix = sourcePath.left(sourcePath.lastIndexOf(u'/')); + QStringView pathPrefix = QStringView(sourcePath).left(sourcePath.lastIndexOf(u'/')); // Check if the path contains any special chars int pos = -1; @@ -647,7 +647,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path, if (lastIndexOfSlash != -1) pathPrefix = pathPrefix.left(lastIndexOfSlash); else - pathPrefix.clear(); + pathPrefix = {}; } else { // Check if the path is a file. if (QFileInfo(sourcePath).isFile()) { @@ -664,10 +664,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path, // Special case - if the prefix ends up being nothing, use "." instead. int startIndex = 0; if (pathPrefix.isEmpty()) { - pathPrefix = "."_L1; + pathPrefix = u"."; startIndex = 2; } + const QString pathPrefixString = pathPrefix.toString(); + // The path can be a file or directory. QList<QSslCertificate> certs; @@ -678,9 +680,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path, QRegularExpression pattern(QRegularExpression::anchoredPattern(sourcePath)); #endif - QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories); - while (it.hasNext()) { - QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex); + using F = QDirListing::IteratorFlag; + constexpr auto iterFlags = F::FollowSymlinks | F::Recursive; + for (const auto &dirEntry : QDirListing(pathPrefixString, QDir::Files, iterFlags)) { + QString filePath = dirEntry.filePath(); + if (startIndex > 0) + filePath.remove(0, startIndex); #if QT_CONFIG(regularexpression) if (!pattern.match(filePath).hasMatch()) @@ -878,7 +883,7 @@ static const char *const certificate_blacklist[] = { bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate) { for (int a = 0; certificate_blacklist[a] != nullptr; a++) { - QString blacklistedCommonName = QString::fromUtf8(certificate_blacklist[(a+1)]); + auto blacklistedCommonName = QAnyStringView(QUtf8StringView(certificate_blacklist[(a+1)])); if (certificate.serialNumber() == certificate_blacklist[a++] && (certificate.subjectInfo(QSslCertificate::CommonName).contains(blacklistedCommonName) || certificate.issuerInfo(QSslCertificate::CommonName).contains(blacklistedCommonName))) @@ -889,19 +894,18 @@ bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate) QByteArray QSslCertificatePrivate::subjectInfoToString(QSslCertificate::SubjectInfo info) { - QByteArray str; switch (info) { - case QSslCertificate::Organization: str = QByteArray("O"); break; - case QSslCertificate::CommonName: str = QByteArray("CN"); break; - case QSslCertificate::LocalityName: str = QByteArray("L"); break; - case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break; - case QSslCertificate::CountryName: str = QByteArray("C"); break; - case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break; - case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break; - case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break; - case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break; + case QSslCertificate::Organization: return "O"_ba; + case QSslCertificate::CommonName: return "CN"_ba; + case QSslCertificate::LocalityName: return"L"_ba; + case QSslCertificate::OrganizationalUnitName: return "OU"_ba; + case QSslCertificate::CountryName: return "C"_ba; + case QSslCertificate::StateOrProvinceName: return "ST"_ba; + case QSslCertificate::DistinguishedNameQualifier: return "dnQualifier"_ba; + case QSslCertificate::SerialNumber: return "serialNumber"_ba; + case QSslCertificate::EmailAddress: return "emailAddress"_ba; } - return str; + return QByteArray(); } /*! @@ -918,13 +922,13 @@ QString QSslCertificate::issuerDisplayName() const QStringList names; names = issuerInfo(QSslCertificate::CommonName); if (!names.isEmpty()) - return names.first(); + return names.constFirst(); names = issuerInfo(QSslCertificate::Organization); if (!names.isEmpty()) - return names.first(); + return names.constFirst(); names = issuerInfo(QSslCertificate::OrganizationalUnitName); if (!names.isEmpty()) - return names.first(); + return names.constFirst(); return QString(); } @@ -943,13 +947,13 @@ QString QSslCertificate::subjectDisplayName() const QStringList names; names = subjectInfo(QSslCertificate::CommonName); if (!names.isEmpty()) - return names.first(); + return names.constFirst(); names = subjectInfo(QSslCertificate::Organization); if (!names.isEmpty()) - return names.first(); + return names.constFirst(); names = subjectInfo(QSslCertificate::OrganizationalUnitName); if (!names.isEmpty()) - return names.first(); + return names.constFirst(); return QString(); } @@ -974,15 +978,15 @@ QDebug operator<<(QDebug debug, const QSslCertificate &certificate) QDebugStateSaver saver(debug); debug.resetFormat().nospace(); debug << "QSslCertificate(" - << certificate.version() - << ", " << certificate.serialNumber() - << ", " << certificate.digest().toBase64() - << ", " << certificate.issuerDisplayName() - << ", " << certificate.subjectDisplayName() - << ", " << certificate.subjectAlternativeNames() + << "Version=" << certificate.version() + << ", SerialNumber=" << certificate.serialNumber() + << ", Digest=" << certificate.digest().toBase64() + << ", Issuer=" << certificate.issuerDisplayName() + << ", Subject=" << certificate.subjectDisplayName() + << ", AlternativeSubjectNames=" << certificate.subjectAlternativeNames() #if QT_CONFIG(datestring) - << ", " << certificate.effectiveDate() - << ", " << certificate.expiryDate() + << ", EffectiveDate=" << certificate.effectiveDate() + << ", ExpiryDate=" << certificate.expiryDate() #endif << ')'; return debug; diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h index 02cf002460..ca59abae82 100644 --- a/src/network/ssl/qsslcertificate_p.h +++ b/src/network/ssl/qsslcertificate_p.h @@ -35,8 +35,8 @@ public: ~QSslCertificatePrivate(); QList<QSslCertificateExtension> extensions() const; - Q_NETWORK_PRIVATE_EXPORT static bool isBlacklisted(const QSslCertificate &certificate); - Q_NETWORK_PRIVATE_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info); + Q_NETWORK_EXPORT static bool isBlacklisted(const QSslCertificate &certificate); + Q_NETWORK_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info); QAtomicInt ref; std::unique_ptr<QTlsPrivate::X509Certificate> backend; diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index 63eaa6d092..fd308d7037 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -105,6 +105,12 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1"; */ /*! + \variable QSslConfiguration::ALPNProtocolHTTP2 + \brief The value used for negotiating HTTP 2 during the Application-Layer + Protocol Negotiation. +*/ + +/*! Constructs an empty SSL configuration. This configuration contains no valid settings and the state will be empty. isNull() will return true after this constructor is called. @@ -550,8 +556,6 @@ void QSslConfiguration::setPrivateKey(const QSslKey &key) ciphers. You can revert to using the entire set by calling setCiphers() with the list returned by supportedCiphers(). - \note This is not currently supported in the Schannel backend. - \sa setCiphers(), supportedCiphers() */ QList<QSslCipher> QSslConfiguration::ciphers() const @@ -567,8 +571,6 @@ QList<QSslCipher> QSslConfiguration::ciphers() const Restricting the cipher suite must be done before the handshake phase, where the session cipher is chosen. - \note This is not currently supported in the Schannel backend. - \sa ciphers(), supportedCiphers() */ void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers) @@ -581,16 +583,14 @@ void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers) Sets the cryptographic cipher suite for this configuration to \a ciphers, which is a colon-separated list of cipher suite names. The ciphers are listed - in order of preference, starting with the most preferred cipher. For example: - - \snippet code/src_network_ssl_qsslconfiguration.cpp 1 - + in order of preference, starting with the most preferred cipher. Each cipher name in \a ciphers must be the name of a cipher in the list returned by supportedCiphers(). Restricting the cipher suite must be done before the handshake phase, where the session cipher is chosen. - \note This is not currently supported in the Schannel backend. + \note With the Schannel backend the order of the ciphers is ignored and Schannel + picks the most secure one during the handshake. \sa ciphers() */ @@ -922,7 +922,11 @@ void QSslConfiguration::setPreSharedKeyIdentityHint(const QByteArray &hint) Retrieves the current set of Diffie-Hellman parameters. If no Diffie-Hellman parameters have been set, the QSslConfiguration object - defaults to using the 1024-bit MODP group from RFC 2409. + defaults to using the 2048-bit MODP group from RFC 3526. + + \note The default parameters may change in future Qt versions. + Please check the documentation of the \e{exact Qt version} that you + are using in order to know what defaults that version uses. */ QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const { @@ -936,7 +940,14 @@ QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const a server to \a dhparams. If no Diffie-Hellman parameters have been set, the QSslConfiguration object - defaults to using the 1024-bit MODP group from RFC 2409. + defaults to using the 2048-bit MODP group from RFC 3526. + + Since 6.7 you can provide an empty Diffie-Hellman parameter to use auto selection + (see SSL_CTX_set_dh_auto of openssl) if the tls backend supports it. + + \note The default parameters may change in future Qt versions. + Please check the documentation of the \e{exact Qt version} that you + are using in order to know what defaults that version uses. */ void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams) { diff --git a/src/network/ssl/qssldiffiehellmanparameters.cpp b/src/network/ssl/qssldiffiehellmanparameters.cpp index b2c112bbf9..7da14f3536 100644 --- a/src/network/ssl/qssldiffiehellmanparameters.cpp +++ b/src/network/ssl/qssldiffiehellmanparameters.cpp @@ -33,17 +33,18 @@ QT_BEGIN_NAMESPACE -// The 1024-bit MODP group from RFC 2459 (Second Oakley Group) +// The 2048-bit MODP group from RFC 3526 Q_AUTOTEST_EXPORT const char *qssl_dhparams_default_base64 = - "MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR" - "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL" - "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC"; + "MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmO" + "NATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr" + "+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXTmmkWP6j9JM9fg2VdI9yjrZYc" + "YvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhghfDKQXkYuNs474553LBgOhgObJ4Oi7Aei" + "j7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg=="; /*! Returns the default QSslDiffieHellmanParameters used by QSslSocket. - This is currently the 1024-bit MODP group from RFC 2459, also - known as the Second Oakley Group. + This is currently the 2048-bit MODP group from RFC 3526. */ QSslDiffieHellmanParameters QSslDiffieHellmanParameters::defaultParameters() { diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.h b/src/network/ssl/qsslpresharedkeyauthenticator.h index 98cfad19ed..a3912406d3 100644 --- a/src/network/ssl/qsslpresharedkeyauthenticator.h +++ b/src/network/ssl/qsslpresharedkeyauthenticator.h @@ -16,6 +16,7 @@ QT_BEGIN_NAMESPACE class QSslPreSharedKeyAuthenticatorPrivate; class QSslPreSharedKeyAuthenticator { + Q_GADGET_EXPORT(Q_NETWORK_EXPORT) public: Q_NETWORK_EXPORT QSslPreSharedKeyAuthenticator(); Q_NETWORK_EXPORT ~QSslPreSharedKeyAuthenticator(); diff --git a/src/network/ssl/qsslserver.cpp b/src/network/ssl/qsslserver.cpp index 967c478904..40a6a6f526 100644 --- a/src/network/ssl/qsslserver.cpp +++ b/src/network/ssl/qsslserver.cpp @@ -341,7 +341,7 @@ void QSslServerPrivate::initializeHandshakeProcess(QSslSocket *socket) }); auto it = socketData.emplace(quintptr(socket), readyRead, destroyed, std::make_shared<QTimer>()); it->timeoutTimer->setSingleShot(true); - it->timeoutTimer->callOnTimeout([this, socket]() { handleHandshakeTimedOut(socket); }); + it->timeoutTimer->callOnTimeout(q, [this, socket]() { handleHandshakeTimedOut(socket); }); it->timeoutTimer->setInterval(handshakeTimeout); it->timeoutTimer->start(); } @@ -408,3 +408,5 @@ void QSslServerPrivate::handleHandshakeTimedOut(QSslSocket *socket) } QT_END_NAMESPACE + +#include "moc_qsslserver.cpp" diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 4eefe43929..395394d432 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -97,8 +97,7 @@ \list \li The socket's cryptographic cipher suite can be customized before - the handshake phase with QSslConfiguration::setCiphers() - and QSslConfiguration::setDefaultCiphers(). + the handshake phase with QSslConfiguration::setCiphers(). \li The socket's local certificate and private key can be customized before the handshake phase with setLocalCertificate() and setPrivateKey(). @@ -365,6 +364,12 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +#ifdef Q_OS_VXWORKS +constexpr auto isVxworks = true; +#else +constexpr auto isVxworks = false; +#endif + class QSslSocketGlobalData { public: @@ -1539,7 +1544,12 @@ QList<QString> QSslSocket::availableBackends() from the list of available backends. \note When selecting a default backend implicitly, QSslSocket prefers - the OpenSSL backend if available. + the OpenSSL backend if available. If it's not available, the Schannel backend + is implicitly selected on Windows, and Secure Transport on Darwin platforms. + Failing these, if a custom TLS backend is found, it is used. + If no other backend is found, the "certificate only" backend is selected. + For more information about TLS plugins, please see + \l {Enabling and Disabling SSL Support when Building Qt from Source}. \sa setActiveBackend(), availableBackends() */ @@ -1973,6 +1983,10 @@ QSslSocketPrivate::QSslSocketPrivate() , flushTriggered(false) { QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration); + // If the global configuration doesn't allow root certificates to be loaded + // on demand then we have to disable it for this socket as well. + if (!configuration.allowRootCertOnDemandLoading) + allowRootCertOnDemandLoading = false; const auto *tlsBackend = tlsBackendInUse(); if (!tlsBackend) { @@ -2281,6 +2295,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri ptr->sessionProtocol = global->sessionProtocol; ptr->ciphers = global->ciphers; ptr->caCertificates = global->caCertificates; + ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading; ptr->protocol = global->protocol; ptr->peerVerifyMode = global->peerVerifyMode; ptr->peerVerifyDepth = global->peerVerifyDepth; @@ -2955,7 +2970,13 @@ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories() ba("/opt/openssl/certs/"), // HP-UX ba("/etc/ssl/"), // OpenBSD }; - return QList<QByteArray>::fromReadOnlyData(dirs); + QList<QByteArray> result = QList<QByteArray>::fromReadOnlyData(dirs); + if constexpr (isVxworks) { + static QByteArray vxworksCertsDir = qgetenv("VXWORKS_CERTS_DIR"); + if (!vxworksCertsDir.isEmpty()) + result.push_back(vxworksCertsDir); + } + return result; } /*! @@ -3086,10 +3107,11 @@ QTlsBackend *QSslSocketPrivate::tlsBackendInUse() tlsBackend = QTlsBackend::findBackend(activeBackendName); if (tlsBackend) { - QObject::connect(tlsBackend, &QObject::destroyed, [] { + QObject::connect(tlsBackend, &QObject::destroyed, tlsBackend, [] { const QMutexLocker locker(&backendMutex); tlsBackend = nullptr; - }); + }, + Qt::DirectConnection); } return tlsBackend; } diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h index 3174a68953..3ed1bc45cc 100644 --- a/src/network/ssl/qsslsocket.h +++ b/src/network/ssl/qsslsocket.h @@ -35,6 +35,7 @@ public: SslClientMode, SslServerMode }; + Q_ENUM(SslMode) enum PeerVerifyMode { VerifyNone, @@ -42,6 +43,7 @@ public: VerifyPeer, AutoVerifyPeer }; + Q_ENUM(PeerVerifyMode) explicit QSslSocket(QObject *parent = nullptr); ~QSslSocket(); diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp index 8ef82a8a8e..761ab33fbe 100644 --- a/src/network/ssl/qtlsbackend.cpp +++ b/src/network/ssl/qtlsbackend.cpp @@ -889,20 +889,28 @@ QSslCipher QTlsBackend::createCiphersuite(const QString &suiteName, QSsl::SslPro /*! \internal - Auxiliary function. Creates a new QSslCipher from \a name (which is an implementation-specific - string), \a protocol and \a protocolString, e.g.: + 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 - createCipher(QStringLiteral("schannel"), QSsl::TlsV1_2, "TLSv1.2"_L1); + createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, "ECDH"_L1, "AES"_L1, "RSA"_L1, 256, + QSsl::TlsV1_2, "TLSv1.2"_L1); \endcode */ -QSslCipher QTlsBackend::createCipher(const QString &name, QSsl::SslProtocol protocol, - const QString &protocolString) +QSslCipher QTlsBackend::createCiphersuite(const QString &name, const QString &keyExchangeMethod, + const QString &encryptionMethod, + const QString &authenticationMethod, + int bits, QSsl::SslProtocol protocol, + const QString &protocolString) { - // Note the name 'createCipher' (not 'ciphersuite'): we don't provide - // information about Kx, Au, bits/supported etc. 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; diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h index 76fa0994f5..090531014b 100644 --- a/src/network/ssl/qtlsbackend_p.h +++ b/src/network/ssl/qtlsbackend_p.h @@ -57,7 +57,7 @@ class QSslKey; namespace QTlsPrivate { -class Q_NETWORK_PRIVATE_EXPORT TlsKey { +class Q_NETWORK_EXPORT TlsKey { public: virtual ~TlsKey(); @@ -94,7 +94,7 @@ public: QByteArray pemFooter() const; }; -class Q_NETWORK_PRIVATE_EXPORT X509Certificate +class Q_NETWORK_EXPORT X509Certificate { public: virtual ~X509Certificate(); @@ -151,7 +151,7 @@ using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertif #if QT_CONFIG(ssl) // TLS over TCP. Handshake, encryption/decryption. -class Q_NETWORK_PRIVATE_EXPORT TlsCryptograph : public QObject +class Q_NETWORK_EXPORT TlsCryptograph : public QObject { public: virtual ~TlsCryptograph(); @@ -187,7 +187,7 @@ class TlsCryptograph; #if QT_CONFIG(dtls) -class Q_NETWORK_PRIVATE_EXPORT DtlsBase +class Q_NETWORK_EXPORT DtlsBase { public: virtual ~DtlsBase(); @@ -217,7 +217,7 @@ public: }; // TLS over UDP. Handshake, encryption/decryption. -class Q_NETWORK_PRIVATE_EXPORT DtlsCryptograph : virtual public DtlsBase +class Q_NETWORK_EXPORT DtlsCryptograph : virtual public DtlsBase { public: @@ -346,8 +346,11 @@ public: static QSslCipher createCiphersuite(const QString &description, int bits, int supportedBits); static QSslCipher createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol, const QString &protocolString); - static QSslCipher createCipher(const QString &name, QSsl::SslProtocol protocol, - const QString &protocolString); + static QSslCipher createCiphersuite(const QString &name, const QString &keyExchangeMethod, + const QString &encryptionMethod, + const QString &authenticationMethod, + int bits, QSsl::SslProtocol protocol, + const QString &protocolString); // Those statics are implemented using QSslSocketPrivate (which is not exported, // unlike QTlsBackend). |