diff options
Diffstat (limited to 'src/network/ssl/qsslsocket.cpp')
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 537 |
1 files changed, 424 insertions, 113 deletions
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 9a02f439ab..395394d432 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Copyright (C) 2014 BlackBerry Limited. All rights reserved. -** 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. +// Copyright (C) 2014 BlackBerry Limited. All rights reserved. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only //#define QSSLSOCKET_DEBUG @@ -54,10 +18,10 @@ QSslSocket establishes a secure, encrypted TCP connection you can use for transmitting encrypted data. It can operate in both client - and server mode, and it supports modern SSL protocols, including - SSL 3 and TLS 1.2. By default, QSslSocket uses only SSL protocols + and server mode, and it supports modern TLS protocols, including + TLS 1.3. By default, QSslSocket uses only TLS protocols which are considered to be secure (QSsl::SecureProtocols), but you can - change the SSL protocol by calling setProtocol() as long as you do + change the TLS protocol by calling setProtocol() as long as you do it before the handshake has started. SSL encryption operates on top of the existing TCP stream after @@ -133,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(). @@ -188,7 +151,7 @@ behavior is identical to QTcpSocket. \value SslClientMode The socket is a client-side SSL socket. - It is either alreayd encrypted, or it is in the SSL handshake + It is either already encrypted, or it is in the SSL handshake phase (see QSslSocket::isEncrypted()). \value SslServerMode The socket is a server-side SSL socket. @@ -386,16 +349,8 @@ #include "qsslcipher.h" #include "qocspresponse.h" #include "qtlsbackend_p.h" -#ifndef QT_NO_OPENSSL -#include "qsslsocket_openssl_p.h" -#endif -#ifdef QT_SECURETRANSPORT -#include "qsslsocket_mac_p.h" -#endif -#if QT_CONFIG(schannel) -#include "qsslsocket_schannel_p.h" -#endif #include "qsslconfiguration_p.h" +#include "qsslsocket_p.h" #include <QtCore/qdebug.h> #include <QtCore/qdir.h> @@ -407,6 +362,14 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + +#ifdef Q_OS_VXWORKS +constexpr auto isVxworks = true; +#else +constexpr auto isVxworks = false; +#endif + class QSslSocketGlobalData { public: @@ -433,7 +396,7 @@ Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData) set to the one returned by the static method defaultCiphers(). */ QSslSocket::QSslSocket(QObject *parent) - : QTcpSocket(*new QSslSocketBackendPrivate, parent) + : QTcpSocket(*new QSslSocketPrivate, parent) { Q_D(QSslSocket); #ifdef QSSLSOCKET_DEBUG @@ -903,7 +866,8 @@ void QSslSocket::close() // On Windows, CertGetCertificateChain is probably still doing its // job, if the socket is re-used, we want to ignore its reported // root CA. - d->caToFetch = QSslCertificate{}; + if (auto *backend = d->backend.get()) + backend->cancelCAFetch(); if (!d->abortCalled && (encryptedBytesToWrite() || !d->writeBuffer.isEmpty())) flush(); @@ -1210,7 +1174,9 @@ QSsl::SslProtocol QSslSocket::sessionProtocol() const QList<QOcspResponse> QSslSocket::ocspResponses() const { Q_D(const QSslSocket); - return d->ocspResponses; + if (const auto *backend = d->backend.get()) + return backend->ocsps(); + return {}; } /*! @@ -1485,7 +1451,9 @@ bool QSslSocket::waitForDisconnected(int msecs) QList<QSslError> QSslSocket::sslHandshakeErrors() const { Q_D(const QSslSocket); - return d->sslErrors; + if (const auto *backend = d->backend.get()) + return backend->tlsErrors(); + return {}; } /*! @@ -1502,12 +1470,14 @@ bool QSslSocket::supportsSsl() \since 5.0 Returns the version number of the SSL library in use. Note that this is the version of the library in use at run-time not compile - time. If no SSL support is available then this will return an - undefined value. + time. If no SSL support is available then this will return -1. */ long QSslSocket::sslLibraryVersionNumber() { - return QSslSocketPrivate::sslLibraryVersionNumber(); + if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) + return tlsBackend->tlsLibraryVersionNumber(); + + return -1; } /*! @@ -1518,20 +1488,23 @@ long QSslSocket::sslLibraryVersionNumber() */ QString QSslSocket::sslLibraryVersionString() { - return QSslSocketPrivate::sslLibraryVersionString(); + if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) + return tlsBackend->tlsLibraryVersionString(); + return {}; } /*! \since 5.4 Returns the version number of the SSL library in use at compile - time. If no SSL support is available then this will return an - undefined value. + time. If no SSL support is available then this will return -1. \sa sslLibraryVersionNumber() */ long QSslSocket::sslLibraryBuildVersionNumber() { - return QSslSocketPrivate::sslLibraryBuildVersionNumber(); + if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) + return tlsBackend->tlsLibraryBuildVersionNumber(); + return -1; } /*! @@ -1544,7 +1517,10 @@ long QSslSocket::sslLibraryBuildVersionNumber() */ QString QSslSocket::sslLibraryBuildVersionString() { - return QSslSocketPrivate::sslLibraryBuildVersionString(); + if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) + return tlsBackend->tlsLibraryBuildVersionString(); + + return {}; } /*! @@ -1568,7 +1544,12 @@ QList<QString> QSslSocket::availableBackends() from the list of available backends. \note When selecting a default backend implicitly, QSslSocket prefers - native backends, such as SecureTransport on Darwin, or Schannel on Windows. + 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() */ @@ -1857,7 +1838,8 @@ void QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) void QSslSocket::continueInterruptedHandshake() { Q_D(QSslSocket); - d->handshakeInterrupted = false; + if (auto *backend = d->backend.get()) + backend->enableHandshakeContinuation(); } /*! @@ -1914,7 +1896,8 @@ void QSslSocket::disconnectFromHost() } // Make sure we don't process any signal from the CA fetcher // (Windows): - d->caToFetch = QSslCertificate{}; + if (auto *backend = d->backend.get()) + backend->cancelCAFetch(); // Perhaps emit closing() if (d->state != ClosingState) { @@ -1982,6 +1965,8 @@ qint64 QSslSocket::writeData(const char *data, qint64 len) return len; } +bool QSslSocketPrivate::s_loadRootCertsOnDemand = false; + /*! \internal */ @@ -1990,7 +1975,6 @@ QSslSocketPrivate::QSslSocketPrivate() , mode(QSslSocket::UnencryptedMode) , autoStartHandshake(false) , connectionEncrypted(false) - , shutdown(false) , ignoreAllSslErrors(false) , readyReadEmittedPointer(nullptr) , allowRootCertOnDemandLoading(true) @@ -1999,6 +1983,21 @@ 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) { + qCWarning(lcSsl, "No TLS backend is available"); + return; + } + backend.reset(tlsBackend->createTlsCryptograph()); + if (!backend.get()) { + qCWarning(lcSsl) << "The backend named" << tlsBackend->backendName() + << "does not support TLS"; + } } /*! @@ -2011,28 +2010,54 @@ QSslSocketPrivate::~QSslSocketPrivate() /*! \internal */ +bool QSslSocketPrivate::supportsSsl() +{ + if (const auto *tlsBackend = tlsBackendInUse()) + return tlsBackend->implementedClasses().contains(QSsl::ImplementedClass::Socket); + return false; +} + +/*! + \internal + + Declared static in QSslSocketPrivate, makes sure the SSL libraries have + been initialized. +*/ +void QSslSocketPrivate::ensureInitialized() +{ + if (!supportsSsl()) + return; + + const auto *tlsBackend = tlsBackendInUse(); + Q_ASSERT(tlsBackend); + tlsBackend->ensureInitialized(); +} + +/*! + \internal +*/ void QSslSocketPrivate::init() { + // TLSTODO: delete those data members. mode = QSslSocket::UnencryptedMode; autoStartHandshake = false; connectionEncrypted = false; ignoreAllSslErrors = false; - shutdown = false; abortCalled = false; pendingClose = false; flushTriggered = false; - ocspResponses.clear(); - systemOrSslErrorDetected = false; - // we don't want to clear the ignoreErrorsList, so - // that it is possible setting it before connecting -// ignoreErrorsList.clear(); + // We don't want to clear the ignoreErrorsList, so + // that it is possible setting it before connecting. buffer.clear(); writeBuffer.clear(); configuration.peerCertificate.clear(); configuration.peerCertificateChain.clear(); - fetchAuthorityInformation = false; - caToFetch = QSslCertificate{}; + + if (backend.get()) { + Q_ASSERT(q_ptr); + backend->init(static_cast<QSslSocket *>(q_ptr), this); + } } /*! @@ -2040,13 +2065,15 @@ void QSslSocketPrivate::init() */ bool QSslSocketPrivate::verifyProtocolSupported(const char *where) { - QLatin1String protocolName("DTLS"); + auto protocolName = "DTLS"_L1; switch (configuration.protocol) { case QSsl::UnknownProtocol: // UnknownProtocol, according to our docs, is for cipher whose protocol is unknown. // Should not be used when configuring QSslSocket. - protocolName = QLatin1String("UnknownProtocol"); + protocolName = "UnknownProtocol"_L1; Q_FALLTHROUGH(); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED case QSsl::DtlsV1_0: case QSsl::DtlsV1_2: case QSsl::DtlsV1_0OrLater: @@ -2055,6 +2082,7 @@ bool QSslSocketPrivate::verifyProtocolSupported(const char *where) setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, QSslSocket::tr("Attempted to use an unsupported protocol.")); return false; +QT_WARNING_POP default: return true; } @@ -2103,7 +2131,35 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph /*! \internal */ -void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers) +void QSslSocketPrivate::resetDefaultEllipticCurves() +{ + const auto *tlsBackend = tlsBackendInUse(); + if (!tlsBackend) + return; + + auto ids = tlsBackend->ellipticCurvesIds(); + if (!ids.size()) + return; + + QList<QSslEllipticCurve> curves; + curves.reserve(ids.size()); + for (int id : ids) { + QSslEllipticCurve curve; + curve.id = id; + curves.append(curve); + } + + // Set the list of supported ECs, but not the list + // of *default* ECs. OpenSSL doesn't like forcing an EC for the wrong + // ciphersuite, so don't try it -- leave the empty list to mean + // "the implementation will choose the most suitable one". + setDefaultSupportedEllipticCurves(curves); +} + +/*! + \internal +*/ +void QSslSocketPrivate::setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers) { QMutexLocker locker(&globalData()->mutex); globalData()->dtlsConfig.detach(); @@ -2113,7 +2169,7 @@ void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers) /*! \internal */ -QList<QSslCipher> q_getDefaultDtlsCiphers() +QList<QSslCipher> QSslSocketPrivate::defaultDtlsCiphers() { QSslSocketPrivate::ensureInitialized(); QMutexLocker locker(&globalData()->mutex); @@ -2239,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; @@ -2360,6 +2417,11 @@ bool QSslSocketPrivate::isPaused() const return paused; } +void QSslSocketPrivate::setPaused(bool p) +{ + paused = p; +} + bool QSslSocketPrivate::bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode) { // this function is called from QAbstractSocket::bind @@ -2590,6 +2652,7 @@ void QSslSocketPrivate::_q_resumeImplementation() if (verifyErrorsHaveBeenIgnored()) { continueHandshake(); } else { + const auto sslErrors = backend->tlsErrors(); Q_ASSERT(!sslErrors.isEmpty()); setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString()); plainSocket->disconnectFromHost(); @@ -2604,13 +2667,16 @@ void QSslSocketPrivate::_q_resumeImplementation() */ bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored() { + Q_ASSERT(backend.get()); + bool doEmitSslError; if (!ignoreErrorsList.empty()) { // check whether the errors we got are all in the list of expected errors // (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) // was called) + const auto &sslErrors = backend->tlsErrors(); doEmitSslError = false; - for (int a = 0; a < sslErrors.count(); a++) { + for (int a = 0; a < sslErrors.size(); a++) { if (!ignoreErrorsList.contains(sslErrors.at(a))) { doEmitSslError = true; break; @@ -2628,6 +2694,91 @@ bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored() /*! \internal */ +bool QSslSocketPrivate::isAutoStartingHandshake() const +{ + return autoStartHandshake; +} + +/*! + \internal +*/ +bool QSslSocketPrivate::isPendingClose() const +{ + return pendingClose; +} + +/*! + \internal +*/ +void QSslSocketPrivate::setPendingClose(bool pc) +{ + pendingClose = pc; +} + +/*! + \internal +*/ +qint64 QSslSocketPrivate::maxReadBufferSize() const +{ + return readBufferMaxSize; +} + +/*! + \internal +*/ +void QSslSocketPrivate::setMaxReadBufferSize(qint64 maxSize) +{ + readBufferMaxSize = maxSize; +} + +/*! + \internal +*/ +void QSslSocketPrivate::setEncrypted(bool enc) +{ + connectionEncrypted = enc; +} + +/*! + \internal +*/ +QIODevicePrivate::QRingBufferRef &QSslSocketPrivate::tlsWriteBuffer() +{ + return writeBuffer; +} + +/*! + \internal +*/ +QIODevicePrivate::QRingBufferRef &QSslSocketPrivate::tlsBuffer() +{ + return buffer; +} + +/*! + \internal +*/ +bool &QSslSocketPrivate::tlsEmittedBytesWritten() +{ + return emittedBytesWritten; +} + +/*! + \internal +*/ +bool *QSslSocketPrivate::readyReadPointer() +{ + return readyReadEmittedPointer; +} + +bool QSslSocketPrivate::hasUndecryptedData() const +{ + return backend.get() && backend->hasUndecryptedData(); +} + +/*! + \internal +*/ qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize) { if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) { @@ -2643,9 +2794,9 @@ qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize) if (r2 < 0) return (r > 0 ? r : r2); return r + r2; - } else { - return -1; } + + return -1; } else { //encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer return QTcpSocketPrivate::peek(data, maxSize); @@ -2663,13 +2814,13 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize) QByteArray ret; ret.reserve(maxSize); ret.resize(buffer.peek(ret.data(), maxSize, transactionPos)); - if (ret.length() == maxSize) + if (ret.size() == maxSize) return ret; //peek at data in the plain socket if (plainSocket) - return ret + plainSocket->peek(maxSize - ret.length()); - else - return QByteArray(); + return ret + plainSocket->peek(maxSize - ret.size()); + + return QByteArray(); } else { //encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer return QTcpSocketPrivate::peek(maxSize); @@ -2711,6 +2862,82 @@ bool QSslSocketPrivate::flush() /*! \internal */ +void QSslSocketPrivate::startClientEncryption() +{ + if (backend.get()) + backend->startClientEncryption(); +} + +/*! + \internal +*/ +void QSslSocketPrivate::startServerEncryption() +{ + if (backend.get()) + backend->startServerEncryption(); +} + +/*! + \internal +*/ +void QSslSocketPrivate::transmit() +{ + if (backend.get()) + backend->transmit(); +} + +/*! + \internal +*/ +void QSslSocketPrivate::disconnectFromHost() +{ + if (backend.get()) + backend->disconnectFromHost(); +} + +/*! + \internal +*/ +void QSslSocketPrivate::disconnected() +{ + if (backend.get()) + backend->disconnected(); +} + +/*! + \internal +*/ +QSslCipher QSslSocketPrivate::sessionCipher() const +{ + if (backend.get()) + return backend->sessionCipher(); + + return {}; +} + +/*! + \internal +*/ +QSsl::SslProtocol QSslSocketPrivate::sessionProtocol() const +{ + if (backend.get()) + return backend->sessionProtocol(); + + return QSsl::UnknownProtocol; +} + +/*! + \internal +*/ +void QSslSocketPrivate::continueHandshake() +{ + if (backend.get()) + backend->continueHandshake(); +} + +/*! + \internal +*/ bool QSslSocketPrivate::rootCertOnDemandLoadingSupported() { return s_loadRootCertsOnDemand; @@ -2719,34 +2946,63 @@ bool QSslSocketPrivate::rootCertOnDemandLoadingSupported() /*! \internal */ +void QSslSocketPrivate::setRootCertOnDemandLoadingSupported(bool supported) +{ + s_loadRootCertsOnDemand = supported; +} + +/*! + \internal +*/ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories() { - return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva ... - << "/usr/lib/ssl/certs/" // Gentoo, Mandrake - << "/usr/share/ssl/" // Centos, Redhat, SuSE - << "/usr/local/ssl/" // Normal OpenSSL Tarball - << "/var/ssl/certs/" // AIX - << "/usr/local/ssl/certs/" // Solaris - << "/etc/openssl/certs/" // BlackBerry - << "/opt/openssl/certs/" // HP-UX - << "/etc/ssl/"; // OpenBSD + const auto ba = [](const auto &cstr) constexpr { + return QByteArray::fromRawData(std::begin(cstr), std::size(cstr) - 1); + }; + static const QByteArray dirs[] = { + ba("/etc/ssl/certs/"), // (K)ubuntu, OpenSUSE, Mandriva ... + ba("/usr/lib/ssl/certs/"), // Gentoo, Mandrake + ba("/usr/share/ssl/"), // Centos, Redhat, SuSE + ba("/usr/local/ssl/"), // Normal OpenSSL Tarball + ba("/var/ssl/certs/"), // AIX + ba("/usr/local/ssl/certs/"), // Solaris + ba("/etc/openssl/certs/"), // BlackBerry + ba("/opt/openssl/certs/"), // HP-UX + ba("/etc/ssl/"), // OpenBSD + }; + 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; } /*! \internal */ -void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointer<QSslContext> sslContext) +void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, std::shared_ptr<QSslContext> tlsContext) { - if (socket->d_func()->sslContextPointer.isNull()) - socket->d_func()->sslContextPointer = sslContext; + if (!socket) + return; + + if (auto *backend = socket->d_func()->backend.get()) + backend->checkSettingSslContext(tlsContext); } /*! \internal */ -QSharedPointer<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket) +std::shared_ptr<QSslContext> QSslSocketPrivate::sslContext(QSslSocket *socket) { - return (socket) ? socket->d_func()->sslContextPointer : QSharedPointer<QSslContext>(); + if (!socket) + return {}; + + if (const auto *backend = socket->d_func()->backend.get()) + return backend->sslContext(); + + return {}; } bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName) @@ -2786,17 +3042,17 @@ bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QS */ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hostname) { - int wildcard = cn.indexOf(QLatin1Char('*')); + qsizetype wildcard = cn.indexOf(u'*'); // Check this is a wildcard cert, if not then just compare the strings if (wildcard < 0) - return QLatin1String(QUrl::toAce(cn)) == hostname; + return QLatin1StringView(QUrl::toAce(cn)) == hostname; - int firstCnDot = cn.indexOf(QLatin1Char('.')); - int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1); + qsizetype firstCnDot = cn.indexOf(u'.'); + qsizetype secondCnDot = cn.indexOf(u'.', firstCnDot+1); // Check at least 3 components - if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length())) + if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.size())) return false; // Check * is last character of 1st component (ie. there's a following .) @@ -2804,12 +3060,12 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos return false; // Check only one star - if (cn.lastIndexOf(QLatin1Char('*')) != wildcard) + if (cn.lastIndexOf(u'*') != wildcard) return false; // Reject wildcard character embedded within the A-labels or U-labels of an internationalized // domain name (RFC6125 section 7.2) - if (cn.startsWith(QLatin1String("xn--"), Qt::CaseInsensitive)) + if (cn.startsWith("xn--"_L1, Qt::CaseInsensitive)) return false; // Check characters preceding * (if any) match @@ -2817,9 +3073,9 @@ bool QSslSocketPrivate::isMatchingHostname(const QString &cn, const QString &hos return false; // Check characters following first . match - int hnDot = hostname.indexOf(QLatin1Char('.')); + qsizetype hnDot = hostname.indexOf(u'.'); if (QStringView{hostname}.mid(hnDot + 1) != QStringView{cn}.mid(firstCnDot + 1) - && QStringView{hostname}.mid(hnDot + 1) != QLatin1String(QUrl::toAce(cn.mid(firstCnDot + 1)))) { + && QStringView{hostname}.mid(hnDot + 1) != QLatin1StringView(QUrl::toAce(cn.mid(firstCnDot + 1)))) { return false; } @@ -2849,7 +3105,62 @@ QTlsBackend *QSslSocketPrivate::tlsBackendInUse() return nullptr; } - return tlsBackend = QTlsBackend::findBackend(activeBackendName); + tlsBackend = QTlsBackend::findBackend(activeBackendName); + if (tlsBackend) { + QObject::connect(tlsBackend, &QObject::destroyed, tlsBackend, [] { + const QMutexLocker locker(&backendMutex); + tlsBackend = nullptr; + }, + Qt::DirectConnection); + } + return tlsBackend; +} + +/*! + \internal +*/ +QSslSocket::SslMode QSslSocketPrivate::tlsMode() const +{ + return mode; +} + +/*! + \internal +*/ +bool QSslSocketPrivate::isRootsOnDemandAllowed() const +{ + return allowRootCertOnDemandLoading; +} + +/*! + \internal +*/ +QString QSslSocketPrivate::verificationName() const +{ + return verificationPeerName; +} + +/*! + \internal +*/ +QString QSslSocketPrivate::tlsHostName() const +{ + return hostName; +} + +QTcpSocket *QSslSocketPrivate::plainTcpSocket() const +{ + return plainSocket; +} + +/*! + \internal +*/ +QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates() +{ + if (const auto *tlsBackend = tlsBackendInUse()) + return tlsBackend->systemCaCertificates(); + return {}; } QT_END_NAMESPACE |