summaryrefslogtreecommitdiffstats
path: root/src/plugins/tls/openssl/qtls_openssl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/tls/openssl/qtls_openssl.cpp')
-rw-r--r--src/plugins/tls/openssl/qtls_openssl.cpp116
1 files changed, 63 insertions, 53 deletions
diff --git a/src/plugins/tls/openssl/qtls_openssl.cpp b/src/plugins/tls/openssl/qtls_openssl.cpp
index 569e1d9c84..57d09a649b 100644
--- a/src/plugins/tls/openssl/qtls_openssl.cpp
+++ b/src/plugins/tls/openssl/qtls_openssl.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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 "qsslsocket_openssl_symbols_p.h"
#include "qx509_openssl_p.h"
@@ -60,6 +24,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
namespace {
QSsl::AlertLevel tlsAlertLevel(int value)
@@ -83,9 +49,9 @@ QSsl::AlertLevel tlsAlertLevel(int value)
QString tlsAlertDescription(int value)
{
- QString description = QLatin1String(q_SSL_alert_desc_string_long(value));
+ QString description = QLatin1StringView(q_SSL_alert_desc_string_long(value));
if (!description.size())
- description = QLatin1String("no description provided");
+ description = "no description provided"_L1;
return description;
}
@@ -126,7 +92,7 @@ QSslCertificate findCertificateToFetch(const QList<QSslError> &tlsErrors, bool c
if (checkAIA) {
const auto extensions = certToFetch.extensions();
for (const auto &ext : extensions) {
- if (ext.oid() == QStringLiteral("1.3.6.1.5.5.7.1.1")) // See RFC 4325
+ if (ext.oid() == u"1.3.6.1.5.5.7.1.1") // See RFC 4325
return certToFetch;
}
//The only reason we check this extensions is because an application set trusted
@@ -169,9 +135,25 @@ int q_X509Callback(int ok, X509_STORE_CTX *ctx)
// To retrieve this pointer the X509_STORE_CTX_get_ex_data() function can be
// used with the correct index."
const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
- + TlsCryptographOpenSSL::errorOffsetInExData;
- if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx())))
+ + TlsCryptographOpenSSL::errorOffsetInExData;
+ if (SSL *ssl = static_cast<SSL *>(q_X509_STORE_CTX_get_ex_data(
+ ctx, q_SSL_get_ex_data_X509_STORE_CTX_idx()))) {
+
+ // We may be in a renegotiation, check if we are inside a call to SSL_read:
+ const auto tlsOffset = QTlsBackendOpenSSL::s_indexForSSLExtraData
+ + TlsCryptographOpenSSL::socketOffsetInExData;
+ auto tls = static_cast<TlsCryptographOpenSSL *>(q_SSL_get_ex_data(ssl, tlsOffset));
+ Q_ASSERT(tls);
+ if (tls->isInSslRead()) {
+ // We are in a renegotiation, make a note of this for later.
+ // We'll check that the certificate is the same as the one we got during
+ // the initial handshake
+ tls->setRenegotiated(true);
+ return 1;
+ }
+
errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
+ }
}
if (!errors) {
@@ -479,7 +461,7 @@ bool qt_OCSP_certificate_match(OCSP_SINGLERESP *singleResponse, X509 *peerCert,
const QSharedPointer<OCSP_CERTID> guard(recreatedId, q_OCSP_CERTID_free);
if (q_OCSP_id_cmp(const_cast<OCSP_CERTID *>(certId), recreatedId)) {
- qDebug(lcTlsBackend, "Certificate ID mismatch");
+ qCDebug(lcTlsBackend, "Certificate ID mismatch");
return false;
}
// Bingo!
@@ -508,7 +490,7 @@ void TlsCryptographOpenSSL::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
handshakeInterrupted = false;
fetchAuthorityInformation = false;
- caToFetch = QSslCertificate{};
+ caToFetch.reset();
}
void TlsCryptographOpenSSL::checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext)
@@ -595,7 +577,7 @@ bool TlsCryptographOpenSSL::startHandshake()
auto configuration = q->sslConfiguration();
if (!errorsReportedFromCallback) {
const auto &peerCertificateChain = configuration.peerCertificateChain();
- for (const auto &currentError : qAsConst(lastErrors)) {
+ for (const auto &currentError : std::as_const(lastErrors)) {
emit q->peerVerifyError(QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(currentError.code,
peerCertificateChain.value(currentError.depth)));
if (q->state() != QAbstractSocket::ConnectedState)
@@ -715,7 +697,7 @@ bool TlsCryptographOpenSSL::startHandshake()
// Translate errors from the error list into QSslErrors.
errors.reserve(errors.size() + errorList.size());
- for (const auto &error : qAsConst(errorList))
+ for (const auto &error : std::as_const(errorList))
errors << X509CertificateOpenSSL::openSSLErrorToQSslError(error.code, peerCertificateChain.value(error.depth));
if (!errors.isEmpty()) {
@@ -767,7 +749,7 @@ void TlsCryptographOpenSSL::enableHandshakeContinuation()
void TlsCryptographOpenSSL::cancelCAFetch()
{
fetchAuthorityInformation = false;
- caToFetch = QSslCertificate{};
+ caToFetch.reset();
}
void TlsCryptographOpenSSL::continueHandshake()
@@ -806,7 +788,7 @@ void TlsCryptographOpenSSL::continueHandshake()
debugLineClientRandom.append(masterKey.toHex().toUpper());
debugLineClientRandom.append("\n");
- QString sslKeyFile = QDir::tempPath() + QLatin1String("/qt-ssl-keys");
+ QString sslKeyFile = QDir::tempPath() + "/qt-ssl-keys"_L1;
QFile file(sslKeyFile);
if (!file.open(QIODevice::Append))
qCWarning(lcTlsBackend) << "could not open file" << sslKeyFile << "for appending";
@@ -1047,7 +1029,25 @@ void TlsCryptographOpenSSL::transmit()
break;
}
// Don't use SSL_pending(). It's very unreliable.
+ inSslRead = true;
readBytes = q_SSL_read(ssl, buffer.reserve(bytesToRead), bytesToRead);
+ inSslRead = false;
+ if (renegotiated) {
+ renegotiated = false;
+ X509 *x509 = q_SSL_get_peer_certificate(ssl);
+ const auto peerCertificate =
+ QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
+ // Fail the renegotiate if the certificate has changed, else: continue.
+ if (peerCertificate != q->peerCertificate()) {
+ const ScopedBool bg(inSetAndEmitError, true);
+ setErrorAndEmit(
+ d, QAbstractSocket::RemoteHostClosedError,
+ QSslSocket::tr(
+ "TLS certificate unexpectedly changed during renegotiation!"));
+ q->abort();
+ return;
+ }
+ }
if (readBytes > 0) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << "TlsCryptographOpenSSL::transmit: decrypted" << readBytes << "bytes";
@@ -1726,11 +1726,11 @@ unsigned TlsCryptographOpenSSL::pskClientTlsCallback(const char *hint, char *ide
return 0;
// Copy data back into OpenSSL
- const int identityLength = qMin(authenticator.identity().length(), authenticator.maximumIdentityLength());
+ const int identityLength = qMin(authenticator.identity().size(), authenticator.maximumIdentityLength());
std::memcpy(identity, authenticator.identity().constData(), identityLength);
identity[identityLength] = 0;
- const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
+ const int pskLength = qMin(authenticator.preSharedKey().size(), authenticator.maximumPreSharedKeyLength());
std::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
return pskLength;
}
@@ -1752,11 +1752,21 @@ unsigned TlsCryptographOpenSSL::pskServerTlsCallback(const char *identity, unsig
return 0;
// Copy data back into OpenSSL
- const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
+ const int pskLength = qMin(authenticator.preSharedKey().size(), authenticator.maximumPreSharedKeyLength());
std::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
return pskLength;
}
+bool TlsCryptographOpenSSL::isInSslRead() const
+{
+ return inSslRead;
+}
+
+void TlsCryptographOpenSSL::setRenegotiated(bool renegotiated)
+{
+ this->renegotiated = renegotiated;
+}
+
#ifdef Q_OS_WIN
void TlsCryptographOpenSSL::fetchCaRootForCert(const QSslCertificate &cert)
@@ -1793,7 +1803,7 @@ void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate t
Q_ASSERT(q);
//Done, fetched already:
- caToFetch = QSslCertificate{};
+ caToFetch.reset();
if (fetchAuthorityInformation) {
if (!q->sslConfiguration().caCertificates().contains(trustedRoot))