Merge "Convert QSslSocket(Backend)Private into plugin"
This commit is contained in:
commit
fc52acf621
@ -43,10 +43,9 @@ qt_internal_add_module(Network
|
||||
socket/qudpsocket.cpp socket/qudpsocket.h
|
||||
ssl/qasn1element.cpp ssl/qasn1element_p.h
|
||||
ssl/qpassworddigestor.cpp ssl/qpassworddigestor.h
|
||||
ssl/qssl.cpp ssl/qssl.h ssl/qssl_p.h ssl/qtls_utils_p.h
|
||||
ssl/qssl.cpp ssl/qssl.h ssl/qssl_p.h
|
||||
ssl/qsslcertificate.cpp ssl/qsslcertificate.h ssl/qsslcertificate_p.h
|
||||
ssl/qsslcertificateextension.cpp ssl/qsslcertificateextension.h ssl/qsslcertificateextension_p.h
|
||||
ssl/qtls_utils_p.h
|
||||
ssl/qtlsbackend.cpp ssl/qtlsbackend_p.h
|
||||
ssl/qtlsbackend_cert.cpp ssl/qtlsbackend_cert_p.h
|
||||
ssl/qx509_base.cpp ssl/qx509_base_p.h
|
||||
@ -331,7 +330,8 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_ssl
|
||||
qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
|
||||
SOURCES
|
||||
ssl/qsslsocket_qt.cpp
|
||||
ssl/qsslsocket_schannel.cpp ssl/qsslsocket_schannel_p.h
|
||||
ssl/qwincrypt_p.h
|
||||
ssl/qtls_schannel.cpp ssl/qtls_schannel_p.h
|
||||
ssl/qtlsbackend_schannel_p.h
|
||||
ssl/qtlskey_generic.cpp ssl/qtlskey_generic_p.h
|
||||
ssl/qtlskey_schannel.cpp ssl/qtlskey_schannel_p.h
|
||||
@ -345,7 +345,7 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_s
|
||||
|
||||
qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FEATURE_ssl
|
||||
SOURCES
|
||||
ssl/qsslsocket_mac.cpp ssl/qsslsocket_mac_p.h
|
||||
ssl/qtls_st.cpp ssl/qtls_st_p.h
|
||||
ssl/qsslsocket_mac_shared.cpp
|
||||
ssl/qsslsocket_qt.cpp
|
||||
ssl/qtlskey_generic.cpp ssl/qtlskey_generic_p.h
|
||||
@ -364,8 +364,9 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_openssl AND QT_FEATURE_ss
|
||||
SOURCES
|
||||
ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h
|
||||
ssl/qssldiffiehellmanparameters_openssl.cpp
|
||||
ssl/qsslsocket_openssl.cpp ssl/qsslsocket_openssl_p.h
|
||||
ssl/qopenssl.cpp ssl/qopenssl_p.h
|
||||
ssl/qsslsocket_openssl_symbols.cpp ssl/qsslsocket_openssl_symbols_p.h
|
||||
ssl/qtls_openssl.cpp ssl/qtls_openssl_p.h
|
||||
ssl/qtlskey_openssl.cpp ssl/qtlskey_openssl_p.h
|
||||
ssl/qtlsbackend_openssl.cpp ssl/qtlsbackend_openssl_p.h
|
||||
ssl/qx509_openssl.cpp ssl/qx509_openssl_p.h
|
||||
|
@ -55,4 +55,6 @@
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include <QtNetwork/private/qtnetwork-config_p.h>
|
||||
|
||||
#define Q_NETWORK_PRIVATE_EXPORT Q_NETWORK_EXPORT
|
||||
|
||||
#endif // QTNETWORKGLOBAL_P_H
|
||||
|
@ -44,7 +44,6 @@
|
||||
|
||||
#include "qsslpresharedkeyauthenticator_p.h"
|
||||
#include "qsslsocket_openssl_symbols_p.h"
|
||||
#include "qsslsocket_openssl_p.h"
|
||||
#include "qsslcertificate_p.h"
|
||||
#include "qdtls_openssl_p.h"
|
||||
#include "qx509_openssl_p.h"
|
||||
@ -198,7 +197,7 @@ extern "C" int q_generate_cookie_callback(SSL *ssl, unsigned char *dst,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *generic = q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData);
|
||||
void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData);
|
||||
if (!generic) {
|
||||
qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, cannot generate cookie");
|
||||
return 0;
|
||||
@ -252,7 +251,7 @@ extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *generic = q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData);
|
||||
void *generic = q_SSL_get_ex_data(ssl, QTlsBackendOpenSSL::s_indexForSSLExtraData);
|
||||
if (!generic) {
|
||||
qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, handshake failure");
|
||||
return 0;
|
||||
@ -273,7 +272,7 @@ extern "C" unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *iden
|
||||
unsigned max_psk_len)
|
||||
{
|
||||
auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
|
||||
QSslSocketBackendPrivate::s_indexForSSLExtraData));
|
||||
QTlsBackendOpenSSL::s_indexForSSLExtraData));
|
||||
if (!dtls)
|
||||
return 0;
|
||||
|
||||
@ -285,7 +284,7 @@ extern "C" unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsign
|
||||
unsigned max_psk_len)
|
||||
{
|
||||
auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
|
||||
QSslSocketBackendPrivate::s_indexForSSLExtraData));
|
||||
QTlsBackendOpenSSL::s_indexForSSLExtraData));
|
||||
if (!dtls)
|
||||
return 0;
|
||||
|
||||
@ -693,7 +692,7 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
|
||||
}
|
||||
|
||||
const int set = q_SSL_set_ex_data(newConnection.data(),
|
||||
QSslSocketBackendPrivate::s_indexForSSLExtraData,
|
||||
QTlsBackendOpenSSL::s_indexForSSLExtraData,
|
||||
this);
|
||||
|
||||
if (set != 1 && configurationCopy->peerVerifyMode != QSslSocket::VerifyNone) {
|
||||
@ -815,7 +814,7 @@ bool QDtlsClientVerifierOpenSSL::verifyClient(QUdpSocket *socket, const QByteArr
|
||||
const int ret = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
|
||||
if (ret < 0) {
|
||||
// Since 1.1 - it's a fatal error (not so in 1.0.2 for non-blocking socket)
|
||||
setDtlsError(QDtlsError::TlsFatalError, QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
setDtlsError(QDtlsError::TlsFatalError, QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1031,7 +1030,7 @@ bool QDtlsPrivateOpenSSL::continueHandshake(QUdpSocket *socket, const QByteArray
|
||||
default:
|
||||
storePeerCertificates();
|
||||
setDtlsError(QDtlsError::TlsFatalError,
|
||||
QSslSocketBackendPrivate::msgErrorsDuringHandshake());
|
||||
QTlsBackendOpenSSL::msgErrorsDuringHandshake());
|
||||
dtls.reset();
|
||||
handshakeState = QDtls::HandshakeNotStarted;
|
||||
return false;
|
||||
@ -1192,7 +1191,7 @@ qint64 QDtlsPrivateOpenSSL::writeDatagramEncrypted(QUdpSocket *socket,
|
||||
// DTLSTODO: we don't know yet what to do. Tests needed - probably,
|
||||
// some errors can be just ignored (it's UDP, not TCP after all).
|
||||
// Unlike QSslSocket we do not abort though.
|
||||
QString description(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
QString description(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) {
|
||||
setDtlsError(QDtlsError::UnderlyingSocketError, socket->errorString());
|
||||
} else {
|
||||
@ -1258,7 +1257,7 @@ QByteArray QDtlsPrivateOpenSSL::decryptDatagram(QUdpSocket *socket, const QByteA
|
||||
default:
|
||||
setDtlsError(QDtlsError::TlsNonFatalError,
|
||||
QDtls::tr("Error while reading: %1")
|
||||
.arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()));
|
||||
.arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
|
||||
return dgram;
|
||||
}
|
||||
}
|
||||
@ -1276,15 +1275,10 @@ unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity
|
||||
if (hint) {
|
||||
identityHint.clear();
|
||||
identityHint.append(hint);
|
||||
// From the original code in QSslSocket:
|
||||
// "it's NULL terminated, but do not include the NULL" == this fromRawData(ptr/size).
|
||||
authenticator.d->identityHint = QByteArray::fromRawData(identityHint.constData(),
|
||||
int(std::strlen(hint)));
|
||||
}
|
||||
|
||||
authenticator.d->maximumIdentityLength = int(max_identity_len) - 1; // needs to be NULL terminated
|
||||
authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
|
||||
|
||||
QTlsBackend::setupClientPskAuth(&authenticator, hint ? identityHint.constData() : nullptr,
|
||||
hint ? std::strlen(hint) : 0, max_identity_len, max_psk_len);
|
||||
pskAuthenticator.swap(authenticator);
|
||||
}
|
||||
|
||||
@ -1314,11 +1308,8 @@ unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned c
|
||||
{
|
||||
QSslPreSharedKeyAuthenticator authenticator;
|
||||
// Fill in some read-only fields (for the user)
|
||||
authenticator.d->identityHint = dtlsConfiguration.preSharedKeyIdentityHint;
|
||||
authenticator.d->identity = identity;
|
||||
authenticator.d->maximumIdentityLength = 0; // user cannot set an identity
|
||||
authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
|
||||
|
||||
QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint,
|
||||
max_psk_len);
|
||||
pskAuthenticator.swap(authenticator);
|
||||
}
|
||||
|
||||
@ -1367,7 +1358,7 @@ bool QDtlsPrivateOpenSSL::verifyPeer()
|
||||
name = dtls.udpSocket->peerName();
|
||||
}
|
||||
|
||||
if (!QSslSocketPrivate::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
|
||||
if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
|
||||
errors << QSslError(QSslError::HostNameMismatch, dtlsConfiguration.peerCertificate);
|
||||
}
|
||||
|
||||
@ -1418,9 +1409,10 @@ void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
|
||||
{
|
||||
Q_ASSERT(dtls.tlsConnection.data());
|
||||
|
||||
const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data());
|
||||
sessionCipher = cipher ? QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher)
|
||||
: QSslCipher();
|
||||
if (const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data()))
|
||||
sessionCipher = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
|
||||
else
|
||||
sessionCipher = {};
|
||||
|
||||
// Note: cipher's protocol version will be reported as either TLS 1.0 or
|
||||
// TLS 1.2, that's how it's set by OpenSSL (and that's what they are?).
|
||||
|
@ -47,11 +47,12 @@
|
||||
#include <openssl/ossl_typ.h>
|
||||
|
||||
#include "qtlsbackend_openssl_p.h"
|
||||
#include "qtls_openssl_p.h"
|
||||
#include "qdtls_base_p.h"
|
||||
#include "qdtls_p.h"
|
||||
|
||||
#include <private/qsslcontext_openssl_p.h>
|
||||
#include <private/qsslsocket_openssl_p.h>
|
||||
#include <private/qopenssl_p.h>
|
||||
|
||||
#include <QtNetwork/qsslpresharedkeyauthenticator.h>
|
||||
#include <QtNetwork/qhostaddress.h>
|
||||
@ -185,7 +186,6 @@ private:
|
||||
QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
|
||||
|
||||
public:
|
||||
|
||||
unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
|
||||
unsigned char *psk, unsigned max_psk_len);
|
||||
unsigned pskServerCallback(const char *identity, unsigned char *psk,
|
||||
|
@ -72,6 +72,10 @@ enum class QOcspRevocationReason
|
||||
RemoveFromCRL
|
||||
};
|
||||
|
||||
namespace QTlsPrivate {
|
||||
class TlsCryptographOpenSSL;
|
||||
}
|
||||
|
||||
class QOcspResponse;
|
||||
Q_NETWORK_EXPORT size_t qHash(const QOcspResponse &response, size_t seed = 0) noexcept;
|
||||
|
||||
@ -99,7 +103,7 @@ public:
|
||||
private:
|
||||
bool isEqual(const QOcspResponse &other) const;
|
||||
|
||||
friend class QSslSocketBackendPrivate;
|
||||
friend class QTlsPrivate::TlsCryptographOpenSSL;
|
||||
friend bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
|
||||
{ return lhs.isEqual(rhs); }
|
||||
friend bool operator!=(const QOcspResponse &lhs, const QOcspResponse &rhs)
|
||||
|
71
src/network/ssl/qopenssl.cpp
Normal file
71
src/network/ssl/qopenssl.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Copyright (C) 2014 Governikus GmbH & Co. KG
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
**
|
||||
** In addition, as a special exception, the copyright holders listed above give
|
||||
** permission to link the code of its release of Qt with the OpenSSL project's
|
||||
** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the
|
||||
** same license as the original version), and distribute the linked executables.
|
||||
**
|
||||
** You must comply with the GNU General Public License version 2 in all
|
||||
** respects for all of the code used other than the "OpenSSL" code. If you
|
||||
** modify this file, you may extend this exception to your version of the file,
|
||||
** but you are not obligated to do so. If you do not wish to do so, delete
|
||||
** this exception statement from your version of this file.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtlsbackend_openssl_p.h"
|
||||
#include "qopenssl_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_GLOBAL_STATIC(QTlsBackendOpenSSL, backendOpenSsl)
|
||||
|
||||
void QSslSocketPrivate::registerAdHocFactory()
|
||||
{
|
||||
// TLSTODO: this is a temporary solution, waiting for
|
||||
// backends to move to ... plugins.
|
||||
if (!backendOpenSsl())
|
||||
qCWarning(lcSsl, "Failed to create backend factory");
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -67,10 +67,9 @@
|
||||
//
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
#include "qsslsocket_p.h"
|
||||
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include "qsslsocket_p.h"
|
||||
#include "qsslcipher.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <qt_windows.h>
|
||||
@ -82,6 +81,8 @@
|
||||
#endif
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
// This file is included in several *.cpp files and provides different
|
||||
// openssl declarations where they are needed.
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
@ -100,92 +101,17 @@
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/tls1.h>
|
||||
|
||||
#if QT_CONFIG(opensslv11)
|
||||
#include <openssl/dh.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct QSslErrorEntry {
|
||||
int code;
|
||||
int depth;
|
||||
int code = 0;
|
||||
int depth = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
|
||||
|
||||
class QSslSocketBackendPrivate : public QSslSocketPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QSslSocket)
|
||||
public:
|
||||
QSslSocketBackendPrivate();
|
||||
virtual ~QSslSocketBackendPrivate();
|
||||
|
||||
// SSL context
|
||||
bool initSslContext();
|
||||
void destroySslContext();
|
||||
SSL *ssl;
|
||||
BIO *readBio;
|
||||
BIO *writeBio;
|
||||
SSL_SESSION *session;
|
||||
QList<QSslErrorEntry> errorList;
|
||||
static int s_indexForSSLExtraData; // index used in SSL_get_ex_data to get the matching QSslSocketBackendPrivate
|
||||
enum ExDataOffset {
|
||||
errorOffsetInExData = 1,
|
||||
socketOffsetInExData = 2
|
||||
};
|
||||
|
||||
bool inSetAndEmitError = false;
|
||||
|
||||
// Platform specific functions
|
||||
void startClientEncryption() override;
|
||||
void startServerEncryption() override;
|
||||
void transmit() override;
|
||||
bool startHandshake();
|
||||
void disconnectFromHost() override;
|
||||
void disconnected() override;
|
||||
QSslCipher sessionCipher() const override;
|
||||
QSsl::SslProtocol sessionProtocol() const override;
|
||||
void continueHandshake() override;
|
||||
bool checkSslErrors();
|
||||
void storePeerCertificates();
|
||||
int handleNewSessionTicket(SSL *context);
|
||||
unsigned int tlsPskClientCallback(const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
|
||||
unsigned int tlsPskServerCallback(const char *identity, unsigned char *psk, unsigned int max_psk_len);
|
||||
#ifdef Q_OS_WIN
|
||||
void fetchCaRootForCert(const QSslCertificate &cert);
|
||||
void _q_caRootLoaded(QSslCertificate,QSslCertificate) override;
|
||||
#endif
|
||||
|
||||
#if QT_CONFIG(ocsp)
|
||||
bool checkOcspStatus();
|
||||
#endif
|
||||
|
||||
void alertMessageSent(int encoded);
|
||||
void alertMessageReceived(int encoded);
|
||||
|
||||
int emitErrorFromCallback(X509_STORE_CTX *ctx);
|
||||
void trySendFatalAlert();
|
||||
|
||||
bool pendingFatalAlert = false;
|
||||
bool errorsReportedFromCallback = false;
|
||||
|
||||
// This decription will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription)
|
||||
QString ocspErrorDescription;
|
||||
// These will go to sslErrors()
|
||||
QList<QSslError> ocspErrors;
|
||||
QByteArray ocspResponseDer;
|
||||
|
||||
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
|
||||
static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher);
|
||||
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName);
|
||||
static QList<QSslError> verify(const QList<QSslCertificate> &cas, const QList<QSslCertificate> &certificateChain,
|
||||
const QString &hostName);
|
||||
static QString getErrorsFromOpenSsl();
|
||||
static void logAndClearErrorQueue();
|
||||
static QString msgErrorsDuringHandshake();
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
@ -153,8 +153,6 @@ public:
|
||||
|
||||
private:
|
||||
QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
|
||||
friend class QSslCertificatePrivate;
|
||||
friend class QSslSocketBackendPrivate;
|
||||
friend class QTlsBackend;
|
||||
|
||||
friend Q_NETWORK_EXPORT size_t qHash(const QSslCertificate &key, size_t seed) noexcept;
|
||||
|
@ -71,10 +71,8 @@ public:
|
||||
~QSslCertificatePrivate();
|
||||
|
||||
QList<QSslCertificateExtension> extensions() const;
|
||||
static bool isBlacklisted(const QSslCertificate &certificate);
|
||||
static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
|
||||
|
||||
friend class QSslSocketBackendPrivate;
|
||||
Q_NETWORK_PRIVATE_EXPORT static bool isBlacklisted(const QSslCertificate &certificate);
|
||||
Q_NETWORK_PRIVATE_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
|
||||
|
||||
QAtomicInt ref;
|
||||
std::unique_ptr<QTlsPrivate::X509Certificate> backend;
|
||||
|
@ -85,7 +85,7 @@ public:
|
||||
private:
|
||||
// ### Qt 7: make implicitly shared
|
||||
std::unique_ptr<QSslCipherPrivate> d;
|
||||
friend class QSslSocketBackendPrivate;
|
||||
friend class QTlsBackend;
|
||||
};
|
||||
|
||||
Q_DECLARE_SHARED(QSslCipher)
|
||||
|
@ -201,7 +201,6 @@ public:
|
||||
private:
|
||||
friend class QSslSocket;
|
||||
friend class QSslConfigurationPrivate;
|
||||
friend class QSslSocketBackendPrivate;
|
||||
friend class QSslContext;
|
||||
friend class QDtlsBasePrivate;
|
||||
friend class dtlsopenssl::DtlsState;
|
||||
|
@ -79,7 +79,7 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSslConfigurationPrivate: public QSharedData
|
||||
class Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate: public QSharedData
|
||||
{
|
||||
public:
|
||||
QSslConfigurationPrivate()
|
||||
@ -114,11 +114,11 @@ public:
|
||||
bool allowRootCertOnDemandLoading;
|
||||
bool peerSessionShared;
|
||||
|
||||
Q_AUTOTEST_EXPORT static bool peerSessionWasShared(const QSslConfiguration &configuration);
|
||||
static bool peerSessionWasShared(const QSslConfiguration &configuration);
|
||||
|
||||
QSsl::SslOptions sslOptions;
|
||||
|
||||
Q_AUTOTEST_EXPORT static const QSsl::SslOptions defaultSslOptions;
|
||||
static const QSsl::SslOptions defaultSslOptions;
|
||||
|
||||
QList<QSslEllipticCurve> ellipticCurves;
|
||||
|
||||
|
@ -43,12 +43,13 @@
|
||||
#include <QtNetwork/qsslsocket.h>
|
||||
#include <QtNetwork/qssldiffiehellmanparameters.h>
|
||||
|
||||
#include "private/qopenssl_p.h"
|
||||
#include "private/qssl_p.h"
|
||||
#include "private/qsslsocket_p.h"
|
||||
#include "private/qsslcontext_openssl_p.h"
|
||||
#include "private/qsslsocket_openssl_p.h"
|
||||
#include "private/qsslsocket_openssl_symbols_p.h"
|
||||
#include "private/qssldiffiehellmanparameters_p.h"
|
||||
#include "private/qtlsbackend_openssl_p.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -61,10 +62,17 @@ Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
|
||||
*forceSecurityLevel() = true;
|
||||
}
|
||||
|
||||
// defined in qsslsocket_openssl.cpp:
|
||||
extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
|
||||
namespace QTlsPrivate
|
||||
{
|
||||
// These callback functions are defined in qtls_openssl.cpp.
|
||||
extern "C" int q_X509Callback(int ok, X509_STORE_CTX *ctx);
|
||||
extern "C" int q_X509CallbackDirect(int ok, X509_STORE_CTX *ctx);
|
||||
extern QString getErrorsFromOpenSsl();
|
||||
|
||||
#if QT_CONFIG(ocsp)
|
||||
extern "C" int qt_OCSP_status_server_callback(SSL *ssl, void *);
|
||||
#endif // ocsp
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
#if QT_CONFIG(dtls)
|
||||
// defined in qdtls_openssl.cpp:
|
||||
@ -82,9 +90,6 @@ extern "C" int q_verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
|
||||
extern "C" int q_ssl_sess_set_new_cb(SSL *context, SSL_SESSION *session);
|
||||
#endif // TLS1_3_VERSION
|
||||
|
||||
// Defined in qsslsocket.cpp
|
||||
QList<QSslCipher> q_getDefaultDtlsCiphers();
|
||||
|
||||
static inline QString msgErrorSettingBackendConfig(const QString &why)
|
||||
{
|
||||
return QSslSocket::tr("Error when setting the OpenSSL configuration (%1)").arg(why);
|
||||
@ -95,6 +100,56 @@ static inline QString msgErrorSettingEllipticCurves(const QString &why)
|
||||
return QSslSocket::tr("Error when setting the elliptic curves (%1)").arg(why);
|
||||
}
|
||||
|
||||
long QSslContext::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
|
||||
{
|
||||
long options;
|
||||
switch (protocol) {
|
||||
case QSsl::SecureProtocols:
|
||||
case QSsl::TlsV1_0OrLater:
|
||||
options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
|
||||
break;
|
||||
case QSsl::TlsV1_1OrLater:
|
||||
options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;
|
||||
break;
|
||||
case QSsl::TlsV1_2OrLater:
|
||||
options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
|
||||
break;
|
||||
case QSsl::TlsV1_3OrLater:
|
||||
options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2;
|
||||
break;
|
||||
default:
|
||||
options = SSL_OP_ALL;
|
||||
}
|
||||
|
||||
// This option is disabled by default, so we need to be able to clear it
|
||||
if (sslOptions & QSsl::SslOptionDisableEmptyFragments)
|
||||
options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
|
||||
else
|
||||
options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
|
||||
|
||||
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
||||
// This option is disabled by default, so we need to be able to clear it
|
||||
if (sslOptions & QSsl::SslOptionDisableLegacyRenegotiation)
|
||||
options &= ~SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
|
||||
else
|
||||
options |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
if (sslOptions & QSsl::SslOptionDisableSessionTickets)
|
||||
options |= SSL_OP_NO_TICKET;
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
if (sslOptions & QSsl::SslOptionDisableCompression)
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
|
||||
if (!(sslOptions & QSsl::SslOptionDisableServerCipherPreference))
|
||||
options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
QSslContext::QSslContext()
|
||||
: ctx(nullptr),
|
||||
pkey(nullptr),
|
||||
@ -130,6 +185,12 @@ QSharedPointer<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::Ssl
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
QSharedPointer<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
|
||||
bool allowRootCertOnDemandLoading)
|
||||
{
|
||||
return sharedFromConfiguration(mode, privConfiguration, allowRootCertOnDemandLoading);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
|
||||
@ -335,7 +396,7 @@ init_context:
|
||||
}
|
||||
|
||||
sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg(
|
||||
unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QSslSocketBackendPrivate::getErrorsFromOpenSsl()
|
||||
unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QTlsBackendOpenSSL::getErrorsFromOpenSsl()
|
||||
);
|
||||
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||
return;
|
||||
@ -438,7 +499,7 @@ init_context:
|
||||
}
|
||||
|
||||
// Enable bug workarounds.
|
||||
long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
|
||||
const long options = setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
|
||||
q_SSL_CTX_set_options(sslContext->ctx, options);
|
||||
|
||||
// Tell OpenSSL to release memory early
|
||||
@ -464,13 +525,13 @@ init_context:
|
||||
// Initialize ciphers
|
||||
QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
|
||||
if (ciphers.isEmpty())
|
||||
ciphers = isDtls ? q_getDefaultDtlsCiphers() : QSslSocketPrivate::defaultCiphers();
|
||||
ciphers = isDtls ? QTlsBackend::defaultDtlsCiphers() : QTlsBackend::defaultCiphers();
|
||||
|
||||
const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
|
||||
|
||||
if (preTls13Ciphers.size()) {
|
||||
if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, preTls13Ciphers.data())) {
|
||||
sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||
return;
|
||||
}
|
||||
@ -480,7 +541,7 @@ init_context:
|
||||
#ifdef TLS1_3_VERSION
|
||||
if (tls13Ciphers.size()) {
|
||||
if (!q_SSL_CTX_set_ciphersuites(sslContext->ctx, tls13Ciphers.data())) {
|
||||
sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||
return;
|
||||
}
|
||||
@ -513,7 +574,7 @@ init_context:
|
||||
}
|
||||
}
|
||||
|
||||
if (QSslSocketPrivate::s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
|
||||
if (QSslSocketPrivate::rootCertOnDemandLoadingSupported() && allowRootCertOnDemandLoading) {
|
||||
// tell OpenSSL the directories where to look up the root certs on demand
|
||||
const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
|
||||
int success = 1;
|
||||
@ -529,7 +590,7 @@ init_context:
|
||||
}
|
||||
#endif // OPENSSL_VERSION_MAJOR
|
||||
if (success != 1) {
|
||||
const auto qtErrors = QSslSocketBackendPrivate::getErrorsFromOpenSsl();
|
||||
const auto qtErrors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
|
||||
qCWarning(lcSsl) << "An error encountered while to set root certificates location:"
|
||||
<< qtErrors;
|
||||
}
|
||||
@ -545,7 +606,7 @@ init_context:
|
||||
|
||||
// Load certificate
|
||||
if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
|
||||
sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||
return;
|
||||
}
|
||||
@ -572,14 +633,14 @@ init_context:
|
||||
sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
|
||||
|
||||
if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, pkey)) {
|
||||
sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the certificate matches the private key.
|
||||
if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
|
||||
sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||
return;
|
||||
}
|
||||
@ -605,10 +666,10 @@ init_context:
|
||||
#if QT_CONFIG(dtls)
|
||||
isDtls ? dtlscallbacks::q_X509DtlsCallback :
|
||||
#endif // dtls
|
||||
q_X509Callback;
|
||||
QTlsPrivate::q_X509Callback;
|
||||
|
||||
if (!isDtls && configuration.handshakeMustInterruptOnError())
|
||||
verificationCallback = q_X509CallbackDirect;
|
||||
verificationCallback = QTlsPrivate::q_X509CallbackDirect;
|
||||
|
||||
auto verificationMode = SSL_VERIFY_PEER;
|
||||
if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
|
||||
@ -680,7 +741,7 @@ init_context:
|
||||
for (const auto &sslCurve : qcurves)
|
||||
curves.push_back(sslCurve.id);
|
||||
if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) {
|
||||
sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
||||
sslContext->errorStr = msgErrorSettingEllipticCurves(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||
return;
|
||||
}
|
||||
@ -690,10 +751,6 @@ init_context:
|
||||
applyBackendConfig(sslContext);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(ocsp)
|
||||
extern "C" int qt_OCSP_status_server_callback(SSL *ssl, void *); // Defined in qsslsocket_openssl.cpp.
|
||||
#endif // ocsp
|
||||
// static
|
||||
void QSslContext::applyBackendConfig(QSslContext *sslContext)
|
||||
{
|
||||
const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
|
||||
@ -706,7 +763,7 @@ void QSslContext::applyBackendConfig(QSslContext *sslContext)
|
||||
// This is our private, undocumented configuration option, existing only for
|
||||
// the purpose of testing OCSP status responses. We don't even check this
|
||||
// callback was set. If no - the test must fail.
|
||||
q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, qt_OCSP_status_server_callback);
|
||||
q_SSL_CTX_set_tlsext_status_cb(sslContext->ctx, QTlsPrivate::qt_OCSP_status_server_callback);
|
||||
if (conf.size() == 1)
|
||||
return;
|
||||
}
|
||||
|
@ -73,6 +73,9 @@ public:
|
||||
bool allowRootCertOnDemandLoading);
|
||||
static QSharedPointer<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
|
||||
bool allowRootCertOnDemandLoading);
|
||||
static QSharedPointer<QSslContext> sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
|
||||
bool allowRootCertOnDemandLoading);
|
||||
static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
|
||||
|
||||
QSslError::SslError error() const;
|
||||
QString errorString() const;
|
||||
|
@ -69,22 +69,22 @@ int q_DH_check(DH *dh, int *status)
|
||||
EVP_PKEY *key = q_EVP_PKEY_new();
|
||||
if (!key) {
|
||||
qCWarning(lcSsl, "EVP_PKEY_new failed");
|
||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||||
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||
return 0;
|
||||
}
|
||||
const auto keyDeleter = qScopeGuard([key](){
|
||||
q_EVP_PKEY_free(key);
|
||||
});
|
||||
if (!q_EVP_PKEY_set1_DH(key, dh)) {
|
||||
qCWarning(lcSsl, "EVP_PKEY_set1_DH failed");
|
||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||||
qCWarning(lcTlsBackend, "EVP_PKEY_set1_DH failed");
|
||||
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||
return 0;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
|
||||
if (!keyCtx) {
|
||||
qCWarning(lcSsl, "EVP_PKEY_CTX_new failed");
|
||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||||
qCWarning(lcTlsBackend, "EVP_PKEY_CTX_new failed");
|
||||
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||
return 0;
|
||||
}
|
||||
const auto ctxDeleter = qScopeGuard([keyCtx]{
|
||||
@ -92,7 +92,7 @@ int q_DH_check(DH *dh, int *status)
|
||||
});
|
||||
|
||||
const int result = q_EVP_PKEY_param_check(keyCtx);
|
||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||||
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||
// Note: unlike DH_check, we cannot obtain the 'status',
|
||||
// if the 'result' is 0 (actually the result is 1 only
|
||||
// if this 'status' was 0). We could probably check the
|
||||
|
@ -82,7 +82,6 @@ private:
|
||||
|
||||
friend class QSslContext;
|
||||
friend class QSslSocketPrivate;
|
||||
friend class QSslSocketBackendPrivate;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
|
||||
|
@ -94,8 +94,6 @@ public:
|
||||
|
||||
private:
|
||||
QExplicitlySharedDataPointer<QSslKeyPrivate> d;
|
||||
friend class QSslCertificate;
|
||||
friend class QSslSocketBackendPrivate;
|
||||
friend class QTlsBackend;
|
||||
};
|
||||
|
||||
|
@ -50,7 +50,6 @@ QT_REQUIRE_CONFIG(ssl);
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSslPreSharedKeyAuthenticatorPrivate;
|
||||
|
||||
class QSslPreSharedKeyAuthenticator
|
||||
{
|
||||
public:
|
||||
@ -76,8 +75,7 @@ public:
|
||||
private:
|
||||
Q_NETWORK_EXPORT bool isEqual(const QSslPreSharedKeyAuthenticator &other) const;
|
||||
|
||||
friend class QSslSocketBackendPrivate;
|
||||
friend class QDtlsPrivateOpenSSL;
|
||||
friend class QTlsBackend;
|
||||
|
||||
friend bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
|
||||
{ return lhs.isEqual(rhs); }
|
||||
|
@ -386,16 +386,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>
|
||||
@ -433,7 +425,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 +895,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 +1203,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 +1480,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 +1499,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 +1517,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 +1546,10 @@ long QSslSocket::sslLibraryBuildVersionNumber()
|
||||
*/
|
||||
QString QSslSocket::sslLibraryBuildVersionString()
|
||||
{
|
||||
return QSslSocketPrivate::sslLibraryBuildVersionString();
|
||||
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
|
||||
return tlsBackend->tlsLibraryBuildVersionString();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1857,7 +1862,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 +1920,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 +1989,8 @@ qint64 QSslSocket::writeData(const char *data, qint64 len)
|
||||
return len;
|
||||
}
|
||||
|
||||
bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
@ -1990,7 +1999,6 @@ QSslSocketPrivate::QSslSocketPrivate()
|
||||
, mode(QSslSocket::UnencryptedMode)
|
||||
, autoStartHandshake(false)
|
||||
, connectionEncrypted(false)
|
||||
, shutdown(false)
|
||||
, ignoreAllSslErrors(false)
|
||||
, readyReadEmittedPointer(nullptr)
|
||||
, allowRootCertOnDemandLoading(true)
|
||||
@ -1999,6 +2007,17 @@ QSslSocketPrivate::QSslSocketPrivate()
|
||||
, flushTriggered(false)
|
||||
{
|
||||
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2008,31 +2027,57 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2103,7 +2148,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 +2186,7 @@ void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QList<QSslCipher> q_getDefaultDtlsCiphers()
|
||||
QList<QSslCipher> QSslSocketPrivate::defaultDtlsCiphers()
|
||||
{
|
||||
QSslSocketPrivate::ensureInitialized();
|
||||
QMutexLocker locker(&globalData()->mutex);
|
||||
@ -2360,6 +2433,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 +2668,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,11 +2683,14 @@ 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++) {
|
||||
if (!ignoreErrorsList.contains(sslErrors.at(a))) {
|
||||
@ -2625,6 +2707,91 @@ bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
|
||||
return !doEmitSslError;
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
*/
|
||||
@ -2643,9 +2810,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);
|
||||
@ -2668,8 +2835,8 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize)
|
||||
//peek at data in the plain socket
|
||||
if (plainSocket)
|
||||
return ret + plainSocket->peek(maxSize - ret.length());
|
||||
else
|
||||
return QByteArray();
|
||||
|
||||
return QByteArray();
|
||||
} else {
|
||||
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
|
||||
return QTcpSocketPrivate::peek(maxSize);
|
||||
@ -2708,6 +2875,82 @@ bool QSslSocketPrivate::flush()
|
||||
return plainSocket && plainSocket->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
|
||||
*/
|
||||
@ -2716,6 +2959,14 @@ bool QSslSocketPrivate::rootCertOnDemandLoadingSupported()
|
||||
return s_loadRootCertsOnDemand;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QSslSocketPrivate::setRootCertOnDemandLoadingSupported(bool supported)
|
||||
{
|
||||
s_loadRootCertsOnDemand = supported;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
@ -2735,10 +2986,13 @@ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointer<QSslContext> sslContext)
|
||||
void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointer<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);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -2746,7 +3000,13 @@ void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointe
|
||||
*/
|
||||
QSharedPointer<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)
|
||||
@ -2852,6 +3112,61 @@ QTlsBackend *QSslSocketPrivate::tlsBackendInUse()
|
||||
return tlsBackend = QTlsBackend::findBackend(activeBackendName);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QSslSocket::SslMode QSslSocketPrivate::tlsMode() const
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QSslConfigurationPrivate &QSslSocketPrivate::privateConfiguration()
|
||||
{
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
|
||||
#include "moc_qsslsocket.cpp"
|
||||
|
@ -201,6 +201,7 @@ protected:
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(QSslSocket)
|
||||
Q_DISABLE_COPY_MOVE(QSslSocket)
|
||||
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_connectedSlot())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_hostFoundSlot())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_disconnectedSlot())
|
||||
@ -214,10 +215,6 @@ private:
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_flushWriteBuffer())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_resumeImplementation())
|
||||
#if defined(Q_OS_WIN) && !QT_CONFIG(schannel)
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_caRootLoaded(QSslCertificate,QSslCertificate))
|
||||
#endif
|
||||
friend class QSslSocketBackendPrivate;
|
||||
};
|
||||
|
||||
#endif // QT_NO_SSL
|
||||
|
@ -38,30 +38,22 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
//#define QSSLSOCKET_DEBUG
|
||||
//#define QT_DECRYPT_SSL_TRAFFIC
|
||||
#include "qsslcertificate.h"
|
||||
|
||||
#include "qssl_p.h"
|
||||
#include "qsslsocket.h"
|
||||
#include "qsslsocket_p.h"
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
# include "qsslsocket_openssl_p.h"
|
||||
# include "qsslsocket_openssl_symbols_p.h"
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
|
||||
#include "qsslcertificate_p.h"
|
||||
#include "qtlsbackend_p.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
# include <private/qcore_mac_p.h>
|
||||
#endif
|
||||
#include <private/qcore_mac_p.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
# include <Security/Security.h>
|
||||
#endif
|
||||
#include <CoreFoundation/CFArray.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -114,18 +106,17 @@ bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCWarning(lcSsl, "Error receiving trust for a CA certificate");
|
||||
qCWarning(lcTlsBackend, "Error receiving trust for a CA certificate");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
} // unnamed namespace
|
||||
#endif // Q_OS_MACOS
|
||||
|
||||
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
namespace QTlsPrivate {
|
||||
QList<QSslCertificate> systemCaCertificates()
|
||||
{
|
||||
ensureInitialized();
|
||||
|
||||
QList<QSslCertificate> systemCerts;
|
||||
// SecTrustSettingsCopyCertificates is not defined on iOS.
|
||||
#ifdef Q_OS_MACOS
|
||||
@ -152,5 +143,6 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
#endif
|
||||
return systemCerts;
|
||||
}
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -52,13 +52,15 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qsslsocket_openssl_p.h"
|
||||
#include "qsslsocket_p.h"
|
||||
#include <QtCore/QJniEnvironment>
|
||||
#include <QtCore/QJniObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData()
|
||||
namespace QTlsPrivate {
|
||||
|
||||
QList<QByteArray> fetchSslCertificateData()
|
||||
{
|
||||
QList<QByteArray> certificateData;
|
||||
|
||||
@ -86,4 +88,6 @@ QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData()
|
||||
return certificateData;
|
||||
}
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -69,7 +69,7 @@
|
||||
//
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
#include "qsslsocket_openssl_p.h"
|
||||
#include "qopenssl_p.h"
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if QT_CONFIG(ocsp)
|
||||
|
@ -55,59 +55,25 @@
|
||||
//
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <private/qtcpsocket_p.h>
|
||||
#include "qsslkey.h"
|
||||
#include "qsslconfiguration_p.h"
|
||||
|
||||
#include "qocspresponse.h"
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <private/qsslcontext_openssl_p.h>
|
||||
#else
|
||||
class QSslContext;
|
||||
#endif
|
||||
#include "qsslconfiguration_p.h"
|
||||
#include "qsslkey.h"
|
||||
#include "qtlsbackend_p.h"
|
||||
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qstringlist.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
|
||||
#include <private/qringbuffer_p.h>
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
#include <Security/SecCertificate.h>
|
||||
#include <CoreFoundation/CFArray.h>
|
||||
#elif defined(Q_OS_WIN)
|
||||
#include <QtCore/qt_windows.h>
|
||||
#include <memory>
|
||||
#include <wincrypt.h>
|
||||
#ifndef HCRYPTPROV_LEGACY
|
||||
#define HCRYPTPROV_LEGACY HCRYPTPROV
|
||||
#endif // !HCRYPTPROV_LEGACY
|
||||
#endif // Q_OS_WIN
|
||||
#include <QtCore/qstringlist.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
typedef CFDataRef (*PtrSecCertificateCopyData)(SecCertificateRef);
|
||||
typedef OSStatus (*PtrSecTrustSettingsCopyCertificates)(int, CFArrayRef*);
|
||||
typedef OSStatus (*PtrSecTrustCopyAnchorCertificates)(CFArrayRef*);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
|
||||
// Those are needed by both OpenSSL and Schannel back-ends on Windows:
|
||||
struct QHCertStoreDeleter {
|
||||
void operator()(HCERTSTORE store)
|
||||
{
|
||||
CertCloseStore(store, 0);
|
||||
}
|
||||
};
|
||||
|
||||
using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
|
||||
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
class QSslContext;
|
||||
class QTlsBackend;
|
||||
|
||||
class QSslSocketPrivate : public QTcpSocketPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QSslSocket)
|
||||
@ -122,14 +88,11 @@ public:
|
||||
QSslSocket::SslMode mode;
|
||||
bool autoStartHandshake;
|
||||
bool connectionEncrypted;
|
||||
bool shutdown;
|
||||
bool ignoreAllSslErrors;
|
||||
QList<QSslError> ignoreErrorsList;
|
||||
bool* readyReadEmittedPointer;
|
||||
|
||||
QSslConfigurationPrivate configuration;
|
||||
QList<QSslError> sslErrors;
|
||||
QSharedPointer<QSslContext> sslContextPointer;
|
||||
|
||||
// if set, this hostname is used for certificate validation instead of the hostname
|
||||
// that was used for connecting to.
|
||||
@ -140,16 +103,14 @@ public:
|
||||
static bool s_loadRootCertsOnDemand;
|
||||
|
||||
static bool supportsSsl();
|
||||
static long sslLibraryVersionNumber();
|
||||
static QString sslLibraryVersionString();
|
||||
static long sslLibraryBuildVersionNumber();
|
||||
static QString sslLibraryBuildVersionString();
|
||||
static void ensureInitialized();
|
||||
|
||||
static QList<QSslCipher> defaultCiphers();
|
||||
static QList<QSslCipher> defaultDtlsCiphers();
|
||||
static QList<QSslCipher> supportedCiphers();
|
||||
static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
|
||||
static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
|
||||
static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
|
||||
static void resetDefaultCiphers();
|
||||
|
||||
static QList<QSslEllipticCurve> supportedEllipticCurves();
|
||||
static void setDefaultSupportedEllipticCurves(const QList<QSslEllipticCurve> &curves);
|
||||
@ -160,19 +121,19 @@ public:
|
||||
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
||||
static void addDefaultCaCertificate(const QSslCertificate &cert);
|
||||
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
||||
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QSslCertificate &cert,
|
||||
const QString &peerName);
|
||||
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
|
||||
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
|
||||
|
||||
// The socket itself, including private slots.
|
||||
QTcpSocket *plainSocket;
|
||||
QTcpSocket *plainSocket = nullptr;
|
||||
void createPlainSocket(QIODevice::OpenMode openMode);
|
||||
static void pauseSocketNotifiers(QSslSocket*);
|
||||
static void resumeSocketNotifiers(QSslSocket*);
|
||||
Q_NETWORK_EXPORT static void pauseSocketNotifiers(QSslSocket*);
|
||||
Q_NETWORK_EXPORT static void resumeSocketNotifiers(QSslSocket*);
|
||||
// ### The 2 methods below should be made member methods once the QSslContext class is made public
|
||||
static void checkSettingSslContext(QSslSocket*, QSharedPointer<QSslContext>);
|
||||
static QSharedPointer<QSslContext> sslContext(QSslSocket *socket);
|
||||
bool isPaused() const;
|
||||
Q_NETWORK_EXPORT bool isPaused() const;
|
||||
Q_NETWORK_EXPORT void setPaused(bool p);
|
||||
bool bind(const QHostAddress &address, quint16, QAbstractSocket::BindMode) override;
|
||||
void _q_connectedSlot();
|
||||
void _q_hostFoundSlot();
|
||||
@ -187,62 +148,59 @@ public:
|
||||
void _q_flushWriteBuffer();
|
||||
void _q_flushReadBuffer();
|
||||
void _q_resumeImplementation();
|
||||
#if defined(Q_OS_WIN) && !QT_CONFIG(schannel)
|
||||
virtual void _q_caRootLoaded(QSslCertificate,QSslCertificate) = 0;
|
||||
#endif
|
||||
|
||||
static QList<QByteArray> unixRootCertDirectories(); // used also by QSslContext
|
||||
Q_NETWORK_PRIVATE_EXPORT static QList<QByteArray> unixRootCertDirectories(); // used also by QSslContext
|
||||
|
||||
virtual qint64 peek(char *data, qint64 maxSize) override;
|
||||
virtual QByteArray peek(qint64 maxSize) override;
|
||||
qint64 peek(char *data, qint64 maxSize) override;
|
||||
QByteArray peek(qint64 maxSize) override;
|
||||
bool flush() override;
|
||||
|
||||
// Platform specific functions
|
||||
virtual void startClientEncryption() = 0;
|
||||
virtual void startServerEncryption() = 0;
|
||||
virtual void transmit() = 0;
|
||||
virtual void disconnectFromHost() = 0;
|
||||
virtual void disconnected() = 0;
|
||||
virtual QSslCipher sessionCipher() const = 0;
|
||||
virtual QSsl::SslProtocol sessionProtocol() const = 0;
|
||||
virtual void continueHandshake() = 0;
|
||||
void startClientEncryption();
|
||||
void startServerEncryption();
|
||||
void transmit();
|
||||
void disconnectFromHost();
|
||||
void disconnected();
|
||||
QSslCipher sessionCipher() const;
|
||||
QSsl::SslProtocol sessionProtocol() const;
|
||||
void continueHandshake();
|
||||
|
||||
Q_AUTOTEST_EXPORT static bool rootCertOnDemandLoadingSupported();
|
||||
Q_NETWORK_PRIVATE_EXPORT static bool rootCertOnDemandLoadingSupported();
|
||||
Q_NETWORK_PRIVATE_EXPORT static void setRootCertOnDemandLoadingSupported(bool supported);
|
||||
|
||||
static QTlsBackend *tlsBackendInUse();
|
||||
static void registerAdHocFactory();
|
||||
|
||||
private:
|
||||
static bool ensureLibraryLoaded();
|
||||
static void ensureCiphersAndCertsLoaded();
|
||||
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
|
||||
static QList<QByteArray> fetchSslCertificateData();
|
||||
#endif
|
||||
|
||||
static bool s_libraryLoaded;
|
||||
static bool s_loadedCiphersAndCerts;
|
||||
// Needed by TlsCryptograph:
|
||||
Q_NETWORK_PRIVATE_EXPORT QSslSocket::SslMode tlsMode() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate &privateConfiguration();
|
||||
Q_NETWORK_PRIVATE_EXPORT bool isRootsOnDemandAllowed() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT QString verificationName() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT QString tlsHostName() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT QTcpSocket *plainTcpSocket() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT bool verifyErrorsHaveBeenIgnored();
|
||||
Q_NETWORK_PRIVATE_EXPORT bool isAutoStartingHandshake() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT bool isPendingClose() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT void setPendingClose(bool pc);
|
||||
Q_NETWORK_PRIVATE_EXPORT qint64 maxReadBufferSize() const;
|
||||
Q_NETWORK_PRIVATE_EXPORT void setMaxReadBufferSize(qint64 maxSize);
|
||||
Q_NETWORK_PRIVATE_EXPORT void setEncrypted(bool enc);
|
||||
Q_NETWORK_PRIVATE_EXPORT QRingBufferRef &tlsWriteBuffer();
|
||||
Q_NETWORK_PRIVATE_EXPORT QRingBufferRef &tlsBuffer();
|
||||
Q_NETWORK_PRIVATE_EXPORT bool &tlsEmittedBytesWritten();
|
||||
Q_NETWORK_PRIVATE_EXPORT bool *readyReadPointer();
|
||||
|
||||
protected:
|
||||
bool verifyErrorsHaveBeenIgnored();
|
||||
// Only implemented/useful in Schannel for now
|
||||
virtual bool hasUndecryptedData() { return false; };
|
||||
|
||||
bool hasUndecryptedData() const;
|
||||
bool paused;
|
||||
bool flushTriggered;
|
||||
bool systemOrSslErrorDetected = false;
|
||||
QList<QOcspResponse> ocspResponses;
|
||||
bool handshakeInterrupted = false;
|
||||
bool fetchAuthorityInformation = false;
|
||||
QSslCertificate caToFetch;
|
||||
|
||||
static inline QMutex backendMutex;
|
||||
static inline QString activeBackendName;
|
||||
static inline QTlsBackend *tlsBackend = nullptr;
|
||||
};
|
||||
|
||||
#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
|
||||
// Implemented in qsslsocket_qt.cpp
|
||||
QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase);
|
||||
#endif
|
||||
std::unique_ptr<QTlsPrivate::TlsCryptograph> backend;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
169
src/network/ssl/qtls_openssl_p.h
Normal file
169
src/network/ssl/qtls_openssl_p.h
Normal file
@ -0,0 +1,169 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTLS_OPENSSL_P_H
|
||||
#define QTLS_OPENSSL_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include "qtlsbackend_openssl_p.h"
|
||||
#include "qsslcontext_openssl_p.h"
|
||||
#include "qsslcertificate.h"
|
||||
#include "qocspresponse.h"
|
||||
#include "qopenssl_p.h"
|
||||
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qlist.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QTlsPrivate {
|
||||
|
||||
class TlsCryptographOpenSSL : public TlsCryptograph
|
||||
{
|
||||
public:
|
||||
enum ExDataOffset {
|
||||
errorOffsetInExData = 1,
|
||||
socketOffsetInExData = 2
|
||||
};
|
||||
|
||||
~TlsCryptographOpenSSL();
|
||||
|
||||
void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
|
||||
void checkSettingSslContext(QSharedPointer<QSslContext> tlsContext) override;
|
||||
QSharedPointer<QSslContext> sslContext() const override;
|
||||
|
||||
QList<QSslError> tlsErrors() const override;
|
||||
|
||||
void startClientEncryption() override;
|
||||
void startServerEncryption() override;
|
||||
bool startHandshake();
|
||||
void enableHandshakeContinuation() override;
|
||||
void cancelCAFetch() override;
|
||||
void continueHandshake() override;
|
||||
void transmit() override;
|
||||
void disconnectFromHost() override;
|
||||
void disconnected() override;
|
||||
QSslCipher sessionCipher() const override;
|
||||
QSsl::SslProtocol sessionProtocol() const override;
|
||||
QList<QOcspResponse> ocsps() const override;
|
||||
|
||||
bool checkSslErrors();
|
||||
int handleNewSessionTicket(SSL *connection);
|
||||
|
||||
void alertMessageSent(int encoded);
|
||||
void alertMessageReceived(int encoded);
|
||||
|
||||
int emitErrorFromCallback(X509_STORE_CTX *ctx);
|
||||
void trySendFatalAlert();
|
||||
|
||||
#if QT_CONFIG(ocsp)
|
||||
bool checkOcspStatus();
|
||||
#endif
|
||||
|
||||
QSslSocket *q = nullptr;
|
||||
QSslSocketPrivate *d = nullptr;
|
||||
|
||||
void storePeerCertificates();
|
||||
|
||||
unsigned pskClientTlsCallback(const char *hint, char *identity, unsigned max_identity_len,
|
||||
unsigned char *psk, unsigned max_psk_len);
|
||||
unsigned pskServerTlsCallback(const char *identity, unsigned char *psk,
|
||||
unsigned max_psk_len);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void fetchCaRootForCert(const QSslCertificate &cert);
|
||||
void caRootLoaded(QSslCertificate certificate, QSslCertificate trustedRoot);
|
||||
#endif
|
||||
|
||||
QByteArray ocspResponseDer;
|
||||
private:
|
||||
// TLSTODO: names were preserved, to make comparison
|
||||
// easier (see qsslsocket_openssl.cpp, while it exists).
|
||||
bool initSslContext();
|
||||
void destroySslContext();
|
||||
|
||||
QSharedPointer<QSslContext> sslContextPointer;
|
||||
SSL *ssl = nullptr; // TLSTODO: RAII.
|
||||
|
||||
QList<QSslErrorEntry> errorList;
|
||||
QList<QSslError> sslErrors;
|
||||
|
||||
BIO *readBio = nullptr;
|
||||
BIO *writeBio = nullptr;
|
||||
|
||||
QList<QOcspResponse> ocspResponses;
|
||||
|
||||
// This decription will go to setErrorAndEmit(SslHandshakeError, ocspErrorDescription)
|
||||
QString ocspErrorDescription;
|
||||
// These will go to sslErrors()
|
||||
QList<QSslError> ocspErrors;
|
||||
|
||||
bool systemOrSslErrorDetected = false;
|
||||
bool handshakeInterrupted = false;
|
||||
|
||||
bool fetchAuthorityInformation = false;
|
||||
QSslCertificate caToFetch;
|
||||
|
||||
bool inSetAndEmitError = false;
|
||||
bool pendingFatalAlert = false;
|
||||
bool errorsReportedFromCallback = false;
|
||||
|
||||
bool shutdown = false;
|
||||
};
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QTLS_OPENSSL_P_H
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
#include "qssl_p.h"
|
||||
#include "qsslsocket.h"
|
||||
#include "qsslsocket_schannel_p.h"
|
||||
#include "qtls_schannel_p.h"
|
||||
#include "qsslcertificate.h"
|
||||
#include "qsslcertificateextension.h"
|
||||
#include "qsslcertificate_p.h"
|
||||
@ -161,10 +161,99 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.schannel");
|
||||
|
||||
// Defined in qsslsocket_qt.cpp.
|
||||
QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
|
||||
const QString &passPhrase);
|
||||
|
||||
namespace QTlsPrivate {
|
||||
|
||||
QList<QSslCipher> defaultCiphers()
|
||||
{
|
||||
// Previously the code was in QSslSocketBackendPrivate.
|
||||
QList<QSslCipher> ciphers;
|
||||
// @temp (I hope), stolen from qsslsocket_winrt.cpp
|
||||
const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"),
|
||||
QStringLiteral("TLSv1.2"), QStringLiteral("TLSv1.3") };
|
||||
const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1,
|
||||
QSsl::TlsV1_2, QSsl::TlsV1_3 };
|
||||
const int size = ARRAYSIZE(protocols);
|
||||
static_assert(size == ARRAYSIZE(protocolStrings));
|
||||
ciphers.reserve(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
const QSslCipher cipher = QTlsBackend::createCipher(QStringLiteral("Schannel"),
|
||||
protocols[i], protocolStrings[i]);
|
||||
|
||||
ciphers.append(cipher);
|
||||
}
|
||||
|
||||
return ciphers;
|
||||
|
||||
}
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
namespace {
|
||||
bool supportsTls13();
|
||||
}
|
||||
|
||||
bool QSchannelBackend::s_loadedCiphersAndCerts = false;
|
||||
Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
|
||||
|
||||
long QSchannelBackend::tlsLibraryVersionNumber() const
|
||||
{
|
||||
const auto os = QOperatingSystemVersion::current();
|
||||
return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
|
||||
}
|
||||
|
||||
QString QSchannelBackend::tlsLibraryVersionString() const
|
||||
{
|
||||
const auto os = QOperatingSystemVersion::current();
|
||||
return QString::fromLatin1("Secure Channel, %1 %2.%3.%4")
|
||||
.arg(os.name(),
|
||||
QString::number(os.majorVersion()),
|
||||
QString::number(os.minorVersion()),
|
||||
QString::number(os.microVersion()));
|
||||
}
|
||||
|
||||
long QSchannelBackend::tlsLibraryBuildVersionNumber() const
|
||||
{
|
||||
return tlsLibraryVersionNumber();
|
||||
}
|
||||
|
||||
QString QSchannelBackend::tlsLibraryBuildVersionString() const
|
||||
{
|
||||
const auto os = QOperatingSystemVersion::current();
|
||||
return QString::fromLatin1("%1.%2.%3")
|
||||
.arg(QString::number(os.majorVersion()),
|
||||
QString::number(os.minorVersion()),
|
||||
QString::number(os.microVersion()));
|
||||
}
|
||||
|
||||
void QSchannelBackend::ensureInitialized() const
|
||||
{
|
||||
ensureInitializedImplementation();
|
||||
}
|
||||
|
||||
void QSchannelBackend::ensureInitializedImplementation()
|
||||
{
|
||||
const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
|
||||
if (s_loadedCiphersAndCerts)
|
||||
return;
|
||||
s_loadedCiphersAndCerts = true;
|
||||
|
||||
setDefaultCaCertificates(systemCaCertificatesImplementation());
|
||||
// setDefaultCaCertificates sets it to false, re-enable it:
|
||||
QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
|
||||
|
||||
resetDefaultCiphers();
|
||||
}
|
||||
|
||||
void QSchannelBackend::resetDefaultCiphers()
|
||||
{
|
||||
setDefaultSupportedCiphers(QTlsPrivate::defaultCiphers());
|
||||
setDefaultCiphers(QTlsPrivate::defaultCiphers());
|
||||
}
|
||||
|
||||
QString QSchannelBackend::backendName() const
|
||||
{
|
||||
return builtinBackendNames[nameIndexSchannel];
|
||||
@ -222,6 +311,32 @@ QTlsPrivate::X509Certificate *QSchannelBackend::createCertificate() const
|
||||
return new QTlsPrivate::X509CertificateSchannel;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> QSchannelBackend::systemCaCertificates() const
|
||||
{
|
||||
return systemCaCertificatesImplementation();
|
||||
}
|
||||
|
||||
QTlsPrivate::TlsCryptograph *QSchannelBackend::createTlsCryptograph() const
|
||||
{
|
||||
return new QTlsPrivate::TlsCryptographSchannel;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> QSchannelBackend::systemCaCertificatesImplementation()
|
||||
{
|
||||
// Similar to non-Darwin version found in qtlsbackend_openssl.cpp,
|
||||
// QTlsPrivate::systemCaCertificates function.
|
||||
QList<QSslCertificate> systemCerts;
|
||||
auto hSystemStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
|
||||
if (hSystemStore) {
|
||||
PCCERT_CONTEXT pc = nullptr;
|
||||
while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
|
||||
CERT_FIND_ANY, nullptr, pc))) {
|
||||
systemCerts.append(QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(pc));
|
||||
}
|
||||
}
|
||||
return systemCerts;
|
||||
}
|
||||
|
||||
QTlsPrivate::X509PemReaderPtr QSchannelBackend::X509PemReader() const
|
||||
{
|
||||
return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
|
||||
@ -232,7 +347,7 @@ QTlsPrivate::X509DerReaderPtr QSchannelBackend::X509DerReader() const
|
||||
return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
|
||||
}
|
||||
|
||||
Q_GLOBAL_STATIC(QSchannelBackend, backend)
|
||||
Q_GLOBAL_STATIC(QSchannelBackend, backendSchannel)
|
||||
|
||||
namespace {
|
||||
|
||||
@ -588,93 +703,17 @@ qint64 checkIncompleteData(const SecBuffer &secBuffer)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
|
||||
bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
|
||||
Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
|
||||
|
||||
void QSslSocketPrivate::ensureInitialized()
|
||||
{
|
||||
const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
|
||||
if (s_loadedCiphersAndCerts)
|
||||
return;
|
||||
s_loadedCiphersAndCerts = true;
|
||||
namespace QTlsPrivate {
|
||||
|
||||
setDefaultCaCertificates(systemCaCertificates());
|
||||
s_loadRootCertsOnDemand = true; // setDefaultCaCertificates sets it to false, re-enable it.
|
||||
|
||||
resetDefaultCiphers();
|
||||
}
|
||||
|
||||
void QSslSocketPrivate::resetDefaultCiphers()
|
||||
{
|
||||
setDefaultSupportedCiphers(QSslSocketBackendPrivate::defaultCiphers());
|
||||
setDefaultCiphers(QSslSocketBackendPrivate::defaultCiphers());
|
||||
}
|
||||
|
||||
void QSslSocketPrivate::resetDefaultEllipticCurves()
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
bool QSslSocketPrivate::supportsSsl()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
||||
{
|
||||
// Copied from qsslsocket_openssl.cpp's systemCaCertificates function.
|
||||
QList<QSslCertificate> systemCerts;
|
||||
auto hSystemStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
|
||||
if (hSystemStore) {
|
||||
PCCERT_CONTEXT pc = nullptr;
|
||||
while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
|
||||
CERT_FIND_ANY, nullptr, pc))) {
|
||||
systemCerts.append(QTlsPrivate::X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(pc));
|
||||
}
|
||||
}
|
||||
return systemCerts;
|
||||
}
|
||||
|
||||
long QSslSocketPrivate::sslLibraryVersionNumber()
|
||||
{
|
||||
const auto os = QOperatingSystemVersion::current();
|
||||
return (os.majorVersion() << 24) | ((os.minorVersion() & 0xFF) << 16) | (os.microVersion() & 0xFFFF);
|
||||
}
|
||||
|
||||
QString QSslSocketPrivate::sslLibraryVersionString()
|
||||
{
|
||||
const auto os = QOperatingSystemVersion::current();
|
||||
return QString::fromLatin1("Secure Channel, %1 %2.%3.%4")
|
||||
.arg(os.name(),
|
||||
QString::number(os.majorVersion()),
|
||||
QString::number(os.minorVersion()),
|
||||
QString::number(os.microVersion()));
|
||||
}
|
||||
|
||||
long QSslSocketPrivate::sslLibraryBuildVersionNumber()
|
||||
{
|
||||
// There is no separate build version
|
||||
return sslLibraryVersionNumber();
|
||||
}
|
||||
|
||||
QString QSslSocketPrivate::sslLibraryBuildVersionString()
|
||||
{
|
||||
const auto os = QOperatingSystemVersion::current();
|
||||
return QString::fromLatin1("%1.%2.%3")
|
||||
.arg(QString::number(os.majorVersion()),
|
||||
QString::number(os.minorVersion()),
|
||||
QString::number(os.microVersion()));
|
||||
}
|
||||
|
||||
QSslSocketBackendPrivate::QSslSocketBackendPrivate()
|
||||
TlsCryptographSchannel::TlsCryptographSchannel()
|
||||
{
|
||||
SecInvalidateHandle(&credentialHandle);
|
||||
SecInvalidateHandle(&contextHandle);
|
||||
ensureInitialized();
|
||||
QSchannelBackend::ensureInitializedImplementation();
|
||||
}
|
||||
|
||||
QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
|
||||
TlsCryptographSchannel::~TlsCryptographSchannel()
|
||||
{
|
||||
closeCertificateStores();
|
||||
deallocateContext();
|
||||
@ -682,29 +721,51 @@ QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
|
||||
CertFreeCertificateContext(localCertContext);
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::sendToken(void *token, unsigned long tokenLength, bool emitError)
|
||||
void TlsCryptographSchannel::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
|
||||
{
|
||||
Q_ASSERT(qObj);
|
||||
Q_ASSERT(dObj);
|
||||
|
||||
q = qObj;
|
||||
d = dObj;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
bool TlsCryptographSchannel::sendToken(void *token, unsigned long tokenLength, bool emitError)
|
||||
{
|
||||
if (tokenLength == 0)
|
||||
return true;
|
||||
|
||||
Q_ASSERT(d);
|
||||
auto *plainSocket = d->plainTcpSocket();
|
||||
Q_ASSERT(plainSocket);
|
||||
|
||||
const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
|
||||
if (written != qint64(tokenLength)) {
|
||||
// Failed to write/buffer everything or an error occurred
|
||||
if (emitError)
|
||||
setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
||||
d->setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QSslSocketBackendPrivate::targetName() const
|
||||
QString TlsCryptographSchannel::targetName() const
|
||||
{
|
||||
// Used for SNI extension
|
||||
return verificationPeerName.isEmpty() ? q_func()->peerName() : verificationPeerName;
|
||||
Q_ASSERT(q);
|
||||
Q_ASSERT(d);
|
||||
|
||||
const auto verificationPeerName = d->verificationName();
|
||||
return verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
|
||||
}
|
||||
|
||||
ULONG QSslSocketBackendPrivate::getContextRequirements()
|
||||
ULONG TlsCryptographSchannel::getContextRequirements()
|
||||
{
|
||||
const bool isClient = mode == QSslSocket::SslClientMode;
|
||||
Q_ASSERT(d);
|
||||
|
||||
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||
ULONG req = 0;
|
||||
|
||||
req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
|
||||
@ -716,7 +777,7 @@ ULONG QSslSocketBackendPrivate::getContextRequirements()
|
||||
if (isClient) {
|
||||
req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
|
||||
} else {
|
||||
switch (configuration.peerVerifyMode) {
|
||||
switch (d->privateConfiguration().peerVerifyMode) {
|
||||
case QSslSocket::PeerVerifyMode::VerifyNone:
|
||||
// There doesn't seem to be a way to ask for an optional client cert :-(
|
||||
case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
|
||||
@ -731,15 +792,18 @@ ULONG QSslSocketBackendPrivate::getContextRequirements()
|
||||
return req;
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::acquireCredentialsHandle()
|
||||
bool TlsCryptographSchannel::acquireCredentialsHandle()
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
const auto &configuration = d->privateConfiguration();
|
||||
|
||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||
|
||||
const bool isClient = mode == QSslSocket::SslClientMode;
|
||||
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||
const DWORD protocols = toSchannelProtocol(configuration.protocol);
|
||||
if (protocols == DWORD(-1)) {
|
||||
setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||
QSslSocket::tr("Invalid protocol chosen"));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||
QSslSocket::tr("Invalid protocol chosen"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -776,7 +840,7 @@ bool QSslSocketBackendPrivate::acquireCredentialsHandle()
|
||||
const QString message = isClient
|
||||
? QSslSocket::tr("The certificate provided cannot be used for a client.")
|
||||
: QSslSocket::tr("The certificate provided cannot be used for a server.");
|
||||
setErrorAndEmit(QAbstractSocket::SocketError::SslInvalidUserDataError, message);
|
||||
d->setErrorAndEmit(QAbstractSocket::SocketError::SslInvalidUserDataError, message);
|
||||
return false;
|
||||
}
|
||||
Q_ASSERT(chainContext->cChain == 1);
|
||||
@ -865,13 +929,13 @@ bool QSslSocketBackendPrivate::acquireCredentialsHandle()
|
||||
}
|
||||
|
||||
if (status != SEC_E_OK) {
|
||||
setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::deallocateContext()
|
||||
void TlsCryptographSchannel::deallocateContext()
|
||||
{
|
||||
if (SecIsValidHandle(&contextHandle)) {
|
||||
DeleteSecurityContext(&contextHandle);
|
||||
@ -879,7 +943,7 @@ void QSslSocketBackendPrivate::deallocateContext()
|
||||
}
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::freeCredentialsHandle()
|
||||
void TlsCryptographSchannel::freeCredentialsHandle()
|
||||
{
|
||||
if (SecIsValidHandle(&credentialHandle)) {
|
||||
FreeCredentialsHandle(&credentialHandle);
|
||||
@ -887,18 +951,21 @@ void QSslSocketBackendPrivate::freeCredentialsHandle()
|
||||
}
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::closeCertificateStores()
|
||||
void TlsCryptographSchannel::closeCertificateStores()
|
||||
{
|
||||
localCertificateStore.reset();
|
||||
peerCertificateStore.reset();
|
||||
caCertificateStore.reset();
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::createContext()
|
||||
bool TlsCryptographSchannel::createContext()
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
auto &configuration = d->privateConfiguration();
|
||||
|
||||
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||
Q_ASSERT(mode == QSslSocket::SslClientMode);
|
||||
Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode);
|
||||
ULONG contextReq = getContextRequirements();
|
||||
|
||||
SecBuffer outBuffers[3];
|
||||
@ -951,8 +1018,8 @@ bool QSslSocketBackendPrivate::createContext()
|
||||
// This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
|
||||
// should be the only non-error return-code here.
|
||||
if (status != SEC_I_CONTINUE_NEEDED) {
|
||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -962,11 +1029,15 @@ bool QSslSocketBackendPrivate::createContext()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::acceptContext()
|
||||
bool TlsCryptographSchannel::acceptContext()
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
auto &configuration = d->privateConfiguration();
|
||||
auto *plainSocket = d->plainTcpSocket();
|
||||
|
||||
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||
Q_ASSERT(mode == QSslSocket::SslServerMode);
|
||||
Q_ASSERT(d->tlsMode() == QSslSocket::SslServerMode);
|
||||
ULONG contextReq = getContextRequirements();
|
||||
|
||||
if (missingData > plainSocket->bytesAvailable())
|
||||
@ -1043,8 +1114,8 @@ bool QSslSocketBackendPrivate::acceptContext()
|
||||
}
|
||||
|
||||
if (status != SEC_I_CONTINUE_NEEDED) {
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
||||
return false;
|
||||
}
|
||||
if (!sendToken(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer))
|
||||
@ -1053,11 +1124,15 @@ bool QSslSocketBackendPrivate::acceptContext()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::performHandshake()
|
||||
bool TlsCryptographSchannel::performHandshake()
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
auto *plainSocket = d->plainTcpSocket();
|
||||
Q_ASSERT(plainSocket);
|
||||
|
||||
if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
|
||||
setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
||||
d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
||||
return false;
|
||||
}
|
||||
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
||||
@ -1157,8 +1232,8 @@ bool QSslSocketBackendPrivate::performHandshake()
|
||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||
// Schannel takes care of picking certificate to send (other than the one we can specify),
|
||||
// so if we get here then that means we don't have a certificate the server accepts.
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Server did not accept any certificate we could present."));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Server did not accept any certificate we could present."));
|
||||
return false;
|
||||
case SEC_I_CONTEXT_EXPIRED:
|
||||
// "The message sender has finished using the connection and has initiated a shutdown."
|
||||
@ -1167,8 +1242,8 @@ bool QSslSocketBackendPrivate::performHandshake()
|
||||
return false;
|
||||
}
|
||||
if (!shutdown) { // we did not initiate this
|
||||
setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
||||
d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
||||
}
|
||||
return true;
|
||||
case SEC_E_INCOMPLETE_MESSAGE:
|
||||
@ -1176,8 +1251,8 @@ bool QSslSocketBackendPrivate::performHandshake()
|
||||
missingData = checkIncompleteData(outBuffers[0]);
|
||||
return true;
|
||||
case SEC_E_ALGORITHM_MISMATCH:
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Algorithm mismatch"));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Algorithm mismatch"));
|
||||
shutdown = true; // skip sending the "Shutdown" alert
|
||||
return false;
|
||||
}
|
||||
@ -1185,20 +1260,23 @@ bool QSslSocketBackendPrivate::performHandshake()
|
||||
// Note: We can get here if the connection is using TLS 1.2 and the server certificate uses
|
||||
// MD5, which is not allowed in Schannel. This causes an "invalid token" error during handshake.
|
||||
// (If you came here investigating an error: md5 is insecure, update your certificate)
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::verifyHandshake()
|
||||
bool TlsCryptographSchannel::verifyHandshake()
|
||||
{
|
||||
Q_Q(QSslSocket);
|
||||
Q_ASSERT(d);
|
||||
Q_ASSERT(q);
|
||||
auto &configuration = d->privateConfiguration();
|
||||
|
||||
sslErrors.clear();
|
||||
|
||||
const bool isClient = mode == QSslSocket::SslClientMode;
|
||||
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||
#define CHECK_STATUS(status) \
|
||||
if (status != SEC_E_OK) { \
|
||||
setErrorAndEmit(QAbstractSocket::SslInternalError, \
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInternalError, \
|
||||
QSslSocket::tr("Failed to query the TLS context: %1") \
|
||||
.arg(schannelErrorToString(status))); \
|
||||
return false; \
|
||||
@ -1207,8 +1285,8 @@ bool QSslSocketBackendPrivate::verifyHandshake()
|
||||
// Everything is set up, now make sure there's nothing wrong and query some attributes...
|
||||
if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
|
||||
configuration.peerVerifyMode, isClient)) {
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Did not get the required attributes for the connection."));
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Did not get the required attributes for the connection."));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1235,7 +1313,7 @@ bool QSslSocketBackendPrivate::verifyHandshake()
|
||||
QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
|
||||
alpn.ProtocolIdSize);
|
||||
if (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Unwanted protocol was negotiated"));
|
||||
return false;
|
||||
}
|
||||
@ -1285,20 +1363,22 @@ bool QSslSocketBackendPrivate::verifyHandshake()
|
||||
if (certificateContext && !verifyCertContext(certificateContext))
|
||||
return false;
|
||||
|
||||
if (!checkSslErrors() || state != QAbstractSocket::ConnectedState) {
|
||||
if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState) {
|
||||
#ifdef QSSLSOCKET_DEBUG
|
||||
qCDebug(lcSsl) << __func__ << "was unsuccessful. Paused:" << paused;
|
||||
#endif
|
||||
// If we're paused then checkSslErrors returned false, but it's not an error
|
||||
return paused && state == QAbstractSocket::ConnectedState;
|
||||
return d->isPaused() && q->state() == QAbstractSocket::ConnectedState;
|
||||
}
|
||||
|
||||
schannelState = SchannelState::Done;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::renegotiate()
|
||||
bool TlsCryptographSchannel::renegotiate()
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
|
||||
SecBuffer outBuffers[3];
|
||||
outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
|
||||
outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
|
||||
@ -1318,7 +1398,7 @@ bool QSslSocketBackendPrivate::renegotiate()
|
||||
ULONG contextReq = getContextRequirements();
|
||||
TimeStamp expiry;
|
||||
SECURITY_STATUS status;
|
||||
if (mode == QSslSocket::SslClientMode) {
|
||||
if (d->tlsMode() == QSslSocket::SslClientMode) {
|
||||
status = InitializeSecurityContext(&credentialHandle, // phCredential
|
||||
&contextHandle, // phContext
|
||||
const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
|
||||
@ -1352,7 +1432,7 @@ bool QSslSocketBackendPrivate::renegotiate()
|
||||
schannelState = SchannelState::PerformHandshake;
|
||||
return true;
|
||||
}
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
|
||||
return false;
|
||||
}
|
||||
@ -1361,8 +1441,10 @@ bool QSslSocketBackendPrivate::renegotiate()
|
||||
\internal
|
||||
reset the state in preparation for reuse of socket
|
||||
*/
|
||||
void QSslSocketBackendPrivate::reset()
|
||||
void TlsCryptographSchannel::reset()
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
|
||||
closeCertificateStores(); // certificate stores could've changed
|
||||
deallocateContext();
|
||||
freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
|
||||
@ -1377,34 +1459,42 @@ void QSslSocketBackendPrivate::reset()
|
||||
intermediateBuffer.clear();
|
||||
schannelState = SchannelState::InitializeHandshake;
|
||||
|
||||
connectionEncrypted = false;
|
||||
|
||||
d->setEncrypted(false);
|
||||
shutdown = false;
|
||||
renegotiating = false;
|
||||
|
||||
missingData = 0;
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::startClientEncryption()
|
||||
void TlsCryptographSchannel::startClientEncryption()
|
||||
{
|
||||
if (connectionEncrypted)
|
||||
Q_ASSERT(q);
|
||||
|
||||
if (q->isEncrypted())
|
||||
return; // let's not mess up the connection...
|
||||
reset();
|
||||
continueHandshake();
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::startServerEncryption()
|
||||
void TlsCryptographSchannel::startServerEncryption()
|
||||
{
|
||||
if (connectionEncrypted)
|
||||
Q_ASSERT(q);
|
||||
|
||||
if (q->isEncrypted())
|
||||
return; // let's not mess up the connection...
|
||||
reset();
|
||||
continueHandshake();
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::transmit()
|
||||
void TlsCryptographSchannel::transmit()
|
||||
{
|
||||
Q_Q(QSslSocket);
|
||||
Q_ASSERT(q);
|
||||
Q_ASSERT(d);
|
||||
auto *plainSocket = d->plainTcpSocket();
|
||||
Q_ASSERT(plainSocket);
|
||||
|
||||
if (mode == QSslSocket::UnencryptedMode)
|
||||
if (d->tlsMode() == QSslSocket::UnencryptedMode)
|
||||
return; // This function should not have been called
|
||||
|
||||
// Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
|
||||
@ -1416,7 +1506,9 @@ void QSslSocketBackendPrivate::transmit()
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionEncrypted) { // encrypt data in writeBuffer and write it to plainSocket
|
||||
auto &writeBuffer = d->tlsWriteBuffer();
|
||||
auto &buffer = d->tlsBuffer();
|
||||
if (q->isEncrypted()) { // encrypt data in writeBuffer and write it to plainSocket
|
||||
qint64 totalBytesWritten = 0;
|
||||
qint64 writeBufferSize;
|
||||
while ((writeBufferSize = writeBuffer.size()) > 0) {
|
||||
@ -1444,7 +1536,7 @@ void QSslSocketBackendPrivate::transmit()
|
||||
};
|
||||
auto status = EncryptMessage(&contextHandle, 0, &message, 0);
|
||||
if (status != SEC_E_OK) {
|
||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
QSslSocket::tr("Schannel failed to encrypt data: %1")
|
||||
.arg(schannelErrorToString(status)));
|
||||
return;
|
||||
@ -1461,13 +1553,14 @@ void QSslSocketBackendPrivate::transmit()
|
||||
if (bytesWritten >= 0) {
|
||||
totalBytesWritten += bytesWritten;
|
||||
} else {
|
||||
setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
||||
d->setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalBytesWritten > 0) {
|
||||
// Don't emit bytesWritten() recursively.
|
||||
bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
|
||||
if (!emittedBytesWritten) {
|
||||
emittedBytesWritten = true;
|
||||
emit q->bytesWritten(totalBytesWritten);
|
||||
@ -1477,9 +1570,10 @@ void QSslSocketBackendPrivate::transmit()
|
||||
}
|
||||
}
|
||||
|
||||
if (connectionEncrypted) { // Decrypt data from remote
|
||||
if (q->isEncrypted()) { // Decrypt data from remote
|
||||
int totalRead = 0;
|
||||
bool hadIncompleteData = false;
|
||||
const auto readBufferMaxSize = d->maxReadBufferSize();
|
||||
while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
|
||||
if (missingData > plainSocket->bytesAvailable()
|
||||
&& (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
|
||||
@ -1560,7 +1654,7 @@ void QSslSocketBackendPrivate::transmit()
|
||||
// The message has been altered, disconnect now.
|
||||
shutdown = true; // skips sending the shutdown alert
|
||||
disconnectFromHost();
|
||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
schannelErrorToString(status));
|
||||
break;
|
||||
} else if (status == SEC_E_OUT_OF_SEQUENCE) {
|
||||
@ -1569,13 +1663,13 @@ void QSslSocketBackendPrivate::transmit()
|
||||
// while SEC_E_MESSAGE_ALTERED is for stream-oriented ones (what we use).
|
||||
shutdown = true; // skips sending the shutdown alert
|
||||
disconnectFromHost();
|
||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||
schannelErrorToString(status));
|
||||
break;
|
||||
} else if (status == SEC_I_CONTEXT_EXPIRED) {
|
||||
// 'remote' has initiated a shutdown
|
||||
disconnectFromHost();
|
||||
setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||
d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||
schannelErrorToString(status));
|
||||
break;
|
||||
} else if (status == SEC_I_RENEGOTIATE) {
|
||||
@ -1593,7 +1687,7 @@ void QSslSocketBackendPrivate::transmit()
|
||||
}
|
||||
|
||||
if (totalRead) {
|
||||
if (readyReadEmittedPointer)
|
||||
if (bool *readyReadEmittedPointer = d->readyReadPointer())
|
||||
*readyReadEmittedPointer = true;
|
||||
emit q->readyRead();
|
||||
emit q->channelReadyRead(0);
|
||||
@ -1601,9 +1695,11 @@ void QSslSocketBackendPrivate::transmit()
|
||||
}
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::sendShutdown()
|
||||
void TlsCryptographSchannel::sendShutdown()
|
||||
{
|
||||
const bool isClient = mode == QSslSocket::SslClientMode;
|
||||
Q_ASSERT(d);
|
||||
|
||||
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||
DWORD shutdownToken = SCHANNEL_SHUTDOWN;
|
||||
SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(DWORD), SECBUFFER_TOKEN);
|
||||
SecBufferDesc token{
|
||||
@ -1678,18 +1774,23 @@ void QSslSocketBackendPrivate::sendShutdown()
|
||||
}
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::disconnectFromHost()
|
||||
void TlsCryptographSchannel::disconnectFromHost()
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
Q_ASSERT(d);
|
||||
auto *plainSocket = d->plainTcpSocket();
|
||||
Q_ASSERT(plainSocket);
|
||||
|
||||
if (SecIsValidHandle(&contextHandle)) {
|
||||
if (!shutdown) {
|
||||
shutdown = true;
|
||||
if (plainSocket->state() != QAbstractSocket::UnconnectedState) {
|
||||
if (connectionEncrypted) {
|
||||
if (q->isEncrypted()) {
|
||||
// Read as much as possible because this is likely our last chance
|
||||
qint64 tempMax = readBufferMaxSize;
|
||||
readBufferMaxSize = 0;
|
||||
qint64 tempMax = d->maxReadBufferSize();
|
||||
d->setMaxReadBufferSize(0);
|
||||
transmit();
|
||||
readBufferMaxSize = tempMax;
|
||||
d->setMaxReadBufferSize(tempMax);
|
||||
sendShutdown();
|
||||
}
|
||||
}
|
||||
@ -1699,32 +1800,40 @@ void QSslSocketBackendPrivate::disconnectFromHost()
|
||||
plainSocket->disconnectFromHost();
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::disconnected()
|
||||
void TlsCryptographSchannel::disconnected()
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
|
||||
shutdown = true;
|
||||
connectionEncrypted = false;
|
||||
d->setEncrypted(false);
|
||||
deallocateContext();
|
||||
freeCredentialsHandle();
|
||||
}
|
||||
|
||||
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
|
||||
QSslCipher TlsCryptographSchannel::sessionCipher() const
|
||||
{
|
||||
if (!connectionEncrypted)
|
||||
Q_ASSERT(q);
|
||||
|
||||
if (!q->isEncrypted())
|
||||
return QSslCipher();
|
||||
return QSslCipher(QStringLiteral("Schannel"), sessionProtocol());
|
||||
}
|
||||
|
||||
QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
|
||||
QSsl::SslProtocol TlsCryptographSchannel::sessionProtocol() const
|
||||
{
|
||||
if (!connectionEncrypted)
|
||||
if (!q->isEncrypted())
|
||||
return QSsl::SslProtocol::UnknownProtocol;
|
||||
return toQtSslProtocol(connectionInfo.dwProtocol);
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::continueHandshake()
|
||||
void TlsCryptographSchannel::continueHandshake()
|
||||
{
|
||||
Q_Q(QSslSocket);
|
||||
const bool isServer = mode == QSslSocket::SslServerMode;
|
||||
Q_ASSERT(q);
|
||||
Q_ASSERT(d);
|
||||
auto *plainSocket = d->plainTcpSocket();
|
||||
Q_ASSERT(plainSocket);
|
||||
|
||||
const bool isServer = d->tlsMode() == QSslSocket::SslServerMode;
|
||||
switch (schannelState) {
|
||||
case SchannelState::InitializeHandshake:
|
||||
if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
|
||||
@ -1762,13 +1871,13 @@ void QSslSocketBackendPrivate::continueHandshake()
|
||||
Q_FALLTHROUGH();
|
||||
case SchannelState::Done:
|
||||
// connectionEncrypted is already true if we come here from a renegotiation
|
||||
if (!connectionEncrypted) {
|
||||
connectionEncrypted = true; // all is done
|
||||
if (!q->isEncrypted()) {
|
||||
d->setEncrypted(true); // all is done
|
||||
emit q->encrypted();
|
||||
}
|
||||
renegotiating = false;
|
||||
if (pendingClose) {
|
||||
pendingClose = false;
|
||||
if (d->isPendingClose()) {
|
||||
d->setPendingClose(false);
|
||||
disconnectFromHost();
|
||||
} else {
|
||||
transmit();
|
||||
@ -1785,75 +1894,37 @@ void QSslSocketBackendPrivate::continueHandshake()
|
||||
}
|
||||
}
|
||||
|
||||
QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
|
||||
QList<QSslError> TlsCryptographSchannel::tlsErrors() const
|
||||
{
|
||||
QList<QSslCipher> ciphers;
|
||||
// @temp (I hope), stolen from qsslsocket_winrt.cpp
|
||||
const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"),
|
||||
QStringLiteral("TLSv1.2"), QStringLiteral("TLSv1.3") };
|
||||
const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1,
|
||||
QSsl::TlsV1_2, QSsl::TlsV1_3 };
|
||||
const int size = ARRAYSIZE(protocols);
|
||||
static_assert(size == ARRAYSIZE(protocolStrings));
|
||||
ciphers.reserve(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
QSslCipher cipher;
|
||||
cipher.d->isNull = false;
|
||||
cipher.d->name = QStringLiteral("Schannel");
|
||||
cipher.d->protocol = protocols[i];
|
||||
cipher.d->protocolString = protocolStrings[i];
|
||||
ciphers.append(cipher);
|
||||
}
|
||||
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
QList<QSslError> QSslSocketBackendPrivate::verify(const QList<QSslCertificate> &certificateChain,
|
||||
const QString &hostName)
|
||||
{
|
||||
Q_UNUSED(certificateChain);
|
||||
Q_UNUSED(hostName);
|
||||
|
||||
Q_UNIMPLEMENTED();
|
||||
return {}; // @future implement(?)
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
|
||||
QList<QSslCertificate> *caCertificates,
|
||||
const QByteArray &passPhrase)
|
||||
{
|
||||
Q_UNUSED(device);
|
||||
Q_UNUSED(key);
|
||||
Q_UNUSED(cert);
|
||||
Q_UNUSED(caCertificates);
|
||||
Q_UNUSED(passPhrase);
|
||||
// @future: can load into its own certificate store (encountered problems extracting key).
|
||||
Q_UNIMPLEMENTED();
|
||||
return false;
|
||||
return sslErrors;
|
||||
}
|
||||
|
||||
/*
|
||||
Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
|
||||
*/
|
||||
bool QSslSocketBackendPrivate::checkSslErrors()
|
||||
bool TlsCryptographSchannel::checkSslErrors()
|
||||
{
|
||||
if (sslErrors.isEmpty())
|
||||
return true;
|
||||
Q_Q(QSslSocket);
|
||||
|
||||
Q_ASSERT(q);
|
||||
Q_ASSERT(d);
|
||||
const auto &configuration = d->privateConfiguration();
|
||||
auto *plainSocket = d->plainTcpSocket();
|
||||
|
||||
emit q->sslErrors(sslErrors);
|
||||
|
||||
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
||||
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
||||
&& mode == QSslSocket::SslClientMode);
|
||||
const bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
|
||||
&& d->tlsMode() == QSslSocket::SslClientMode);
|
||||
const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
|
||||
// check whether we need to emit an SSL handshake error
|
||||
if (doVerifyPeer && doEmitSslError) {
|
||||
if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
|
||||
pauseSocketNotifiers(q);
|
||||
paused = true;
|
||||
QSslSocketPrivate::pauseSocketNotifiers(q);
|
||||
d->setPaused(true);
|
||||
} else {
|
||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||
sslErrors.constFirst().errorString());
|
||||
plainSocket->disconnectFromHost();
|
||||
}
|
||||
@ -1863,9 +1934,12 @@ bool QSslSocketBackendPrivate::checkSslErrors()
|
||||
return true;
|
||||
}
|
||||
|
||||
void QSslSocketBackendPrivate::initializeCertificateStores()
|
||||
void TlsCryptographSchannel::initializeCertificateStores()
|
||||
{
|
||||
//// helper function which turns a chain into a certificate store
|
||||
Q_ASSERT(d);
|
||||
const auto &configuration = d->privateConfiguration();
|
||||
|
||||
auto createStoreFromCertificateChain = [](const QList<QSslCertificate> certChain, const QSslKey &privateKey) {
|
||||
const wchar_t *passphrase = L"";
|
||||
// Need to embed the private key in the certificate
|
||||
@ -1880,7 +1954,7 @@ void QSslSocketBackendPrivate::initializeCertificateStores()
|
||||
|
||||
if (!configuration.localCertificateChain.isEmpty()) {
|
||||
if (configuration.privateKey.isNull()) {
|
||||
setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||
QSslSocket::tr("Cannot provide a certificate with no key"));
|
||||
return;
|
||||
}
|
||||
@ -1898,12 +1972,14 @@ void QSslSocketBackendPrivate::initializeCertificateStores()
|
||||
}
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
|
||||
bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
|
||||
{
|
||||
Q_ASSERT(certContext);
|
||||
Q_Q(QSslSocket);
|
||||
Q_ASSERT(q);
|
||||
Q_ASSERT(d);
|
||||
auto &configuration = d->privateConfiguration();
|
||||
|
||||
const bool isClient = mode == QSslSocket::SslClientMode;
|
||||
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||
|
||||
// Create a collection of stores so we can pass in multiple stores as additional locations to
|
||||
// search for the certificate chain
|
||||
@ -2187,14 +2263,15 @@ bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
|
||||
// @Note: Somewhat copied from qsslsocket_mac.cpp
|
||||
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
||||
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
||||
&& mode == QSslSocket::SslClientMode);
|
||||
&& d->tlsMode() == QSslSocket::SslClientMode);
|
||||
// Check the peer certificate itself. First try the subject's common name
|
||||
// (CN) as a wildcard, then try all alternate subject name DNS entries the
|
||||
// same way.
|
||||
if (!configuration.peerCertificate.isNull()) {
|
||||
// but only if we're a client connecting to a server
|
||||
// if we're the server, don't check CN
|
||||
if (mode == QSslSocket::SslClientMode) {
|
||||
if (d->tlsMode() == QSslSocket::SslClientMode) {
|
||||
const auto verificationPeerName = d->verificationName();
|
||||
const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
|
||||
if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
|
||||
// No matches in common names or alternate names.
|
||||
@ -2218,17 +2295,20 @@ bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QSslSocketBackendPrivate::rootCertOnDemandLoadingAllowed()
|
||||
bool TlsCryptographSchannel::rootCertOnDemandLoadingAllowed()
|
||||
{
|
||||
return allowRootCertOnDemandLoading && s_loadRootCertsOnDemand;
|
||||
Q_ASSERT(d);
|
||||
return d->isRootsOnDemandAllowed() && QSslSocketPrivate::rootCertOnDemandLoadingSupported();
|
||||
}
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
void QSslSocketPrivate::registerAdHocFactory()
|
||||
{
|
||||
// TLSTODO: this is a temporary solution, waiting for
|
||||
// backends to move to ... plugins.
|
||||
if (!backend())
|
||||
qCWarning(lcSsl, "Failed to create backend factory");
|
||||
if (!backendSchannel())
|
||||
qCWarning(lcTlsBackend, "Failed to create backend factory");
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -37,8 +37,8 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSSLSOCKET_SCHANNEL_P_H
|
||||
#define QSSLSOCKET_SCHANNEL_P_H
|
||||
#ifndef QTLS_SCHANNEL_P_H
|
||||
#define QTLS_SCHANNEL_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
@ -51,12 +51,17 @@
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
QT_REQUIRE_CONFIG(schannel);
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
QT_REQUIRE_CONFIG(schannel);
|
||||
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
#include "qtlsbackend_schannel_p.h"
|
||||
#include "qsslsocket_p.h"
|
||||
|
||||
#include "qwincrypt_p.h"
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#define SCHANNEL_USE_BLACKLISTS 1
|
||||
#include <Winternl.h> // needed for UNICODE defines
|
||||
@ -67,15 +72,17 @@ QT_REQUIRE_CONFIG(schannel);
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSslSocketBackendPrivate final : public QSslSocketPrivate
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate)
|
||||
Q_DECLARE_PUBLIC(QSslSocket)
|
||||
public:
|
||||
QSslSocketBackendPrivate();
|
||||
~QSslSocketBackendPrivate();
|
||||
namespace QTlsPrivate {
|
||||
|
||||
class TlsCryptographSchannel final : public TlsCryptograph
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(TlsCryptographSchannel)
|
||||
public:
|
||||
TlsCryptographSchannel();
|
||||
~TlsCryptographSchannel();
|
||||
|
||||
void init(QSslSocket *q, QSslSocketPrivate *d) override;
|
||||
|
||||
// Platform specific functions
|
||||
void startClientEncryption() override;
|
||||
void startServerEncryption() override;
|
||||
void transmit() override;
|
||||
@ -84,12 +91,7 @@ public:
|
||||
QSslCipher sessionCipher() const override;
|
||||
QSsl::SslProtocol sessionProtocol() const override;
|
||||
void continueHandshake() override;
|
||||
|
||||
static QList<QSslCipher> defaultCiphers();
|
||||
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain,
|
||||
const QString &hostName);
|
||||
static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
|
||||
QList<QSslCertificate> *caCertificates, const QByteArray &passPhrase);
|
||||
QList<QSslError> tlsErrors() const override;
|
||||
|
||||
private:
|
||||
enum class SchannelState {
|
||||
@ -123,7 +125,10 @@ private:
|
||||
|
||||
bool rootCertOnDemandLoadingAllowed();
|
||||
|
||||
bool hasUndecryptedData() override { return intermediateBuffer.size() > 0; }
|
||||
bool hasUndecryptedData() const override { return intermediateBuffer.size() > 0; }
|
||||
|
||||
QSslSocket *q = nullptr;
|
||||
QSslSocketPrivate *d = nullptr;
|
||||
|
||||
SecPkgContext_ConnectionInfo connectionInfo = {};
|
||||
SecPkgContext_StreamSizes streamSizes = {};
|
||||
@ -143,8 +148,12 @@ private:
|
||||
qint64 missingData = 0;
|
||||
|
||||
bool renegotiating = false;
|
||||
bool shutdown = false;
|
||||
QList<QSslError> sslErrors;
|
||||
};
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSSLSOCKET_SCHANNEL_P_H
|
||||
#endif // QTLS_SCHANNEL_P_H
|
File diff suppressed because it is too large
Load Diff
@ -37,8 +37,8 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSSLSOCKET_MAC_P_H
|
||||
#define QSSLSOCKET_MAC_P_H
|
||||
#ifndef QTLS_ST_P_H
|
||||
#define QTLS_ST_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
@ -52,6 +52,10 @@
|
||||
//
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
#include "qtlsbackend_st_p.h"
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qlist.h>
|
||||
@ -64,6 +68,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QTlsPrivate {
|
||||
|
||||
class QSecureTransportContext
|
||||
{
|
||||
public:
|
||||
@ -78,14 +84,13 @@ private:
|
||||
Q_DISABLE_COPY_MOVE(QSecureTransportContext)
|
||||
};
|
||||
|
||||
class QSslSocketBackendPrivate : public QSslSocketPrivate
|
||||
class TlsCryptographSecureTransport : public TlsCryptograph
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QSslSocket)
|
||||
public:
|
||||
QSslSocketBackendPrivate();
|
||||
virtual ~QSslSocketBackendPrivate();
|
||||
TlsCryptographSecureTransport();
|
||||
~TlsCryptographSecureTransport() override;
|
||||
|
||||
// Final-overriders (QSslSocketPrivate):
|
||||
void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
|
||||
void continueHandshake() override;
|
||||
void disconnected() override;
|
||||
void disconnectFromHost() override;
|
||||
@ -94,17 +99,9 @@ public:
|
||||
void startClientEncryption() override;
|
||||
void startServerEncryption() override;
|
||||
void transmit() override;
|
||||
QList<QSslError> tlsErrors() const override;
|
||||
|
||||
static QList<QSslError> verify(QList<QSslCertificate> certificateChain,
|
||||
const QString &hostName);
|
||||
|
||||
static bool importPkcs12(QIODevice *device,
|
||||
QSslKey *key, QSslCertificate *cert,
|
||||
QList<QSslCertificate> *caCertificates,
|
||||
const QByteArray &passPhrase);
|
||||
|
||||
static QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher);
|
||||
static SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &cipher);
|
||||
SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph);
|
||||
|
||||
private:
|
||||
// SSL context management/properties:
|
||||
@ -121,18 +118,24 @@ private:
|
||||
bool checkSslErrors();
|
||||
bool startHandshake();
|
||||
|
||||
bool isHandshakeComplete() const {return connectionEncrypted && !renegotiating;}
|
||||
bool isHandshakeComplete() const;
|
||||
|
||||
// IO callbacks:
|
||||
static OSStatus ReadCallback(QSslSocketBackendPrivate *socket, char *data, size_t *dataLength);
|
||||
static OSStatus WriteCallback(QSslSocketBackendPrivate *plainSocket, const char *data, size_t *dataLength);
|
||||
static OSStatus ReadCallback(TlsCryptographSecureTransport *socket, char *data, size_t *dataLength);
|
||||
static OSStatus WriteCallback(TlsCryptographSecureTransport *plainSocket, const char *data, size_t *dataLength);
|
||||
|
||||
QSecureTransportContext context;
|
||||
bool renegotiating = false;
|
||||
QSslSocket *q = nullptr;
|
||||
QSslSocketPrivate *d = nullptr;
|
||||
bool shutdown = false;
|
||||
QList<QSslError> sslErrors;
|
||||
|
||||
Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate)
|
||||
Q_DISABLE_COPY_MOVE(TlsCryptographSecureTransport)
|
||||
};
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
#endif // QTLS_ST_P_H
|
@ -40,7 +40,10 @@
|
||||
#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
|
||||
@ -199,6 +202,50 @@ TlsKey *X509Certificate::publicKey() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
|
||||
TlsCryptograph::~TlsCryptograph() = default;
|
||||
|
||||
void TlsCryptograph::checkSettingSslContext(QSharedPointer<QSslContext> tlsContext)
|
||||
{
|
||||
Q_UNUSED(tlsContext);
|
||||
}
|
||||
|
||||
QSharedPointer<QSslContext> TlsCryptograph::sslContext() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void TlsCryptograph::enableHandshakeContinuation()
|
||||
{
|
||||
}
|
||||
|
||||
void TlsCryptograph::cancelCAFetch()
|
||||
{
|
||||
}
|
||||
|
||||
bool TlsCryptograph::hasUndecryptedData() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QOcspResponse> TlsCryptograph::ocsps() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool TlsCryptograph::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
|
||||
{
|
||||
return QSslSocketPrivate::isMatchingHostname(cert, peerName);
|
||||
}
|
||||
|
||||
bool TlsCryptograph::isMatchingHostname(const QString &cn, const QString &hostname)
|
||||
{
|
||||
return QSslSocketPrivate::isMatchingHostname(cn, hostname);
|
||||
}
|
||||
|
||||
#endif // QT_CONFIG(ssl)
|
||||
|
||||
#if QT_CONFIG(dtls)
|
||||
DtlsBase::~DtlsBase() = default;
|
||||
#endif // QT_CONFIG(dtls)
|
||||
@ -228,6 +275,30 @@ bool QTlsBackend::isValid() const
|
||||
return true;
|
||||
}
|
||||
|
||||
long QTlsBackend::tlsLibraryVersionNumber() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString QTlsBackend::tlsLibraryVersionString() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
long QTlsBackend::tlsLibraryBuildVersionNumber() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString QTlsBackend::tlsLibraryBuildVersionString() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void QTlsBackend::ensureInitialized() const
|
||||
{
|
||||
}
|
||||
|
||||
QString QTlsBackend::backendName() const
|
||||
{
|
||||
return QStringLiteral("dummyTLS");
|
||||
@ -248,6 +319,12 @@ QTlsPrivate::X509Certificate *QTlsBackend::createCertificate() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> QTlsBackend::systemCaCertificates() const
|
||||
{
|
||||
REPORT_MISSING_SUPPORT("does not provide system CA certificates");
|
||||
return {};
|
||||
}
|
||||
|
||||
QTlsPrivate::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
|
||||
{
|
||||
REPORT_MISSING_SUPPORT("does not support QSslSocket");
|
||||
@ -441,4 +518,189 @@ void QTlsBackend::resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend)
|
||||
#endif // QT_CONFIG(ssl)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
QSslCipher QTlsBackend::createCiphersuite(const QString &descriptionOneLine, int bits, int supportedBits)
|
||||
{
|
||||
QSslCipher ciph;
|
||||
|
||||
const auto descriptionList = QStringView{descriptionOneLine}.split(QLatin1Char(' '), Qt::SkipEmptyParts);
|
||||
if (descriptionList.size() > 5) {
|
||||
ciph.d->isNull = false;
|
||||
ciph.d->name = descriptionList.at(0).toString();
|
||||
|
||||
QString protoString = descriptionList.at(1).toString();
|
||||
ciph.d->protocolString = protoString;
|
||||
ciph.d->protocol = QSsl::UnknownProtocol;
|
||||
if (protoString == QLatin1String("TLSv1"))
|
||||
ciph.d->protocol = QSsl::TlsV1_0;
|
||||
else if (protoString == QLatin1String("TLSv1.1"))
|
||||
ciph.d->protocol = QSsl::TlsV1_1;
|
||||
else if (protoString == QLatin1String("TLSv1.2"))
|
||||
ciph.d->protocol = QSsl::TlsV1_2;
|
||||
else if (protoString == QLatin1String("TLSv1.3"))
|
||||
ciph.d->protocol = QSsl::TlsV1_3;
|
||||
|
||||
if (descriptionList.at(2).startsWith(QLatin1String("Kx=")))
|
||||
ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3).toString();
|
||||
if (descriptionList.at(3).startsWith(QLatin1String("Au=")))
|
||||
ciph.d->authenticationMethod = descriptionList.at(3).mid(3).toString();
|
||||
if (descriptionList.at(4).startsWith(QLatin1String("Enc=")))
|
||||
ciph.d->encryptionMethod = descriptionList.at(4).mid(4).toString();
|
||||
ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == QLatin1String("export"));
|
||||
|
||||
ciph.d->bits = bits;
|
||||
ciph.d->supportedBits = supportedBits;
|
||||
}
|
||||
|
||||
return ciph;
|
||||
}
|
||||
|
||||
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(QLatin1Char('-'));
|
||||
if (bits.size() >= 2) {
|
||||
if (bits.size() == 2 || bits.size() == 3)
|
||||
ciph.d->keyExchangeMethod = QLatin1String("RSA");
|
||||
else if (bits.front() == QLatin1String("DH") || bits.front() == QLatin1String("DHE"))
|
||||
ciph.d->keyExchangeMethod = QLatin1String("DH");
|
||||
else if (bits.front() == QLatin1String("ECDH") || bits.front() == QLatin1String("ECDHE"))
|
||||
ciph.d->keyExchangeMethod = QLatin1String("ECDH");
|
||||
else
|
||||
qCWarning(lcSsl) << "Unknown Kx" << ciph.d->name;
|
||||
|
||||
if (bits.size() == 2 || bits.size() == 3)
|
||||
ciph.d->authenticationMethod = QLatin1String("RSA");
|
||||
else if (ciph.d->name.contains(QLatin1String("-ECDSA-")))
|
||||
ciph.d->authenticationMethod = QLatin1String("ECDSA");
|
||||
else if (ciph.d->name.contains(QLatin1String("-RSA-")))
|
||||
ciph.d->authenticationMethod = QLatin1String("RSA");
|
||||
else
|
||||
qCWarning(lcSsl) << "Unknown Au" << ciph.d->name;
|
||||
|
||||
if (ciph.d->name.contains(QLatin1String("RC4-"))) {
|
||||
ciph.d->encryptionMethod = QLatin1String("RC4(128)");
|
||||
ciph.d->bits = 128;
|
||||
ciph.d->supportedBits = 128;
|
||||
} else if (ciph.d->name.contains(QLatin1String("DES-CBC3-"))) {
|
||||
ciph.d->encryptionMethod = QLatin1String("3DES(168)");
|
||||
ciph.d->bits = 168;
|
||||
ciph.d->supportedBits = 168;
|
||||
} else if (ciph.d->name.contains(QLatin1String("AES128-"))) {
|
||||
ciph.d->encryptionMethod = QLatin1String("AES(128)");
|
||||
ciph.d->bits = 128;
|
||||
ciph.d->supportedBits = 128;
|
||||
} else if (ciph.d->name.contains(QLatin1String("AES256-GCM"))) {
|
||||
ciph.d->encryptionMethod = QLatin1String("AESGCM(256)");
|
||||
ciph.d->bits = 256;
|
||||
ciph.d->supportedBits = 256;
|
||||
} else if (ciph.d->name.contains(QLatin1String("AES256-"))) {
|
||||
ciph.d->encryptionMethod = QLatin1String("AES(256)");
|
||||
ciph.d->bits = 256;
|
||||
ciph.d->supportedBits = 256;
|
||||
} else if (ciph.d->name.contains(QLatin1String("NULL-"))) {
|
||||
ciph.d->encryptionMethod = QLatin1String("NULL");
|
||||
} else {
|
||||
qCWarning(lcSsl) << "Unknown Enc" << ciph.d->name;
|
||||
}
|
||||
}
|
||||
return ciph;
|
||||
}
|
||||
|
||||
QSslCipher QTlsBackend::createCipher(const QString &name, 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->protocol = protocol;
|
||||
cipher.d->protocolString = protocolString;
|
||||
return cipher;
|
||||
}
|
||||
|
||||
QList<QSslCipher> QTlsBackend::defaultCiphers()
|
||||
{
|
||||
return QSslSocketPrivate::defaultCiphers();
|
||||
}
|
||||
|
||||
QList<QSslCipher> QTlsBackend::defaultDtlsCiphers()
|
||||
{
|
||||
return QSslSocketPrivate::defaultDtlsCiphers();
|
||||
}
|
||||
|
||||
void QTlsBackend::setDefaultCiphers(const QList<QSslCipher> &ciphers)
|
||||
{
|
||||
QSslSocketPrivate::setDefaultCiphers(ciphers);
|
||||
}
|
||||
|
||||
void QTlsBackend::setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
|
||||
{
|
||||
QSslSocketPrivate::setDefaultDtlsCiphers(ciphers);
|
||||
}
|
||||
|
||||
void QTlsBackend::setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers)
|
||||
{
|
||||
QSslSocketPrivate::setDefaultSupportedCiphers(ciphers);
|
||||
}
|
||||
|
||||
void QTlsBackend::resetDefaultEllipticCurves()
|
||||
{
|
||||
QSslSocketPrivate::resetDefaultEllipticCurves();
|
||||
}
|
||||
|
||||
void QTlsBackend::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
|
||||
{
|
||||
QSslSocketPrivate::setDefaultCaCertificates(certs);
|
||||
}
|
||||
|
||||
#endif // QT_CONFIG(ssl)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -40,20 +40,25 @@
|
||||
#include "qtlsbackend_openssl_p.h"
|
||||
#include "qtlskey_openssl_p.h"
|
||||
#include "qx509_openssl_p.h"
|
||||
#include "qtls_openssl_p.h"
|
||||
#include "qsslcipher_p.h"
|
||||
//#include "qsslsocket_p.h"
|
||||
#include "qsslcipher.h"
|
||||
|
||||
#if QT_CONFIG(dtls)
|
||||
#include "qdtls_openssl_p.h"
|
||||
#endif // QT_CONFIG(dtls)
|
||||
|
||||
// TLSTODO: Later, this code (ensure initialised, etc.)
|
||||
// must move from the socket to backend.
|
||||
#include "qsslsocket_p.h"
|
||||
//
|
||||
#include "qsslsocket_openssl_symbols_p.h"
|
||||
#include "qopenssl_p.h"
|
||||
|
||||
#include <qssl.h>
|
||||
|
||||
#include <qdir.h>
|
||||
#include <qdiriterator.h>
|
||||
#include <qlist.h>
|
||||
#include <qmutex.h>
|
||||
#include <qscopeguard.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -61,6 +66,36 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl");
|
||||
|
||||
Q_GLOBAL_STATIC(QRecursiveMutex, qt_opensslInitMutex)
|
||||
|
||||
static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphers,
|
||||
QList<QSslCipher> &defaultCiphers)
|
||||
{
|
||||
Q_ASSERT(connection);
|
||||
|
||||
STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(connection);
|
||||
for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
|
||||
if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
|
||||
const auto ciph = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
|
||||
if (!ciph.isNull()) {
|
||||
// Unconditionally exclude ADH and AECDH ciphers since they offer no MITM protection
|
||||
if (!ciph.name().toLower().startsWith(QLatin1String("adh")) &&
|
||||
!ciph.name().toLower().startsWith(QLatin1String("exp-adh")) &&
|
||||
!ciph.name().toLower().startsWith(QLatin1String("aecdh"))) {
|
||||
ciphers << ciph;
|
||||
|
||||
if (ciph.usedBits() >= 128)
|
||||
defaultCiphers << ciph;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool QTlsBackendOpenSSL::s_libraryLoaded = false;
|
||||
bool QTlsBackendOpenSSL::s_loadedCiphersAndCerts = false;
|
||||
int QTlsBackendOpenSSL::s_indexForSSLExtraData = -1;
|
||||
|
||||
QString QTlsBackendOpenSSL::getErrorsFromOpenSsl()
|
||||
{
|
||||
QString errorString;
|
||||
@ -88,6 +123,41 @@ void QTlsBackendOpenSSL::clearErrorQueue()
|
||||
Q_UNUSED(errs);
|
||||
}
|
||||
|
||||
bool QTlsBackendOpenSSL::ensureLibraryLoaded()
|
||||
{
|
||||
if (!q_resolveOpenSslSymbols())
|
||||
return false;
|
||||
|
||||
const QMutexLocker locker(qt_opensslInitMutex());
|
||||
|
||||
if (!s_libraryLoaded) {
|
||||
// Initialize OpenSSL.
|
||||
if (q_OPENSSL_init_ssl(0, nullptr) != 1)
|
||||
return false;
|
||||
|
||||
if (q_OpenSSL_version_num() < 0x10101000L) {
|
||||
qCWarning(lcTlsBackend, "QSslSocket: OpenSSL >= 1.1.1 is required; %s was found instead", q_OpenSSL_version(OPENSSL_VERSION));
|
||||
return false;
|
||||
}
|
||||
|
||||
q_SSL_load_error_strings();
|
||||
q_OpenSSL_add_all_algorithms();
|
||||
|
||||
s_indexForSSLExtraData = q_CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, 0L, nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
|
||||
// Initialize OpenSSL's random seed.
|
||||
if (!q_RAND_status()) {
|
||||
qWarning("Random number generator not seeded, disabling SSL support");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_libraryLoaded = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QTlsBackendOpenSSL::backendName() const
|
||||
{
|
||||
return builtinBackendNames[nameIndexOpenSSL];
|
||||
@ -95,9 +165,124 @@ QString QTlsBackendOpenSSL::backendName() const
|
||||
|
||||
bool QTlsBackendOpenSSL::isValid() const
|
||||
{
|
||||
// TLSTODO: backend should do initialization,
|
||||
// not socket.
|
||||
return QSslSocket::supportsSsl();
|
||||
return ensureLibraryLoaded();
|
||||
}
|
||||
|
||||
long QTlsBackendOpenSSL::tlsLibraryVersionNumber() const
|
||||
{
|
||||
return q_OpenSSL_version_num();
|
||||
}
|
||||
|
||||
QString QTlsBackendOpenSSL::tlsLibraryVersionString() const
|
||||
{
|
||||
const char *versionString = q_OpenSSL_version(OPENSSL_VERSION);
|
||||
if (!versionString)
|
||||
return QString();
|
||||
|
||||
return QString::fromLatin1(versionString);
|
||||
}
|
||||
|
||||
long QTlsBackendOpenSSL::tlsLibraryBuildVersionNumber() const
|
||||
{
|
||||
return OPENSSL_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
QString QTlsBackendOpenSSL::tlsLibraryBuildVersionString() const
|
||||
{
|
||||
// Using QStringLiteral to store the version string as unicode and
|
||||
// avoid false positives from Google searching the playstore for old
|
||||
// SSL versions. See QTBUG-46265
|
||||
return QStringLiteral(OPENSSL_VERSION_TEXT);
|
||||
}
|
||||
|
||||
void QTlsBackendOpenSSL::ensureInitialized() const
|
||||
{
|
||||
// Old qsslsocket_openssl calls supportsSsl() (which means
|
||||
// library found and symbols resolved, this already assured
|
||||
// by the fact we end up in this function (isValid() returned
|
||||
// true for the backend, see its code). The qsslsocket_openssl
|
||||
// proceedes with loading certificate, ciphers and elliptic
|
||||
// curves.
|
||||
ensureCiphersAndCertsLoaded();
|
||||
}
|
||||
|
||||
void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded() const
|
||||
{
|
||||
const QMutexLocker locker(qt_opensslInitMutex());
|
||||
|
||||
if (s_loadedCiphersAndCerts)
|
||||
return;
|
||||
s_loadedCiphersAndCerts = true;
|
||||
|
||||
resetDefaultCiphers();
|
||||
resetDefaultEllipticCurves();
|
||||
|
||||
#if QT_CONFIG(library)
|
||||
//load symbols needed to receive certificates from system store
|
||||
#if defined(Q_OS_QNX)
|
||||
QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
|
||||
#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
|
||||
// check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
|
||||
QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
|
||||
QStringList symLinkFilter;
|
||||
symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
|
||||
for (int a = 0; a < dirs.count(); ++a) {
|
||||
QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
|
||||
if (iterator.hasNext()) {
|
||||
QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // QT_CONFIG(library)
|
||||
// if on-demand loading was not enabled, load the certs now
|
||||
if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
|
||||
setDefaultCaCertificates(systemCaCertificates());
|
||||
#ifdef Q_OS_WIN
|
||||
//Enabled for fetching additional root certs from windows update on windows.
|
||||
//This flag is set false by setDefaultCaCertificates() indicating the app uses
|
||||
//its own cert bundle rather than the system one.
|
||||
//Same logic that disables the unix on demand cert loading.
|
||||
//Unlike unix, we do preload the certificates from the cert store.
|
||||
QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void QTlsBackendOpenSSL::resetDefaultCiphers()
|
||||
{
|
||||
SSL_CTX *myCtx = q_SSL_CTX_new(q_TLS_client_method());
|
||||
// Note, we assert, not just silently return/bail out early:
|
||||
// this should never happen and problems with OpenSSL's initialization
|
||||
// must be caught before this (see supportsSsl()).
|
||||
Q_ASSERT(myCtx);
|
||||
SSL *mySsl = q_SSL_new(myCtx);
|
||||
Q_ASSERT(mySsl);
|
||||
|
||||
QList<QSslCipher> ciphers;
|
||||
QList<QSslCipher> defaultCiphers;
|
||||
|
||||
q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
|
||||
|
||||
q_SSL_CTX_free(myCtx);
|
||||
q_SSL_free(mySsl);
|
||||
|
||||
setDefaultSupportedCiphers(ciphers);
|
||||
setDefaultCiphers(defaultCiphers);
|
||||
|
||||
#if QT_CONFIG(dtls)
|
||||
ciphers.clear();
|
||||
defaultCiphers.clear();
|
||||
myCtx = q_SSL_CTX_new(q_DTLS_client_method());
|
||||
if (myCtx) {
|
||||
mySsl = q_SSL_new(myCtx);
|
||||
if (mySsl) {
|
||||
q_loadCiphersForConnection(mySsl, ciphers, defaultCiphers);
|
||||
setDefaultDtlsCiphers(defaultCiphers);
|
||||
q_SSL_free(mySsl);
|
||||
}
|
||||
q_SSL_CTX_free(myCtx);
|
||||
}
|
||||
#endif // dtls
|
||||
}
|
||||
|
||||
QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
|
||||
@ -167,6 +352,98 @@ QTlsPrivate::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
|
||||
return new QTlsPrivate::X509CertificateOpenSSL;
|
||||
}
|
||||
|
||||
namespace QTlsPrivate {
|
||||
|
||||
// TLSTODO: remove.
|
||||
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
|
||||
QList<QByteArray> fetchSslCertificateData();
|
||||
#endif
|
||||
|
||||
QList<QSslCertificate> systemCaCertificates();
|
||||
|
||||
#ifndef Q_OS_DARWIN
|
||||
QList<QSslCertificate> systemCaCertificates()
|
||||
{
|
||||
#ifdef QSSLSOCKET_DEBUG
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
#endif
|
||||
QList<QSslCertificate> systemCerts;
|
||||
#if defined(Q_OS_WIN)
|
||||
HCERTSTORE hSystemStore;
|
||||
hSystemStore = CertOpenSystemStoreW(0, L"ROOT");
|
||||
if (hSystemStore) {
|
||||
PCCERT_CONTEXT pc = nullptr;
|
||||
while (1) {
|
||||
pc = CertFindCertificateInStore(hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, pc);
|
||||
if (!pc)
|
||||
break;
|
||||
QByteArray der(reinterpret_cast<const char *>(pc->pbCertEncoded),
|
||||
static_cast<int>(pc->cbCertEncoded));
|
||||
QSslCertificate cert(der, QSsl::Der);
|
||||
systemCerts.append(cert);
|
||||
}
|
||||
CertCloseStore(hSystemStore, 0);
|
||||
}
|
||||
#elif defined(Q_OS_UNIX)
|
||||
QSet<QString> certFiles;
|
||||
QDir currentDir;
|
||||
QStringList nameFilters;
|
||||
QList<QByteArray> directories;
|
||||
QSsl::EncodingFormat platformEncodingFormat;
|
||||
# ifndef Q_OS_ANDROID
|
||||
directories = QSslSocketPrivate::unixRootCertDirectories();
|
||||
nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
|
||||
platformEncodingFormat = QSsl::Pem;
|
||||
# else
|
||||
// Q_OS_ANDROID
|
||||
QByteArray ministroPath = qgetenv("MINISTRO_SSL_CERTS_PATH"); // Set by Ministro
|
||||
directories << ministroPath;
|
||||
nameFilters << QLatin1String("*.der");
|
||||
platformEncodingFormat = QSsl::Der;
|
||||
# ifndef Q_OS_ANDROID_EMBEDDED
|
||||
if (ministroPath.isEmpty()) {
|
||||
QList<QByteArray> certificateData = fetchSslCertificateData();
|
||||
for (int i = 0; i < certificateData.size(); ++i) {
|
||||
systemCerts.append(QSslCertificate::fromData(certificateData.at(i), QSsl::Der));
|
||||
}
|
||||
} else
|
||||
# endif //Q_OS_ANDROID_EMBEDDED
|
||||
# endif //Q_OS_ANDROID
|
||||
{
|
||||
currentDir.setNameFilters(nameFilters);
|
||||
for (int a = 0; a < directories.count(); a++) {
|
||||
currentDir.setPath(QLatin1String(directories.at(a)));
|
||||
QDirIterator it(currentDir);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
// use canonical path here to not load the same certificate twice if symlinked
|
||||
certFiles.insert(it.fileInfo().canonicalFilePath());
|
||||
}
|
||||
}
|
||||
for (const QString& file : qAsConst(certFiles))
|
||||
systemCerts.append(QSslCertificate::fromPath(file, platformEncodingFormat));
|
||||
# ifndef Q_OS_ANDROID
|
||||
systemCerts.append(QSslCertificate::fromPath(QLatin1String("/etc/pki/tls/certs/ca-bundle.crt"), QSsl::Pem)); // Fedora, Mandriva
|
||||
systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/share/certs/ca-root-nss.crt"), QSsl::Pem)); // FreeBSD's ca_root_nss
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
#ifdef QSSLSOCKET_DEBUG
|
||||
qCDebug(lcTlsBackend) << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
|
||||
qCDebug(lcTlsBackend) << "imported " << systemCerts.count() << " certificates";
|
||||
#endif
|
||||
|
||||
return systemCerts;
|
||||
}
|
||||
#endif // !Q_OS_DARWIN
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
QList<QSslCertificate> QTlsBackendOpenSSL::systemCaCertificates() const
|
||||
{
|
||||
return QTlsPrivate::systemCaCertificates();
|
||||
}
|
||||
|
||||
QTlsPrivate::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier() const
|
||||
{
|
||||
#if QT_CONFIG(dtls)
|
||||
@ -177,6 +454,11 @@ QTlsPrivate::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier()
|
||||
#endif // QT_CONFIG(dtls)
|
||||
}
|
||||
|
||||
QTlsPrivate::TlsCryptograph *QTlsBackendOpenSSL::createTlsCryptograph() const
|
||||
{
|
||||
return new QTlsPrivate::TlsCryptographOpenSSL;
|
||||
}
|
||||
|
||||
QTlsPrivate::DtlsCryptograph *QTlsBackendOpenSSL::createDtlsCryptograph(QDtls *q, int mode) const
|
||||
{
|
||||
#if QT_CONFIG(dtls)
|
||||
@ -233,10 +515,7 @@ QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
|
||||
if (name.isEmpty())
|
||||
return nid;
|
||||
|
||||
// TLSTODO: check if it's needed! The fact we are here,
|
||||
// means OpenSSL was loaded, symbols resolved. Is it because
|
||||
// of ensureCiphers(AndCertificates)Loaded ?
|
||||
QSslSocketPrivate::ensureInitialized();
|
||||
ensureInitialized(); // TLSTODO: check if it's needed!
|
||||
#ifndef OPENSSL_NO_EC
|
||||
const QByteArray curveNameLatin1 = name.toLatin1();
|
||||
nid = q_OBJ_sn2nid(curveNameLatin1.data());
|
||||
@ -254,10 +533,7 @@ QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
|
||||
if (name.isEmpty())
|
||||
return nid;
|
||||
|
||||
// TLSTODO: check if it's needed! The fact we are here,
|
||||
// means OpenSSL was loaded, symbols resolved. Is it because
|
||||
// of ensureCiphers(AndCertificates)Loaded ?
|
||||
QSslSocketPrivate::ensureInitialized();
|
||||
ensureInitialized();
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
const QByteArray curveNameLatin1 = name.toLatin1();
|
||||
@ -336,4 +612,19 @@ bool QTlsBackendOpenSSL::isTlsNamedCurve(int id) const
|
||||
return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
|
||||
}
|
||||
|
||||
QString QTlsBackendOpenSSL::msgErrorsDuringHandshake()
|
||||
{
|
||||
return QSslSocket::tr("Error during SSL handshake: %1").arg(getErrorsFromOpenSsl());
|
||||
}
|
||||
|
||||
QSslCipher QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher)
|
||||
{
|
||||
Q_ASSERT(cipher);
|
||||
char buf [256] = {};
|
||||
const QString desc = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf)));
|
||||
int supportedBits = 0;
|
||||
const int bits = q_SSL_CIPHER_get_bits(cipher, &supportedBits);
|
||||
return createCiphersuite(desc, bits, supportedBits);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -54,22 +54,44 @@
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
#include "qssldiffiehellmanparameters.h"
|
||||
#include "qsslcertificate.h"
|
||||
#include "qtlsbackend_p.h"
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qlist.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QTlsBackendOpenSSL final : public QTlsBackend
|
||||
{
|
||||
public:
|
||||
|
||||
static QString getErrorsFromOpenSsl();
|
||||
static void logAndClearErrorQueue();
|
||||
static void clearErrorQueue();
|
||||
|
||||
static bool ensureLibraryLoaded();
|
||||
// Index used in SSL_get_ex_data to get the matching TlsCryptographerOpenSSL:
|
||||
static bool s_libraryLoaded;
|
||||
static bool s_loadedCiphersAndCerts;
|
||||
static int s_indexForSSLExtraData;
|
||||
|
||||
static QString msgErrorsDuringHandshake();
|
||||
static QSslCipher qt_OpenSSL_cipher_to_QSslCipher(const SSL_CIPHER *cipher);
|
||||
private:
|
||||
|
||||
QString backendName() const override;
|
||||
bool isValid() const override;
|
||||
long tlsLibraryVersionNumber() const override;
|
||||
QString tlsLibraryVersionString() const override;
|
||||
long tlsLibraryBuildVersionNumber() const override;
|
||||
QString tlsLibraryBuildVersionString() const override;
|
||||
|
||||
void ensureInitialized() const override;
|
||||
void ensureCiphersAndCertsLoaded() const;
|
||||
static void resetDefaultCiphers();
|
||||
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
||||
@ -80,7 +102,9 @@ private:
|
||||
|
||||
// QSslCertificate:
|
||||
QTlsPrivate::X509Certificate *createCertificate() const override;
|
||||
QList<QSslCertificate> systemCaCertificates() const override;
|
||||
|
||||
QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
|
||||
QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const override;
|
||||
QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(QDtls *q, int mode) const override;
|
||||
|
||||
|
@ -62,11 +62,12 @@
|
||||
#endif
|
||||
|
||||
#include <QtNetwork/qsslcertificate.h>
|
||||
#include <QtNetwork/qsslerror.h>
|
||||
#include <QtNetwork/qsslcipher.h>
|
||||
#include <QtNetwork/qsslkey.h>
|
||||
#include <QtNetwork/qssl.h>
|
||||
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
#include <QtCore/qnamespace.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
@ -78,11 +79,17 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSslPreSharedKeyAuthenticator;
|
||||
class QSslSocketPrivate;
|
||||
class QHostAddress;
|
||||
class QSslContext;
|
||||
|
||||
class QSslSocket;
|
||||
class QByteArray;
|
||||
class QSslCipher;
|
||||
class QUdpSocket;
|
||||
class QIODevice;
|
||||
class QSslError;
|
||||
class QSslKey;
|
||||
|
||||
namespace QTlsPrivate {
|
||||
@ -93,9 +100,8 @@ namespace QTlsPrivate {
|
||||
// however strange they are, for now preserved to ease the transition
|
||||
// (this may change in future - for example, 'decodeDer' is not just
|
||||
// decoding DER, it's initializing a key from DER. Note, QSslKey requires
|
||||
// a real TLS library because private keys tend to be encrypted. This
|
||||
// base class does not need a working TLS library.
|
||||
class TlsKey {
|
||||
// a real TLS library because private keys tend to be encrypted.
|
||||
class Q_NETWORK_PRIVATE_EXPORT TlsKey {
|
||||
public:
|
||||
virtual ~TlsKey();
|
||||
|
||||
@ -137,7 +143,7 @@ public:
|
||||
|
||||
// An abstraction hiding OpenSSL's X509 or our generic
|
||||
// 'derData'-based code.
|
||||
class X509Certificate
|
||||
class Q_NETWORK_PRIVATE_EXPORT X509Certificate
|
||||
{
|
||||
public:
|
||||
virtual ~X509Certificate();
|
||||
@ -191,12 +197,43 @@ using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertif
|
||||
QList<QSslCertificate> *caCertificates,
|
||||
const QByteArray &passPhrase);
|
||||
|
||||
#if QT_CONFIG(ssl)
|
||||
// TLS over TCP. Handshake, encryption/decryption.
|
||||
class Q_NETWORK_PRIVATE_EXPORT TlsCryptograph : public QObject
|
||||
{
|
||||
public:
|
||||
virtual ~TlsCryptograph();
|
||||
|
||||
virtual void init(QSslSocket *q, QSslSocketPrivate *d) = 0;
|
||||
virtual void checkSettingSslContext(QSharedPointer<QSslContext> tlsContext);
|
||||
virtual QSharedPointer<QSslContext> sslContext() const;
|
||||
|
||||
virtual QList<QSslError> tlsErrors() const = 0;
|
||||
|
||||
virtual void startClientEncryption() = 0;
|
||||
virtual void startServerEncryption() = 0;
|
||||
virtual void continueHandshake() = 0;
|
||||
virtual void enableHandshakeContinuation();
|
||||
virtual void disconnectFromHost() = 0;
|
||||
virtual void disconnected() = 0;
|
||||
virtual void cancelCAFetch();
|
||||
virtual QSslCipher sessionCipher() const = 0;
|
||||
virtual QSsl::SslProtocol sessionProtocol() const = 0;
|
||||
|
||||
virtual void transmit() = 0;
|
||||
virtual bool hasUndecryptedData() const;
|
||||
virtual QList<QOcspResponse> ocsps() const;
|
||||
|
||||
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
|
||||
static bool isMatchingHostname(const QString &cn, const QString &hostname);
|
||||
};
|
||||
#else
|
||||
class TlsCryptograph;
|
||||
#endif // QT_CONFIG(ssl)
|
||||
|
||||
#if QT_CONFIG(dtls)
|
||||
|
||||
class DtlsBase
|
||||
class Q_NETWORK_PRIVATE_EXPORT DtlsBase
|
||||
{
|
||||
public:
|
||||
virtual ~DtlsBase();
|
||||
@ -217,7 +254,7 @@ public:
|
||||
};
|
||||
|
||||
// DTLS cookie: generation and verification.
|
||||
class DtlsCookieVerifier : virtual public DtlsBase
|
||||
class Q_NETWORK_EXPORT DtlsCookieVerifier : virtual public DtlsBase
|
||||
{
|
||||
public:
|
||||
virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
|
||||
@ -226,7 +263,7 @@ public:
|
||||
};
|
||||
|
||||
// TLS over UDP. Handshake, encryption/decryption.
|
||||
class DtlsCryptograph : virtual public DtlsBase
|
||||
class Q_NETWORK_PRIVATE_EXPORT DtlsCryptograph : virtual public DtlsBase
|
||||
{
|
||||
public:
|
||||
|
||||
@ -279,6 +316,11 @@ public:
|
||||
~QTlsBackend() override;
|
||||
|
||||
virtual bool isValid() const;
|
||||
virtual long tlsLibraryVersionNumber() const;
|
||||
virtual QString tlsLibraryVersionString() const;
|
||||
virtual long tlsLibraryBuildVersionNumber() const;
|
||||
virtual QString tlsLibraryBuildVersionString() const;
|
||||
virtual void ensureInitialized() const;
|
||||
|
||||
virtual QString backendName() const = 0;
|
||||
virtual QList<QSsl::SslProtocol> supportedProtocols() const = 0;
|
||||
@ -289,6 +331,8 @@ public:
|
||||
virtual QTlsPrivate::TlsKey *createKey() const;
|
||||
virtual QTlsPrivate::X509Certificate *createCertificate() const;
|
||||
|
||||
virtual QList<QSslCertificate> systemCaCertificates() const;
|
||||
|
||||
// TLS and DTLS:
|
||||
virtual QTlsPrivate::TlsCryptograph *createTlsCryptograph() const;
|
||||
virtual QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(class QDtls *qObject, int mode) const;
|
||||
@ -338,6 +382,31 @@ public:
|
||||
|
||||
static void resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend);
|
||||
|
||||
static void setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint,
|
||||
int hintLength, unsigned maxIdentityLen, unsigned maxPskLen);
|
||||
static void setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity,
|
||||
const QByteArray &identityHint, unsigned maxPskLen);
|
||||
#if QT_CONFIG(ssl)
|
||||
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);
|
||||
|
||||
// Those statics are implemented using QSslSocketPrivate (which is not exported,
|
||||
// unlike QTlsBackend).
|
||||
static QList<QSslCipher> defaultCiphers();
|
||||
static QList<QSslCipher> defaultDtlsCiphers();
|
||||
|
||||
static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
|
||||
static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
|
||||
static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
|
||||
|
||||
static void resetDefaultEllipticCurves();
|
||||
|
||||
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
||||
#endif // QT_CONFIG(ssl)
|
||||
|
||||
Q_DISABLE_COPY_MOVE(QTlsBackend)
|
||||
};
|
||||
|
||||
|
@ -62,7 +62,18 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSchannelBackend : public QTlsBackend
|
||||
{
|
||||
public:
|
||||
static void ensureInitializedImplementation();
|
||||
|
||||
private:
|
||||
long tlsLibraryVersionNumber() const override;
|
||||
QString tlsLibraryVersionString() const override;
|
||||
long tlsLibraryBuildVersionNumber() const override;
|
||||
QString tlsLibraryBuildVersionString() const override;
|
||||
void ensureInitialized() const override;
|
||||
|
||||
static void resetDefaultCiphers();
|
||||
|
||||
QString backendName() const override;
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
||||
@ -71,8 +82,15 @@ private:
|
||||
QTlsPrivate::TlsKey *createKey() const override;
|
||||
QTlsPrivate::X509Certificate *createCertificate() const override;
|
||||
|
||||
QTlsPrivate::TlsCryptograph * createTlsCryptograph() const override;
|
||||
|
||||
QList<QSslCertificate> systemCaCertificates() const override;
|
||||
static QList<QSslCertificate> systemCaCertificatesImplementation();
|
||||
|
||||
QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
|
||||
QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
|
||||
|
||||
static bool s_loadedCiphersAndCerts;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -40,11 +40,234 @@
|
||||
#include "qtlsbackend_st_p.h"
|
||||
#include "qtlskey_st_p.h"
|
||||
#include "qx509_st_p.h"
|
||||
#include "qtls_st_p.h"
|
||||
|
||||
#include <QtCore/qsysinfo.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
|
||||
|
||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.securetransport");
|
||||
|
||||
namespace QTlsPrivate {
|
||||
|
||||
QList<QSslCertificate> systemCaCertificates(); // defined in qsslsocket_mac_shared.cpp
|
||||
|
||||
SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode);
|
||||
|
||||
QSslCipher QSslCipher_from_SSLCipherSuite(SSLCipherSuite cipher)
|
||||
{
|
||||
QString name;
|
||||
switch (cipher) {
|
||||
// Sorted as in CipherSuite.h (and groupped by their RFC)
|
||||
// TLS addenda using AES, per RFC 3268
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA:
|
||||
name = QLatin1String("AES128-SHA");
|
||||
break;
|
||||
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
|
||||
name = QLatin1String("DHE-RSA-AES128-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||
name = QLatin1String("AES256-SHA");
|
||||
break;
|
||||
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
name = QLatin1String("DHE-RSA-AES256-SHA");
|
||||
break;
|
||||
|
||||
// ECDSA addenda, RFC 4492
|
||||
case TLS_ECDH_ECDSA_WITH_NULL_SHA:
|
||||
name = QLatin1String("ECDH-ECDSA-NULL-SHA");
|
||||
break;
|
||||
case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
|
||||
name = QLatin1String("ECDH-ECDSA-RC4-SHA");
|
||||
break;
|
||||
case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
|
||||
name = QLatin1String("ECDH-ECDSA-DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
|
||||
name = QLatin1String("ECDH-ECDSA-AES128-SHA");
|
||||
break;
|
||||
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
|
||||
name = QLatin1String("ECDH-ECDSA-AES256-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
|
||||
name = QLatin1String("ECDHE-ECDSA-NULL-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
|
||||
name = QLatin1String("ECDHE-ECDSA-RC4-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
|
||||
name = QLatin1String("ECDHE-ECDSA-DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
|
||||
name = QLatin1String("ECDHE-ECDSA-AES128-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
|
||||
name = QLatin1String("ECDHE-ECDSA-AES256-SHA");
|
||||
break;
|
||||
case TLS_ECDH_RSA_WITH_NULL_SHA:
|
||||
name = QLatin1String("ECDH-RSA-NULL-SHA");
|
||||
break;
|
||||
case TLS_ECDH_RSA_WITH_RC4_128_SHA:
|
||||
name = QLatin1String("ECDH-RSA-RC4-SHA");
|
||||
break;
|
||||
case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
name = QLatin1String("ECDH-RSA-DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
|
||||
name = QLatin1String("ECDH-RSA-AES128-SHA");
|
||||
break;
|
||||
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
|
||||
name = QLatin1String("ECDH-RSA-AES256-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_RSA_WITH_NULL_SHA:
|
||||
name = QLatin1String("ECDHE-RSA-NULL-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
|
||||
name = QLatin1String("ECDHE-RSA-RC4-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
name = QLatin1String("ECDHE-RSA-DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
|
||||
name = QLatin1String("ECDHE-RSA-AES128-SHA");
|
||||
break;
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
name = QLatin1String("ECDHE-RSA-AES256-SHA");
|
||||
break;
|
||||
|
||||
// TLS 1.2 addenda, RFC 5246
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
name = QLatin1String("DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA256:
|
||||
name = QLatin1String("AES128-SHA256");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA256:
|
||||
name = QLatin1String("AES256-SHA256");
|
||||
break;
|
||||
case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
name = QLatin1String("DHE-RSA-DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
|
||||
name = QLatin1String("DHE-RSA-AES128-SHA256");
|
||||
break;
|
||||
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
|
||||
name = QLatin1String("DHE-RSA-AES256-SHA256");
|
||||
break;
|
||||
|
||||
// Addendum from RFC 4279, TLS PSK
|
||||
// all missing atm.
|
||||
|
||||
// RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption
|
||||
// all missing atm.
|
||||
|
||||
// Addenda from rfc 5288 AES Galois Counter Mode (CGM) Cipher Suites for TLS
|
||||
case TLS_RSA_WITH_AES_256_GCM_SHA384:
|
||||
name = QLatin1String("AES256-GCM-SHA384");
|
||||
break;
|
||||
|
||||
// RFC 5487 - PSK with SHA-256/384 and AES GCM
|
||||
// all missing atm.
|
||||
|
||||
// Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
|
||||
name = QLatin1String("ECDHE-ECDSA-AES128-SHA256");
|
||||
break;
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
|
||||
name = QLatin1String("ECDHE-ECDSA-AES256-SHA384");
|
||||
break;
|
||||
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
|
||||
name = QLatin1String("ECDH-ECDSA-AES128-SHA256");
|
||||
break;
|
||||
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
|
||||
name = QLatin1String("ECDH-ECDSA-AES256-SHA384");
|
||||
break;
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
|
||||
name = QLatin1String("ECDHE-RSA-AES128-SHA256");
|
||||
break;
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
|
||||
name = QLatin1String("ECDHE-RSA-AES256-SHA384");
|
||||
break;
|
||||
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
|
||||
name = QLatin1String("ECDH-RSA-AES128-SHA256");
|
||||
break;
|
||||
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
|
||||
name = QLatin1String("ECDH-RSA-AES256-SHA384");
|
||||
break;
|
||||
|
||||
// Addenda from rfc 5289 Elliptic Curve Cipher Suites
|
||||
// with SHA-256/384 and AES Galois Counter Mode (GCM)
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
|
||||
name = QLatin1String("ECDHE-RSA-AES256-GCM-SHA384");
|
||||
break;
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
||||
return QTlsBackend::createCiphersuite(name, QSsl::TlsV1_2, QLatin1String("TLSv1.2"));
|
||||
}
|
||||
|
||||
} // namespace QTlsPrivate
|
||||
|
||||
bool QSecureTransportBackend::s_loadedCiphersAndCerts = false;
|
||||
|
||||
QString QSecureTransportBackend::tlsLibraryVersionString() const
|
||||
{
|
||||
return QLatin1String("Secure Transport, ") + QSysInfo::prettyProductName();
|
||||
}
|
||||
|
||||
QString QSecureTransportBackend::tlsLibraryBuildVersionString() const
|
||||
{
|
||||
return tlsLibraryVersionString();
|
||||
}
|
||||
|
||||
void QSecureTransportBackend::ensureInitialized() const
|
||||
{
|
||||
const QMutexLocker locker(qt_securetransport_mutex());
|
||||
if (s_loadedCiphersAndCerts)
|
||||
return;
|
||||
|
||||
// We have to set it before setDefaultSupportedCiphers,
|
||||
// since this function can trigger static (global)'s initialization
|
||||
// and as a result - recursive ensureInitialized call
|
||||
// from QSslCertificatePrivate's ctor.
|
||||
s_loadedCiphersAndCerts = true;
|
||||
|
||||
const QTlsPrivate::QSecureTransportContext context(QTlsPrivate::qt_createSecureTransportContext(QSslSocket::SslClientMode));
|
||||
if (context) {
|
||||
QList<QSslCipher> ciphers;
|
||||
QList<QSslCipher> defaultCiphers;
|
||||
|
||||
size_t numCiphers = 0;
|
||||
// Fails only if any of parameters is null.
|
||||
SSLGetNumberSupportedCiphers(context, &numCiphers);
|
||||
QList<SSLCipherSuite> cfCiphers(numCiphers);
|
||||
// Fails only if any of parameter is null or number of ciphers is wrong.
|
||||
SSLGetSupportedCiphers(context, cfCiphers.data(), &numCiphers);
|
||||
|
||||
for (size_t i = 0; i < size_t(cfCiphers.size()); ++i) {
|
||||
const QSslCipher ciph(QTlsPrivate::QSslCipher_from_SSLCipherSuite(cfCiphers.at(i)));
|
||||
if (!ciph.isNull()) {
|
||||
ciphers << ciph;
|
||||
if (ciph.usedBits() >= 128)
|
||||
defaultCiphers << ciph;
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultSupportedCiphers(ciphers);
|
||||
setDefaultCiphers(defaultCiphers);
|
||||
|
||||
if (!QSslSocketPrivate::rootCertOnDemandLoadingSupported())
|
||||
setDefaultCaCertificates(systemCaCertificates());
|
||||
} else {
|
||||
s_loadedCiphersAndCerts = false;
|
||||
}
|
||||
}
|
||||
|
||||
QString QSecureTransportBackend::backendName() const
|
||||
{
|
||||
return builtinBackendNames[nameIndexSecureTransport];
|
||||
@ -60,6 +283,11 @@ QTlsPrivate::X509Certificate *QSecureTransportBackend::createCertificate() const
|
||||
return new QTlsPrivate::X509CertificateSecureTransport;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> QSecureTransportBackend::systemCaCertificates() const
|
||||
{
|
||||
return QTlsPrivate::systemCaCertificates();
|
||||
}
|
||||
|
||||
QList<QSsl::SslProtocol> QSecureTransportBackend::supportedProtocols() const
|
||||
{
|
||||
QList<QSsl::SslProtocol> protocols;
|
||||
@ -104,5 +332,10 @@ QTlsPrivate::X509DerReaderPtr QSecureTransportBackend::X509DerReader() const
|
||||
return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
|
||||
}
|
||||
|
||||
QTlsPrivate::TlsCryptograph *QSecureTransportBackend::createTlsCryptograph() const
|
||||
{
|
||||
return new QTlsPrivate::TlsCryptographSecureTransport;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
|
@ -63,6 +63,11 @@ QT_BEGIN_NAMESPACE
|
||||
class QSecureTransportBackend : public QTlsBackend
|
||||
{
|
||||
private:
|
||||
|
||||
QString tlsLibraryVersionString() const override;
|
||||
virtual QString tlsLibraryBuildVersionString() const override;
|
||||
virtual void ensureInitialized() const override;
|
||||
|
||||
QString backendName() const override;
|
||||
|
||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||
@ -72,8 +77,14 @@ private:
|
||||
QTlsPrivate::TlsKey *createKey() const override;
|
||||
QTlsPrivate::X509Certificate *createCertificate() const override;
|
||||
|
||||
QList<QSslCertificate> systemCaCertificates() const override;
|
||||
|
||||
QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
|
||||
QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
|
||||
|
||||
QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
|
||||
|
||||
static bool s_loadedCiphersAndCerts;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
@ -37,15 +37,15 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QTLS_UTILS_P_H
|
||||
#define QTLS_UTILS_P_H
|
||||
#ifndef QWINCRYPT_P_H
|
||||
#define QWINCRYPT_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
@ -53,47 +53,29 @@
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
#if QT_CONFIG(openssl)
|
||||
#include <QtNetwork/private/qsslsocket_openssl_p.h>
|
||||
#endif
|
||||
|
||||
#include <QtNetwork/private/qssl_p.h>
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
#include <wincrypt.h>
|
||||
#ifndef HCRYPTPROV_LEGACY
|
||||
#define HCRYPTPROV_LEGACY HCRYPTPROV
|
||||
#endif // !HCRYPTPROV_LEGACY
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QTlslUtils
|
||||
{
|
||||
|
||||
template <class NativeTlsType, void (*Deleter)(NativeTlsType *)>
|
||||
void safe_delete(NativeTlsType *object)
|
||||
{
|
||||
if (object)
|
||||
Deleter(object);
|
||||
}
|
||||
|
||||
template<class NativeTlsType, int ok, int (*Deleter)(NativeTlsType *)>
|
||||
void safe_delete(NativeTlsType *object)
|
||||
{
|
||||
if (object) {
|
||||
if (Deleter(object) != ok) {
|
||||
qCWarning(lcSsl, "Failed to free a resource.");
|
||||
#if QT_CONFIG(openssl) // || wolfssl later
|
||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
||||
#endif // QT_CONFIG(openssl)
|
||||
}
|
||||
struct QHCertStoreDeleter {
|
||||
void operator()(HCERTSTORE store)
|
||||
{
|
||||
CertCloseStore(store, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class NativeTlsType>
|
||||
using Deleter = std::unique_ptr<NativeTlsType, void (*)(NativeTlsType *)>;
|
||||
|
||||
} // namespace QTlsUtils
|
||||
// A simple RAII type used by Schannel code and Window CA fetcher class:
|
||||
using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QTLS_UTILS_P_H
|
||||
#endif // QWINCRYPT_P_H
|
@ -52,7 +52,8 @@
|
||||
#include "qsslsocket_p.h" // Transitively includes Wincrypt.h
|
||||
|
||||
#if QT_CONFIG(openssl)
|
||||
#include "qsslsocket_openssl_p.h"
|
||||
#include "qopenssl_p.h"
|
||||
#include "qx509_openssl_p.h"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -77,7 +78,9 @@ Q_GLOBAL_STATIC(QWindowsCaRootFetcherThread, windowsCaRootFetcherThread);
|
||||
|
||||
#if QT_CONFIG(openssl)
|
||||
namespace {
|
||||
|
||||
// TLSTODO: we have to ask the currently active TLS backend about verification
|
||||
// support and get a function pointer. QT_CONFIG(openssl) check is becoming useless
|
||||
// as soon as we have several plugins.
|
||||
const QList<QSslCertificate> buildVerifiedChain(const QList<QSslCertificate> &caCertificates,
|
||||
PCCERT_CHAIN_CONTEXT chainContext,
|
||||
const QString &peerVerifyName)
|
||||
@ -123,7 +126,7 @@ const QList<QSslCertificate> buildVerifiedChain(const QList<QSslCertificate> &ca
|
||||
}
|
||||
|
||||
// We rely on OpenSSL's ability to find other problems.
|
||||
const auto tlsErrors = QSslSocketBackendPrivate::verify(caCertificates, verifiedChain, peerVerifyName);
|
||||
const auto tlsErrors = QTlsPrivate::X509CertificateOpenSSL::verify(caCertificates, verifiedChain, peerVerifyName);
|
||||
if (tlsErrors.size())
|
||||
verifiedChain.clear();
|
||||
|
||||
@ -195,7 +198,7 @@ void QWindowsCaRootFetcher::start()
|
||||
qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
|
||||
if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
|
||||
qCDebug(lcSsl) << " - SELF SIGNED";
|
||||
qCDebug(lcSsl) << "QSslSocketBackendPrivate::fetchCaRootForCert - dumping simple chains";
|
||||
qCDebug(lcSsl) << "QWindowsCaRootFetcher - dumping simple chains";
|
||||
for (unsigned int i = 0; i < chain->cChain; i++) {
|
||||
if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
|
||||
qCDebug(lcSsl) << " - TRUSTED SIMPLE CHAIN" << i;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
@ -40,15 +40,15 @@
|
||||
#ifndef QWINDOWSCAROOTFETCHER_P_H
|
||||
#define QWINDOWSCAROOTFETCHER_P_H
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "qsslsocket_p.h"
|
||||
|
||||
#include "qsslsocket.h"
|
||||
#include "qsslcertificate.h"
|
||||
#include "qsslsocket.h"
|
||||
|
||||
#include <memory>
|
||||
#include "qwincrypt_p.h"
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
|
@ -43,7 +43,8 @@
|
||||
#include "qx509_openssl_p.h"
|
||||
|
||||
#include "qsslsocket_openssl_symbols_p.h"
|
||||
|
||||
#include "qtlsbackend_openssl_p.h"
|
||||
#include "qtls_openssl_p.h"
|
||||
#include "qsslsocket.h"
|
||||
|
||||
#include <QtNetwork/qhostaddress.h>
|
||||
@ -356,8 +357,8 @@ extern "C" int qt_X509Callback(int ok, X509_STORE_CTX *ctx)
|
||||
|
||||
// TLSTODO: verification callback has to change as soon as TlsCryptographer is in place.
|
||||
// This is a temporary solution for now to ease the transition.
|
||||
const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
|
||||
+ QSslSocketBackendPrivate::errorOffsetInExData;
|
||||
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())))
|
||||
errors = ErrorListPtr(q_SSL_get_ex_data(ssl, offset));
|
||||
}
|
||||
@ -587,7 +588,7 @@ QList<QSslError> X509CertificateOpenSSL::verify(const QList<QSslCertificate> &ch
|
||||
// No need to add them again (and again) and also, if the default configuration
|
||||
// has its own set of CAs, this probably should not be amended by the ones
|
||||
// from the 'ROOT' store, since it's not what an application chose to trust.
|
||||
if (QSslSocketPrivate::s_loadRootCertsOnDemand)
|
||||
if (QSslSocketPrivate::rootCertOnDemandLoadingSupported())
|
||||
roots.append(QSslSocketPrivate::systemCaCertificates());
|
||||
#endif // Q_OS_WIN
|
||||
return verify(roots, chain, hostName);
|
||||
|
@ -53,8 +53,7 @@
|
||||
|
||||
#include <private/qtnetworkglobal_p.h>
|
||||
|
||||
// TLSTODO: only temporary, and only because of QSslErrorEntry!
|
||||
#include <private/qsslsocket_openssl_p.h>
|
||||
#include <private/qopenssl_p.h>
|
||||
|
||||
#include <private/qtlsbackend_p.h>
|
||||
#include <private/qx509_base_p.h>
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <QtNetwork/private/qsslsocket_openssl_symbols_p.h>
|
||||
#include <QtNetwork/private/qsslsocket_openssl_p.h>
|
||||
|
||||
#include <QtNetwork/qsslcertificate.h>
|
||||
#include <QtNetwork/qtcpserver.h>
|
||||
|
@ -59,7 +59,6 @@
|
||||
#include "private/qtlsbackend_p.h"
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include "private/qsslsocket_openssl_p.h"
|
||||
#include "private/qsslsocket_openssl_symbols_p.h"
|
||||
#endif // QT_NO_OPENSSL
|
||||
|
||||
@ -244,9 +243,6 @@ private slots:
|
||||
void writeBigChunk();
|
||||
void blacklistedCertificates();
|
||||
void versionAccessors();
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void sslOptions();
|
||||
#endif
|
||||
void encryptWithoutConnecting();
|
||||
void resume_data();
|
||||
void resume();
|
||||
@ -3001,60 +2997,6 @@ void tst_QSslSocket::versionAccessors()
|
||||
qDebug() << QString::number(QSslSocket::sslLibraryVersionNumber(), 16);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void tst_QSslSocket::sslOptions()
|
||||
{
|
||||
if (!QSslSocket::supportsSsl())
|
||||
return;
|
||||
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSslConfigurationPrivate::defaultSslOptions),
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE));
|
||||
#else
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSslConfigurationPrivate::defaultSslOptions),
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
|
||||
#endif
|
||||
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableEmptyFragments
|
||||
|QSsl::SslOptionDisableLegacyRenegotiation),
|
||||
long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE));
|
||||
|
||||
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableEmptyFragments),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableLegacyRenegotiation),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS));
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableEmptyFragments
|
||||
|QSsl::SslOptionDisableLegacyRenegotiation
|
||||
|QSsl::SslOptionDisableSessionTickets),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_CIPHER_SERVER_PREFERENCE)));
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_TICKET
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols,
|
||||
QSsl::SslOptionDisableEmptyFragments
|
||||
|QSsl::SslOptionDisableLegacyRenegotiation
|
||||
|QSsl::SslOptionDisableSessionTickets
|
||||
|QSsl::SslOptionDisableCompression),
|
||||
long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE)));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QSslSocket::encryptWithoutConnecting()
|
||||
{
|
||||
if (!QSslSocket::supportsSsl())
|
||||
|
@ -44,9 +44,6 @@
|
||||
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
#include <QtNetwork/private/qhostinfo_p.h>
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <QtNetwork/private/qsslsocket_openssl_p.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE(QSharedPointer<char>)
|
||||
|
Loading…
Reference in New Issue
Block a user