Convert QSslSocket(Backend)Private into plugin
All backend-specific code is now separated and removed from QSslSocket(Private) code. The original code is mostly preserved to avoid (as much as possible) regressions (and to simplify code-review). Fixes: QTBUG-91173 Task-number: QTBUG-65922 Change-Id: I3ac4ba35d952162c8d6dc62d747cbd62dca0ef78 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> (cherry picked from commit 9391ba55149336c395b866b24dc9b844334d50da)
This commit is contained in:
parent
fac23d695f
commit
b477d823ad
@ -43,10 +43,9 @@ qt_internal_add_module(Network
|
|||||||
socket/qudpsocket.cpp socket/qudpsocket.h
|
socket/qudpsocket.cpp socket/qudpsocket.h
|
||||||
ssl/qasn1element.cpp ssl/qasn1element_p.h
|
ssl/qasn1element.cpp ssl/qasn1element_p.h
|
||||||
ssl/qpassworddigestor.cpp ssl/qpassworddigestor.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/qsslcertificate.cpp ssl/qsslcertificate.h ssl/qsslcertificate_p.h
|
||||||
ssl/qsslcertificateextension.cpp ssl/qsslcertificateextension.h ssl/qsslcertificateextension_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.cpp ssl/qtlsbackend_p.h
|
||||||
ssl/qtlsbackend_cert.cpp ssl/qtlsbackend_cert_p.h
|
ssl/qtlsbackend_cert.cpp ssl/qtlsbackend_cert_p.h
|
||||||
ssl/qx509_base.cpp ssl/qx509_base_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
|
qt_internal_extend_target(Network CONDITION QT_FEATURE_schannel AND QT_FEATURE_ssl
|
||||||
SOURCES
|
SOURCES
|
||||||
ssl/qsslsocket_qt.cpp
|
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/qtlsbackend_schannel_p.h
|
||||||
ssl/qtlskey_generic.cpp ssl/qtlskey_generic_p.h
|
ssl/qtlskey_generic.cpp ssl/qtlskey_generic_p.h
|
||||||
ssl/qtlskey_schannel.cpp ssl/qtlskey_schannel_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
|
qt_internal_extend_target(Network CONDITION QT_FEATURE_securetransport AND QT_FEATURE_ssl
|
||||||
SOURCES
|
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_mac_shared.cpp
|
||||||
ssl/qsslsocket_qt.cpp
|
ssl/qsslsocket_qt.cpp
|
||||||
ssl/qtlskey_generic.cpp ssl/qtlskey_generic_p.h
|
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
|
SOURCES
|
||||||
ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h
|
ssl/qsslcontext_openssl.cpp ssl/qsslcontext_openssl_p.h
|
||||||
ssl/qssldiffiehellmanparameters_openssl.cpp
|
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/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/qtlskey_openssl.cpp ssl/qtlskey_openssl_p.h
|
||||||
ssl/qtlsbackend_openssl.cpp ssl/qtlsbackend_openssl_p.h
|
ssl/qtlsbackend_openssl.cpp ssl/qtlsbackend_openssl_p.h
|
||||||
ssl/qx509_openssl.cpp ssl/qx509_openssl_p.h
|
ssl/qx509_openssl.cpp ssl/qx509_openssl_p.h
|
||||||
|
@ -55,4 +55,6 @@
|
|||||||
#include <QtCore/private/qglobal_p.h>
|
#include <QtCore/private/qglobal_p.h>
|
||||||
#include <QtNetwork/private/qtnetwork-config_p.h>
|
#include <QtNetwork/private/qtnetwork-config_p.h>
|
||||||
|
|
||||||
|
#define Q_NETWORK_PRIVATE_EXPORT Q_NETWORK_EXPORT
|
||||||
|
|
||||||
#endif // QTNETWORKGLOBAL_P_H
|
#endif // QTNETWORKGLOBAL_P_H
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
|
|
||||||
#include "qsslpresharedkeyauthenticator_p.h"
|
#include "qsslpresharedkeyauthenticator_p.h"
|
||||||
#include "qsslsocket_openssl_symbols_p.h"
|
#include "qsslsocket_openssl_symbols_p.h"
|
||||||
#include "qsslsocket_openssl_p.h"
|
|
||||||
#include "qsslcertificate_p.h"
|
#include "qsslcertificate_p.h"
|
||||||
#include "qdtls_openssl_p.h"
|
#include "qdtls_openssl_p.h"
|
||||||
#include "qx509_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;
|
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) {
|
if (!generic) {
|
||||||
qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, cannot generate cookie");
|
qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, cannot generate cookie");
|
||||||
return 0;
|
return 0;
|
||||||
@ -252,7 +251,7 @@ extern "C" int q_X509DtlsCallback(int ok, X509_STORE_CTX *ctx)
|
|||||||
return 0;
|
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) {
|
if (!generic) {
|
||||||
qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, handshake failure");
|
qCWarning(lcSsl, "SSL_get_ex_data returned nullptr, handshake failure");
|
||||||
return 0;
|
return 0;
|
||||||
@ -273,7 +272,7 @@ extern "C" unsigned q_PSK_client_callback(SSL *ssl, const char *hint, char *iden
|
|||||||
unsigned max_psk_len)
|
unsigned max_psk_len)
|
||||||
{
|
{
|
||||||
auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
|
auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
|
||||||
QSslSocketBackendPrivate::s_indexForSSLExtraData));
|
QTlsBackendOpenSSL::s_indexForSSLExtraData));
|
||||||
if (!dtls)
|
if (!dtls)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -285,7 +284,7 @@ extern "C" unsigned q_PSK_server_callback(SSL *ssl, const char *identity, unsign
|
|||||||
unsigned max_psk_len)
|
unsigned max_psk_len)
|
||||||
{
|
{
|
||||||
auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
|
auto *dtls = static_cast<dtlsopenssl::DtlsState *>(q_SSL_get_ex_data(ssl,
|
||||||
QSslSocketBackendPrivate::s_indexForSSLExtraData));
|
QTlsBackendOpenSSL::s_indexForSSLExtraData));
|
||||||
if (!dtls)
|
if (!dtls)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -693,7 +692,7 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int set = q_SSL_set_ex_data(newConnection.data(),
|
const int set = q_SSL_set_ex_data(newConnection.data(),
|
||||||
QSslSocketBackendPrivate::s_indexForSSLExtraData,
|
QTlsBackendOpenSSL::s_indexForSSLExtraData,
|
||||||
this);
|
this);
|
||||||
|
|
||||||
if (set != 1 && configurationCopy->peerVerifyMode != QSslSocket::VerifyNone) {
|
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());
|
const int ret = q_DTLSv1_listen(dtls.tlsConnection.data(), peer.data());
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
// Since 1.1 - it's a fatal error (not so in 1.0.2 for non-blocking socket)
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,7 +1030,7 @@ bool QDtlsPrivateOpenSSL::continueHandshake(QUdpSocket *socket, const QByteArray
|
|||||||
default:
|
default:
|
||||||
storePeerCertificates();
|
storePeerCertificates();
|
||||||
setDtlsError(QDtlsError::TlsFatalError,
|
setDtlsError(QDtlsError::TlsFatalError,
|
||||||
QSslSocketBackendPrivate::msgErrorsDuringHandshake());
|
QTlsBackendOpenSSL::msgErrorsDuringHandshake());
|
||||||
dtls.reset();
|
dtls.reset();
|
||||||
handshakeState = QDtls::HandshakeNotStarted;
|
handshakeState = QDtls::HandshakeNotStarted;
|
||||||
return false;
|
return false;
|
||||||
@ -1192,7 +1191,7 @@ qint64 QDtlsPrivateOpenSSL::writeDatagramEncrypted(QUdpSocket *socket,
|
|||||||
// DTLSTODO: we don't know yet what to do. Tests needed - probably,
|
// 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).
|
// some errors can be just ignored (it's UDP, not TCP after all).
|
||||||
// Unlike QSslSocket we do not abort though.
|
// Unlike QSslSocket we do not abort though.
|
||||||
QString description(QSslSocketBackendPrivate::getErrorsFromOpenSsl());
|
QString description(QTlsBackendOpenSSL::getErrorsFromOpenSsl());
|
||||||
if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) {
|
if (socket->error() != QAbstractSocket::UnknownSocketError && description.isEmpty()) {
|
||||||
setDtlsError(QDtlsError::UnderlyingSocketError, socket->errorString());
|
setDtlsError(QDtlsError::UnderlyingSocketError, socket->errorString());
|
||||||
} else {
|
} else {
|
||||||
@ -1258,7 +1257,7 @@ QByteArray QDtlsPrivateOpenSSL::decryptDatagram(QUdpSocket *socket, const QByteA
|
|||||||
default:
|
default:
|
||||||
setDtlsError(QDtlsError::TlsNonFatalError,
|
setDtlsError(QDtlsError::TlsNonFatalError,
|
||||||
QDtls::tr("Error while reading: %1")
|
QDtls::tr("Error while reading: %1")
|
||||||
.arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()));
|
.arg(QTlsBackendOpenSSL::getErrorsFromOpenSsl()));
|
||||||
return dgram;
|
return dgram;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1276,15 +1275,10 @@ unsigned QDtlsPrivateOpenSSL::pskClientCallback(const char *hint, char *identity
|
|||||||
if (hint) {
|
if (hint) {
|
||||||
identityHint.clear();
|
identityHint.clear();
|
||||||
identityHint.append(hint);
|
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
|
QTlsBackend::setupClientPskAuth(&authenticator, hint ? identityHint.constData() : nullptr,
|
||||||
authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
|
hint ? std::strlen(hint) : 0, max_identity_len, max_psk_len);
|
||||||
|
|
||||||
pskAuthenticator.swap(authenticator);
|
pskAuthenticator.swap(authenticator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1314,11 +1308,8 @@ unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned c
|
|||||||
{
|
{
|
||||||
QSslPreSharedKeyAuthenticator authenticator;
|
QSslPreSharedKeyAuthenticator authenticator;
|
||||||
// Fill in some read-only fields (for the user)
|
// Fill in some read-only fields (for the user)
|
||||||
authenticator.d->identityHint = dtlsConfiguration.preSharedKeyIdentityHint;
|
QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint,
|
||||||
authenticator.d->identity = identity;
|
max_psk_len);
|
||||||
authenticator.d->maximumIdentityLength = 0; // user cannot set an identity
|
|
||||||
authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
|
|
||||||
|
|
||||||
pskAuthenticator.swap(authenticator);
|
pskAuthenticator.swap(authenticator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1367,7 +1358,7 @@ bool QDtlsPrivateOpenSSL::verifyPeer()
|
|||||||
name = dtls.udpSocket->peerName();
|
name = dtls.udpSocket->peerName();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QSslSocketPrivate::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
|
if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
|
||||||
errors << QSslError(QSslError::HostNameMismatch, dtlsConfiguration.peerCertificate);
|
errors << QSslError(QSslError::HostNameMismatch, dtlsConfiguration.peerCertificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1418,9 +1409,10 @@ void QDtlsPrivateOpenSSL::fetchNegotiatedParameters()
|
|||||||
{
|
{
|
||||||
Q_ASSERT(dtls.tlsConnection.data());
|
Q_ASSERT(dtls.tlsConnection.data());
|
||||||
|
|
||||||
const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data());
|
if (const SSL_CIPHER *cipher = q_SSL_get_current_cipher(dtls.tlsConnection.data()))
|
||||||
sessionCipher = cipher ? QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher)
|
sessionCipher = QTlsBackendOpenSSL::qt_OpenSSL_cipher_to_QSslCipher(cipher);
|
||||||
: QSslCipher();
|
else
|
||||||
|
sessionCipher = {};
|
||||||
|
|
||||||
// Note: cipher's protocol version will be reported as either TLS 1.0 or
|
// 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?).
|
// 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 <openssl/ossl_typ.h>
|
||||||
|
|
||||||
#include "qtlsbackend_openssl_p.h"
|
#include "qtlsbackend_openssl_p.h"
|
||||||
|
#include "qtls_openssl_p.h"
|
||||||
#include "qdtls_base_p.h"
|
#include "qdtls_base_p.h"
|
||||||
#include "qdtls_p.h"
|
#include "qdtls_p.h"
|
||||||
|
|
||||||
#include <private/qsslcontext_openssl_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/qsslpresharedkeyauthenticator.h>
|
||||||
#include <QtNetwork/qhostaddress.h>
|
#include <QtNetwork/qhostaddress.h>
|
||||||
@ -185,7 +186,6 @@ private:
|
|||||||
QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
|
QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &tlsdgram) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
|
unsigned pskClientCallback(const char *hint, char *identity, unsigned max_identity_len,
|
||||||
unsigned char *psk, unsigned max_psk_len);
|
unsigned char *psk, unsigned max_psk_len);
|
||||||
unsigned pskServerCallback(const char *identity, unsigned char *psk,
|
unsigned pskServerCallback(const char *identity, unsigned char *psk,
|
||||||
|
@ -72,6 +72,10 @@ enum class QOcspRevocationReason
|
|||||||
RemoveFromCRL
|
RemoveFromCRL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace QTlsPrivate {
|
||||||
|
class TlsCryptographOpenSSL;
|
||||||
|
}
|
||||||
|
|
||||||
class QOcspResponse;
|
class QOcspResponse;
|
||||||
Q_NETWORK_EXPORT size_t qHash(const QOcspResponse &response, size_t seed = 0) noexcept;
|
Q_NETWORK_EXPORT size_t qHash(const QOcspResponse &response, size_t seed = 0) noexcept;
|
||||||
|
|
||||||
@ -99,7 +103,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool isEqual(const QOcspResponse &other) const;
|
bool isEqual(const QOcspResponse &other) const;
|
||||||
|
|
||||||
friend class QSslSocketBackendPrivate;
|
friend class QTlsPrivate::TlsCryptographOpenSSL;
|
||||||
friend bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
|
friend bool operator==(const QOcspResponse &lhs, const QOcspResponse &rhs)
|
||||||
{ return lhs.isEqual(rhs); }
|
{ return lhs.isEqual(rhs); }
|
||||||
friend bool operator!=(const QOcspResponse &lhs, const QOcspResponse &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 <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
#include "qsslsocket_p.h"
|
|
||||||
|
|
||||||
#include <QtCore/qlist.h>
|
#include "qsslsocket_p.h"
|
||||||
#include <QtCore/qstring.h>
|
#include "qsslcipher.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <qt_windows.h>
|
#include <qt_windows.h>
|
||||||
@ -82,6 +81,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif // Q_OS_WIN
|
#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/asn1.h>
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
@ -100,92 +101,17 @@
|
|||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/tls1.h>
|
#include <openssl/tls1.h>
|
||||||
|
|
||||||
#if QT_CONFIG(opensslv11)
|
|
||||||
#include <openssl/dh.h>
|
#include <openssl/dh.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
struct QSslErrorEntry {
|
struct QSslErrorEntry {
|
||||||
int code;
|
int code = 0;
|
||||||
int depth;
|
int depth = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QSslErrorEntry, Q_PRIMITIVE_TYPE);
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -153,8 +153,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
|
QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
|
||||||
friend class QSslCertificatePrivate;
|
|
||||||
friend class QSslSocketBackendPrivate;
|
|
||||||
friend class QTlsBackend;
|
friend class QTlsBackend;
|
||||||
|
|
||||||
friend Q_NETWORK_EXPORT size_t qHash(const QSslCertificate &key, size_t seed) noexcept;
|
friend Q_NETWORK_EXPORT size_t qHash(const QSslCertificate &key, size_t seed) noexcept;
|
||||||
|
@ -71,10 +71,8 @@ public:
|
|||||||
~QSslCertificatePrivate();
|
~QSslCertificatePrivate();
|
||||||
|
|
||||||
QList<QSslCertificateExtension> extensions() const;
|
QList<QSslCertificateExtension> extensions() const;
|
||||||
static bool isBlacklisted(const QSslCertificate &certificate);
|
Q_NETWORK_PRIVATE_EXPORT static bool isBlacklisted(const QSslCertificate &certificate);
|
||||||
static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
|
Q_NETWORK_PRIVATE_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
|
||||||
|
|
||||||
friend class QSslSocketBackendPrivate;
|
|
||||||
|
|
||||||
QAtomicInt ref;
|
QAtomicInt ref;
|
||||||
std::unique_ptr<QTlsPrivate::X509Certificate> backend;
|
std::unique_ptr<QTlsPrivate::X509Certificate> backend;
|
||||||
|
@ -85,7 +85,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// ### Qt 7: make implicitly shared
|
// ### Qt 7: make implicitly shared
|
||||||
std::unique_ptr<QSslCipherPrivate> d;
|
std::unique_ptr<QSslCipherPrivate> d;
|
||||||
friend class QSslSocketBackendPrivate;
|
friend class QTlsBackend;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_SHARED(QSslCipher)
|
Q_DECLARE_SHARED(QSslCipher)
|
||||||
|
@ -201,7 +201,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class QSslSocket;
|
friend class QSslSocket;
|
||||||
friend class QSslConfigurationPrivate;
|
friend class QSslConfigurationPrivate;
|
||||||
friend class QSslSocketBackendPrivate;
|
|
||||||
friend class QSslContext;
|
friend class QSslContext;
|
||||||
friend class QDtlsBasePrivate;
|
friend class QDtlsBasePrivate;
|
||||||
friend class dtlsopenssl::DtlsState;
|
friend class dtlsopenssl::DtlsState;
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QSslConfigurationPrivate: public QSharedData
|
class Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate: public QSharedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QSslConfigurationPrivate()
|
QSslConfigurationPrivate()
|
||||||
@ -114,11 +114,11 @@ public:
|
|||||||
bool allowRootCertOnDemandLoading;
|
bool allowRootCertOnDemandLoading;
|
||||||
bool peerSessionShared;
|
bool peerSessionShared;
|
||||||
|
|
||||||
Q_AUTOTEST_EXPORT static bool peerSessionWasShared(const QSslConfiguration &configuration);
|
static bool peerSessionWasShared(const QSslConfiguration &configuration);
|
||||||
|
|
||||||
QSsl::SslOptions sslOptions;
|
QSsl::SslOptions sslOptions;
|
||||||
|
|
||||||
Q_AUTOTEST_EXPORT static const QSsl::SslOptions defaultSslOptions;
|
static const QSsl::SslOptions defaultSslOptions;
|
||||||
|
|
||||||
QList<QSslEllipticCurve> ellipticCurves;
|
QList<QSslEllipticCurve> ellipticCurves;
|
||||||
|
|
||||||
|
@ -43,12 +43,13 @@
|
|||||||
#include <QtNetwork/qsslsocket.h>
|
#include <QtNetwork/qsslsocket.h>
|
||||||
#include <QtNetwork/qssldiffiehellmanparameters.h>
|
#include <QtNetwork/qssldiffiehellmanparameters.h>
|
||||||
|
|
||||||
|
#include "private/qopenssl_p.h"
|
||||||
#include "private/qssl_p.h"
|
#include "private/qssl_p.h"
|
||||||
#include "private/qsslsocket_p.h"
|
#include "private/qsslsocket_p.h"
|
||||||
#include "private/qsslcontext_openssl_p.h"
|
#include "private/qsslcontext_openssl_p.h"
|
||||||
#include "private/qsslsocket_openssl_p.h"
|
|
||||||
#include "private/qsslsocket_openssl_symbols_p.h"
|
#include "private/qsslsocket_openssl_symbols_p.h"
|
||||||
#include "private/qssldiffiehellmanparameters_p.h"
|
#include "private/qssldiffiehellmanparameters_p.h"
|
||||||
|
#include "private/qtlsbackend_openssl_p.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -61,10 +62,17 @@ Q_NETWORK_EXPORT void qt_ForceTlsSecurityLevel()
|
|||||||
*forceSecurityLevel() = true;
|
*forceSecurityLevel() = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// defined in qsslsocket_openssl.cpp:
|
namespace QTlsPrivate
|
||||||
extern int q_X509Callback(int ok, X509_STORE_CTX *ctx);
|
{
|
||||||
|
// 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 "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)
|
#if QT_CONFIG(dtls)
|
||||||
// defined in qdtls_openssl.cpp:
|
// 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);
|
extern "C" int q_ssl_sess_set_new_cb(SSL *context, SSL_SESSION *session);
|
||||||
#endif // TLS1_3_VERSION
|
#endif // TLS1_3_VERSION
|
||||||
|
|
||||||
// Defined in qsslsocket.cpp
|
|
||||||
QList<QSslCipher> q_getDefaultDtlsCiphers();
|
|
||||||
|
|
||||||
static inline QString msgErrorSettingBackendConfig(const QString &why)
|
static inline QString msgErrorSettingBackendConfig(const QString &why)
|
||||||
{
|
{
|
||||||
return QSslSocket::tr("Error when setting the OpenSSL configuration (%1)").arg(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);
|
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()
|
QSslContext::QSslContext()
|
||||||
: ctx(nullptr),
|
: ctx(nullptr),
|
||||||
pkey(nullptr),
|
pkey(nullptr),
|
||||||
@ -130,6 +185,12 @@ QSharedPointer<QSslContext> QSslContext::sharedFromConfiguration(QSslSocket::Ssl
|
|||||||
return sslContext;
|
return sslContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSharedPointer<QSslContext> QSslContext::sharedFromPrivateConfiguration(QSslSocket::SslMode mode, QSslConfigurationPrivate *privConfiguration,
|
||||||
|
bool allowRootCertOnDemandLoading)
|
||||||
|
{
|
||||||
|
return sharedFromConfiguration(mode, privConfiguration, allowRootCertOnDemandLoading);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
|
|
||||||
static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
|
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(
|
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;
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||||
return;
|
return;
|
||||||
@ -438,7 +499,7 @@ init_context:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable bug workarounds.
|
// 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);
|
q_SSL_CTX_set_options(sslContext->ctx, options);
|
||||||
|
|
||||||
// Tell OpenSSL to release memory early
|
// Tell OpenSSL to release memory early
|
||||||
@ -464,13 +525,13 @@ init_context:
|
|||||||
// Initialize ciphers
|
// Initialize ciphers
|
||||||
QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
|
QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers();
|
||||||
if (ciphers.isEmpty())
|
if (ciphers.isEmpty())
|
||||||
ciphers = isDtls ? q_getDefaultDtlsCiphers() : QSslSocketPrivate::defaultCiphers();
|
ciphers = isDtls ? QTlsBackend::defaultDtlsCiphers() : QTlsBackend::defaultCiphers();
|
||||||
|
|
||||||
const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
|
const QByteArray preTls13Ciphers = filterCiphers(ciphers, false);
|
||||||
|
|
||||||
if (preTls13Ciphers.size()) {
|
if (preTls13Ciphers.size()) {
|
||||||
if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, preTls13Ciphers.data())) {
|
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;
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -480,7 +541,7 @@ init_context:
|
|||||||
#ifdef TLS1_3_VERSION
|
#ifdef TLS1_3_VERSION
|
||||||
if (tls13Ciphers.size()) {
|
if (tls13Ciphers.size()) {
|
||||||
if (!q_SSL_CTX_set_ciphersuites(sslContext->ctx, tls13Ciphers.data())) {
|
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;
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||||
return;
|
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
|
// tell OpenSSL the directories where to look up the root certs on demand
|
||||||
const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
|
const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories();
|
||||||
int success = 1;
|
int success = 1;
|
||||||
@ -529,7 +590,7 @@ init_context:
|
|||||||
}
|
}
|
||||||
#endif // OPENSSL_VERSION_MAJOR
|
#endif // OPENSSL_VERSION_MAJOR
|
||||||
if (success != 1) {
|
if (success != 1) {
|
||||||
const auto qtErrors = QSslSocketBackendPrivate::getErrorsFromOpenSsl();
|
const auto qtErrors = QTlsBackendOpenSSL::getErrorsFromOpenSsl();
|
||||||
qCWarning(lcSsl) << "An error encountered while to set root certificates location:"
|
qCWarning(lcSsl) << "An error encountered while to set root certificates location:"
|
||||||
<< qtErrors;
|
<< qtErrors;
|
||||||
}
|
}
|
||||||
@ -545,7 +606,7 @@ init_context:
|
|||||||
|
|
||||||
// Load certificate
|
// Load certificate
|
||||||
if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) {
|
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;
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -572,14 +633,14 @@ init_context:
|
|||||||
sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
|
sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey
|
||||||
|
|
||||||
if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, pkey)) {
|
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;
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the certificate matches the private key.
|
// Check if the certificate matches the private key.
|
||||||
if (!q_SSL_CTX_check_private_key(sslContext->ctx)) {
|
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;
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -605,10 +666,10 @@ init_context:
|
|||||||
#if QT_CONFIG(dtls)
|
#if QT_CONFIG(dtls)
|
||||||
isDtls ? dtlscallbacks::q_X509DtlsCallback :
|
isDtls ? dtlscallbacks::q_X509DtlsCallback :
|
||||||
#endif // dtls
|
#endif // dtls
|
||||||
q_X509Callback;
|
QTlsPrivate::q_X509Callback;
|
||||||
|
|
||||||
if (!isDtls && configuration.handshakeMustInterruptOnError())
|
if (!isDtls && configuration.handshakeMustInterruptOnError())
|
||||||
verificationCallback = q_X509CallbackDirect;
|
verificationCallback = QTlsPrivate::q_X509CallbackDirect;
|
||||||
|
|
||||||
auto verificationMode = SSL_VERIFY_PEER;
|
auto verificationMode = SSL_VERIFY_PEER;
|
||||||
if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
|
if (!isDtls && sslContext->sslConfiguration.missingCertificateIsFatal())
|
||||||
@ -680,7 +741,7 @@ init_context:
|
|||||||
for (const auto &sslCurve : qcurves)
|
for (const auto &sslCurve : qcurves)
|
||||||
curves.push_back(sslCurve.id);
|
curves.push_back(sslCurve.id);
|
||||||
if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) {
|
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;
|
sslContext->errorCode = QSslError::UnspecifiedError;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -690,10 +751,6 @@ init_context:
|
|||||||
applyBackendConfig(sslContext);
|
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)
|
void QSslContext::applyBackendConfig(QSslContext *sslContext)
|
||||||
{
|
{
|
||||||
const QMap<QByteArray, QVariant> &conf = sslContext->sslConfiguration.backendConfiguration();
|
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
|
// This is our private, undocumented configuration option, existing only for
|
||||||
// the purpose of testing OCSP status responses. We don't even check this
|
// the purpose of testing OCSP status responses. We don't even check this
|
||||||
// callback was set. If no - the test must fail.
|
// 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)
|
if (conf.size() == 1)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,9 @@ public:
|
|||||||
bool allowRootCertOnDemandLoading);
|
bool allowRootCertOnDemandLoading);
|
||||||
static QSharedPointer<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
|
static QSharedPointer<QSslContext> sharedFromConfiguration(QSslSocket::SslMode mode, const QSslConfiguration &configuration,
|
||||||
bool allowRootCertOnDemandLoading);
|
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;
|
QSslError::SslError error() const;
|
||||||
QString errorString() const;
|
QString errorString() const;
|
||||||
|
@ -69,22 +69,22 @@ int q_DH_check(DH *dh, int *status)
|
|||||||
EVP_PKEY *key = q_EVP_PKEY_new();
|
EVP_PKEY *key = q_EVP_PKEY_new();
|
||||||
if (!key) {
|
if (!key) {
|
||||||
qCWarning(lcSsl, "EVP_PKEY_new failed");
|
qCWarning(lcSsl, "EVP_PKEY_new failed");
|
||||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto keyDeleter = qScopeGuard([key](){
|
const auto keyDeleter = qScopeGuard([key](){
|
||||||
q_EVP_PKEY_free(key);
|
q_EVP_PKEY_free(key);
|
||||||
});
|
});
|
||||||
if (!q_EVP_PKEY_set1_DH(key, dh)) {
|
if (!q_EVP_PKEY_set1_DH(key, dh)) {
|
||||||
qCWarning(lcSsl, "EVP_PKEY_set1_DH failed");
|
qCWarning(lcTlsBackend, "EVP_PKEY_set1_DH failed");
|
||||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
|
EVP_PKEY_CTX *keyCtx = q_EVP_PKEY_CTX_new(key, nullptr);
|
||||||
if (!keyCtx) {
|
if (!keyCtx) {
|
||||||
qCWarning(lcSsl, "EVP_PKEY_CTX_new failed");
|
qCWarning(lcTlsBackend, "EVP_PKEY_CTX_new failed");
|
||||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const auto ctxDeleter = qScopeGuard([keyCtx]{
|
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);
|
const int result = q_EVP_PKEY_param_check(keyCtx);
|
||||||
QSslSocketBackendPrivate::logAndClearErrorQueue();
|
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||||
// Note: unlike DH_check, we cannot obtain the 'status',
|
// Note: unlike DH_check, we cannot obtain the 'status',
|
||||||
// if the 'result' is 0 (actually the result is 1 only
|
// if the 'result' is 0 (actually the result is 1 only
|
||||||
// if this 'status' was 0). We could probably check the
|
// if this 'status' was 0). We could probably check the
|
||||||
|
@ -82,7 +82,6 @@ private:
|
|||||||
|
|
||||||
friend class QSslContext;
|
friend class QSslContext;
|
||||||
friend class QSslSocketPrivate;
|
friend class QSslSocketPrivate;
|
||||||
friend class QSslSocketBackendPrivate;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
|
Q_DECLARE_TYPEINFO(QSslEllipticCurve, Q_PRIMITIVE_TYPE);
|
||||||
|
@ -94,8 +94,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QExplicitlySharedDataPointer<QSslKeyPrivate> d;
|
QExplicitlySharedDataPointer<QSslKeyPrivate> d;
|
||||||
friend class QSslCertificate;
|
|
||||||
friend class QSslSocketBackendPrivate;
|
|
||||||
friend class QTlsBackend;
|
friend class QTlsBackend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +50,6 @@ QT_REQUIRE_CONFIG(ssl);
|
|||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QSslPreSharedKeyAuthenticatorPrivate;
|
class QSslPreSharedKeyAuthenticatorPrivate;
|
||||||
|
|
||||||
class QSslPreSharedKeyAuthenticator
|
class QSslPreSharedKeyAuthenticator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -76,8 +75,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
Q_NETWORK_EXPORT bool isEqual(const QSslPreSharedKeyAuthenticator &other) const;
|
Q_NETWORK_EXPORT bool isEqual(const QSslPreSharedKeyAuthenticator &other) const;
|
||||||
|
|
||||||
friend class QSslSocketBackendPrivate;
|
friend class QTlsBackend;
|
||||||
friend class QDtlsPrivateOpenSSL;
|
|
||||||
|
|
||||||
friend bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
|
friend bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
|
||||||
{ return lhs.isEqual(rhs); }
|
{ return lhs.isEqual(rhs); }
|
||||||
|
@ -386,16 +386,8 @@
|
|||||||
#include "qsslcipher.h"
|
#include "qsslcipher.h"
|
||||||
#include "qocspresponse.h"
|
#include "qocspresponse.h"
|
||||||
#include "qtlsbackend_p.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 "qsslconfiguration_p.h"
|
||||||
|
#include "qsslsocket_p.h"
|
||||||
|
|
||||||
#include <QtCore/qdebug.h>
|
#include <QtCore/qdebug.h>
|
||||||
#include <QtCore/qdir.h>
|
#include <QtCore/qdir.h>
|
||||||
@ -433,7 +425,7 @@ Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
|
|||||||
set to the one returned by the static method defaultCiphers().
|
set to the one returned by the static method defaultCiphers().
|
||||||
*/
|
*/
|
||||||
QSslSocket::QSslSocket(QObject *parent)
|
QSslSocket::QSslSocket(QObject *parent)
|
||||||
: QTcpSocket(*new QSslSocketBackendPrivate, parent)
|
: QTcpSocket(*new QSslSocketPrivate, parent)
|
||||||
{
|
{
|
||||||
Q_D(QSslSocket);
|
Q_D(QSslSocket);
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
@ -903,7 +895,8 @@ void QSslSocket::close()
|
|||||||
// On Windows, CertGetCertificateChain is probably still doing its
|
// On Windows, CertGetCertificateChain is probably still doing its
|
||||||
// job, if the socket is re-used, we want to ignore its reported
|
// job, if the socket is re-used, we want to ignore its reported
|
||||||
// root CA.
|
// root CA.
|
||||||
d->caToFetch = QSslCertificate{};
|
if (auto *backend = d->backend.get())
|
||||||
|
backend->cancelCAFetch();
|
||||||
|
|
||||||
if (!d->abortCalled && (encryptedBytesToWrite() || !d->writeBuffer.isEmpty()))
|
if (!d->abortCalled && (encryptedBytesToWrite() || !d->writeBuffer.isEmpty()))
|
||||||
flush();
|
flush();
|
||||||
@ -1210,7 +1203,9 @@ QSsl::SslProtocol QSslSocket::sessionProtocol() const
|
|||||||
QList<QOcspResponse> QSslSocket::ocspResponses() const
|
QList<QOcspResponse> QSslSocket::ocspResponses() const
|
||||||
{
|
{
|
||||||
Q_D(const QSslSocket);
|
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
|
QList<QSslError> QSslSocket::sslHandshakeErrors() const
|
||||||
{
|
{
|
||||||
Q_D(const QSslSocket);
|
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
|
\since 5.0
|
||||||
Returns the version number of the SSL library in use. Note that
|
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
|
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
|
time. If no SSL support is available then this will return -1.
|
||||||
undefined value.
|
|
||||||
*/
|
*/
|
||||||
long QSslSocket::sslLibraryVersionNumber()
|
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()
|
QString QSslSocket::sslLibraryVersionString()
|
||||||
{
|
{
|
||||||
return QSslSocketPrivate::sslLibraryVersionString();
|
if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse())
|
||||||
|
return tlsBackend->tlsLibraryVersionString();
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\since 5.4
|
\since 5.4
|
||||||
Returns the version number of the SSL library in use at compile
|
Returns the version number of the SSL library in use at compile
|
||||||
time. If no SSL support is available then this will return an
|
time. If no SSL support is available then this will return -1.
|
||||||
undefined value.
|
|
||||||
|
|
||||||
\sa sslLibraryVersionNumber()
|
\sa sslLibraryVersionNumber()
|
||||||
*/
|
*/
|
||||||
long QSslSocket::sslLibraryBuildVersionNumber()
|
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()
|
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()
|
void QSslSocket::continueInterruptedHandshake()
|
||||||
{
|
{
|
||||||
Q_D(QSslSocket);
|
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
|
// Make sure we don't process any signal from the CA fetcher
|
||||||
// (Windows):
|
// (Windows):
|
||||||
d->caToFetch = QSslCertificate{};
|
if (auto *backend = d->backend.get())
|
||||||
|
backend->cancelCAFetch();
|
||||||
|
|
||||||
// Perhaps emit closing()
|
// Perhaps emit closing()
|
||||||
if (d->state != ClosingState) {
|
if (d->state != ClosingState) {
|
||||||
@ -1982,6 +1989,8 @@ qint64 QSslSocket::writeData(const char *data, qint64 len)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
@ -1990,7 +1999,6 @@ QSslSocketPrivate::QSslSocketPrivate()
|
|||||||
, mode(QSslSocket::UnencryptedMode)
|
, mode(QSslSocket::UnencryptedMode)
|
||||||
, autoStartHandshake(false)
|
, autoStartHandshake(false)
|
||||||
, connectionEncrypted(false)
|
, connectionEncrypted(false)
|
||||||
, shutdown(false)
|
|
||||||
, ignoreAllSslErrors(false)
|
, ignoreAllSslErrors(false)
|
||||||
, readyReadEmittedPointer(nullptr)
|
, readyReadEmittedPointer(nullptr)
|
||||||
, allowRootCertOnDemandLoading(true)
|
, allowRootCertOnDemandLoading(true)
|
||||||
@ -1999,6 +2007,17 @@ QSslSocketPrivate::QSslSocketPrivate()
|
|||||||
, flushTriggered(false)
|
, flushTriggered(false)
|
||||||
{
|
{
|
||||||
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
|
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
|
\internal
|
||||||
*/
|
*/
|
||||||
void QSslSocketPrivate::init()
|
void QSslSocketPrivate::init()
|
||||||
{
|
{
|
||||||
|
// TLSTODO: delete those data members.
|
||||||
mode = QSslSocket::UnencryptedMode;
|
mode = QSslSocket::UnencryptedMode;
|
||||||
autoStartHandshake = false;
|
autoStartHandshake = false;
|
||||||
connectionEncrypted = false;
|
connectionEncrypted = false;
|
||||||
ignoreAllSslErrors = false;
|
ignoreAllSslErrors = false;
|
||||||
shutdown = false;
|
|
||||||
abortCalled = false;
|
abortCalled = false;
|
||||||
pendingClose = false;
|
pendingClose = false;
|
||||||
flushTriggered = false;
|
flushTriggered = false;
|
||||||
ocspResponses.clear();
|
// We don't want to clear the ignoreErrorsList, so
|
||||||
systemOrSslErrorDetected = false;
|
// that it is possible setting it before connecting.
|
||||||
// we don't want to clear the ignoreErrorsList, so
|
|
||||||
// that it is possible setting it before connecting
|
|
||||||
// ignoreErrorsList.clear();
|
|
||||||
|
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
writeBuffer.clear();
|
writeBuffer.clear();
|
||||||
configuration.peerCertificate.clear();
|
configuration.peerCertificate.clear();
|
||||||
configuration.peerCertificateChain.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
|
\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);
|
QMutexLocker locker(&globalData()->mutex);
|
||||||
globalData()->dtlsConfig.detach();
|
globalData()->dtlsConfig.detach();
|
||||||
@ -2113,7 +2186,7 @@ void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers)
|
|||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
QList<QSslCipher> q_getDefaultDtlsCiphers()
|
QList<QSslCipher> QSslSocketPrivate::defaultDtlsCiphers()
|
||||||
{
|
{
|
||||||
QSslSocketPrivate::ensureInitialized();
|
QSslSocketPrivate::ensureInitialized();
|
||||||
QMutexLocker locker(&globalData()->mutex);
|
QMutexLocker locker(&globalData()->mutex);
|
||||||
@ -2360,6 +2433,11 @@ bool QSslSocketPrivate::isPaused() const
|
|||||||
return paused;
|
return paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QSslSocketPrivate::setPaused(bool p)
|
||||||
|
{
|
||||||
|
paused = p;
|
||||||
|
}
|
||||||
|
|
||||||
bool QSslSocketPrivate::bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode)
|
bool QSslSocketPrivate::bind(const QHostAddress &address, quint16 port, QAbstractSocket::BindMode mode)
|
||||||
{
|
{
|
||||||
// this function is called from QAbstractSocket::bind
|
// this function is called from QAbstractSocket::bind
|
||||||
@ -2590,6 +2668,7 @@ void QSslSocketPrivate::_q_resumeImplementation()
|
|||||||
if (verifyErrorsHaveBeenIgnored()) {
|
if (verifyErrorsHaveBeenIgnored()) {
|
||||||
continueHandshake();
|
continueHandshake();
|
||||||
} else {
|
} else {
|
||||||
|
const auto sslErrors = backend->tlsErrors();
|
||||||
Q_ASSERT(!sslErrors.isEmpty());
|
Q_ASSERT(!sslErrors.isEmpty());
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
|
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, sslErrors.constFirst().errorString());
|
||||||
plainSocket->disconnectFromHost();
|
plainSocket->disconnectFromHost();
|
||||||
@ -2604,11 +2683,14 @@ void QSslSocketPrivate::_q_resumeImplementation()
|
|||||||
*/
|
*/
|
||||||
bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
|
bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(backend.get());
|
||||||
|
|
||||||
bool doEmitSslError;
|
bool doEmitSslError;
|
||||||
if (!ignoreErrorsList.empty()) {
|
if (!ignoreErrorsList.empty()) {
|
||||||
// check whether the errors we got are all in the list of expected errors
|
// 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)
|
// (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors)
|
||||||
// was called)
|
// was called)
|
||||||
|
const auto &sslErrors = backend->tlsErrors();
|
||||||
doEmitSslError = false;
|
doEmitSslError = false;
|
||||||
for (int a = 0; a < sslErrors.count(); a++) {
|
for (int a = 0; a < sslErrors.count(); a++) {
|
||||||
if (!ignoreErrorsList.contains(sslErrors.at(a))) {
|
if (!ignoreErrorsList.contains(sslErrors.at(a))) {
|
||||||
@ -2625,6 +2707,91 @@ bool QSslSocketPrivate::verifyErrorsHaveBeenIgnored()
|
|||||||
return !doEmitSslError;
|
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
|
\internal
|
||||||
*/
|
*/
|
||||||
@ -2643,9 +2810,9 @@ qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize)
|
|||||||
if (r2 < 0)
|
if (r2 < 0)
|
||||||
return (r > 0 ? r : r2);
|
return (r > 0 ? r : r2);
|
||||||
return r + r2;
|
return r + r2;
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
|
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
|
||||||
return QTcpSocketPrivate::peek(data, maxSize);
|
return QTcpSocketPrivate::peek(data, maxSize);
|
||||||
@ -2668,7 +2835,7 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize)
|
|||||||
//peek at data in the plain socket
|
//peek at data in the plain socket
|
||||||
if (plainSocket)
|
if (plainSocket)
|
||||||
return ret + plainSocket->peek(maxSize - ret.length());
|
return ret + plainSocket->peek(maxSize - ret.length());
|
||||||
else
|
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
} else {
|
} else {
|
||||||
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
|
//encrypted mode - the socket engine will read and decrypt data into the QIODevice buffer
|
||||||
@ -2708,6 +2875,82 @@ bool QSslSocketPrivate::flush()
|
|||||||
return plainSocket && plainSocket->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
|
\internal
|
||||||
*/
|
*/
|
||||||
@ -2716,6 +2959,14 @@ bool QSslSocketPrivate::rootCertOnDemandLoadingSupported()
|
|||||||
return s_loadRootCertsOnDemand;
|
return s_loadRootCertsOnDemand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
void QSslSocketPrivate::setRootCertOnDemandLoadingSupported(bool supported)
|
||||||
|
{
|
||||||
|
s_loadRootCertsOnDemand = supported;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
@ -2735,10 +2986,13 @@ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
|
|||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointer<QSslContext> sslContext)
|
void QSslSocketPrivate::checkSettingSslContext(QSslSocket* socket, QSharedPointer<QSslContext> tlsContext)
|
||||||
{
|
{
|
||||||
if (socket->d_func()->sslContextPointer.isNull())
|
if (!socket)
|
||||||
socket->d_func()->sslContextPointer = sslContext;
|
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)
|
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)
|
bool QSslSocketPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
|
||||||
@ -2852,6 +3112,61 @@ QTlsBackend *QSslSocketPrivate::tlsBackendInUse()
|
|||||||
return tlsBackend = QTlsBackend::findBackend(activeBackendName);
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#include "moc_qsslsocket.cpp"
|
#include "moc_qsslsocket.cpp"
|
||||||
|
@ -201,6 +201,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
Q_DECLARE_PRIVATE(QSslSocket)
|
Q_DECLARE_PRIVATE(QSslSocket)
|
||||||
Q_DISABLE_COPY_MOVE(QSslSocket)
|
Q_DISABLE_COPY_MOVE(QSslSocket)
|
||||||
|
|
||||||
Q_PRIVATE_SLOT(d_func(), void _q_connectedSlot())
|
Q_PRIVATE_SLOT(d_func(), void _q_connectedSlot())
|
||||||
Q_PRIVATE_SLOT(d_func(), void _q_hostFoundSlot())
|
Q_PRIVATE_SLOT(d_func(), void _q_hostFoundSlot())
|
||||||
Q_PRIVATE_SLOT(d_func(), void _q_disconnectedSlot())
|
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_flushWriteBuffer())
|
||||||
Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
|
Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
|
||||||
Q_PRIVATE_SLOT(d_func(), void _q_resumeImplementation())
|
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
|
#endif // QT_NO_SSL
|
||||||
|
@ -38,30 +38,22 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
//#define QSSLSOCKET_DEBUG
|
#include "qsslcertificate.h"
|
||||||
//#define QT_DECRYPT_SSL_TRAFFIC
|
|
||||||
|
|
||||||
#include "qssl_p.h"
|
#include <QtCore/qglobal.h>
|
||||||
#include "qsslsocket.h"
|
|
||||||
#include "qsslsocket_p.h"
|
|
||||||
|
|
||||||
#ifndef QT_NO_OPENSSL
|
#ifdef Q_OS_MACOS
|
||||||
# include "qsslsocket_openssl_p.h"
|
|
||||||
# include "qsslsocket_openssl_symbols_p.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "qsslcertificate_p.h"
|
#include "qtlsbackend_p.h"
|
||||||
|
|
||||||
#ifdef Q_OS_DARWIN
|
#include <private/qcore_mac_p.h>
|
||||||
# include <private/qcore_mac_p.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QtCore/qdebug.h>
|
#include <QtCore/qdebug.h>
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#include <CoreFoundation/CFArray.h>
|
||||||
# include <Security/Security.h>
|
#include <Security/Security.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#endif // Q_OS_MACOS
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -114,18 +106,17 @@ bool isCaCertificateTrusted(SecCertificateRef cfCert, int domain)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(lcSsl, "Error receiving trust for a CA certificate");
|
qCWarning(lcTlsBackend, "Error receiving trust for a CA certificate");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anon namespace
|
} // unnamed namespace
|
||||||
#endif // Q_OS_MACOS
|
#endif // Q_OS_MACOS
|
||||||
|
|
||||||
QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
namespace QTlsPrivate {
|
||||||
|
QList<QSslCertificate> systemCaCertificates()
|
||||||
{
|
{
|
||||||
ensureInitialized();
|
|
||||||
|
|
||||||
QList<QSslCertificate> systemCerts;
|
QList<QSslCertificate> systemCerts;
|
||||||
// SecTrustSettingsCopyCertificates is not defined on iOS.
|
// SecTrustSettingsCopyCertificates is not defined on iOS.
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
@ -152,5 +143,6 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
|
|||||||
#endif
|
#endif
|
||||||
return systemCerts;
|
return systemCerts;
|
||||||
}
|
}
|
||||||
|
} // namespace QTlsPrivate
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -52,13 +52,15 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "qsslsocket_openssl_p.h"
|
#include "qsslsocket_p.h"
|
||||||
#include <QtCore/QJniEnvironment>
|
#include <QtCore/QJniEnvironment>
|
||||||
#include <QtCore/QJniObject>
|
#include <QtCore/QJniObject>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData()
|
namespace QTlsPrivate {
|
||||||
|
|
||||||
|
QList<QByteArray> fetchSslCertificateData()
|
||||||
{
|
{
|
||||||
QList<QByteArray> certificateData;
|
QList<QByteArray> certificateData;
|
||||||
|
|
||||||
@ -86,4 +88,6 @@ QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData()
|
|||||||
return certificateData;
|
return certificateData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace QTlsPrivate
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
#include "qsslsocket_openssl_p.h"
|
#include "qopenssl_p.h"
|
||||||
#include <QtCore/qglobal.h>
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
#if QT_CONFIG(ocsp)
|
#if QT_CONFIG(ocsp)
|
||||||
|
@ -55,59 +55,25 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
#include <private/qtcpsocket_p.h>
|
#include <private/qtcpsocket_p.h>
|
||||||
#include "qsslkey.h"
|
|
||||||
#include "qsslconfiguration_p.h"
|
|
||||||
#include "qocspresponse.h"
|
#include "qocspresponse.h"
|
||||||
#ifndef QT_NO_OPENSSL
|
#include "qsslconfiguration_p.h"
|
||||||
#include <private/qsslcontext_openssl_p.h>
|
#include "qsslkey.h"
|
||||||
#else
|
#include "qtlsbackend_p.h"
|
||||||
class QSslContext;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QtCore/qlist.h>
|
#include <QtCore/qlist.h>
|
||||||
#include <QtCore/qstringlist.h>
|
|
||||||
#include <QtCore/qmutex.h>
|
#include <QtCore/qmutex.h>
|
||||||
|
#include <QtCore/qstringlist.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 <memory>
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
#if defined(Q_OS_MACOS)
|
class QSslContext;
|
||||||
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 QTlsBackend;
|
class QTlsBackend;
|
||||||
|
|
||||||
class QSslSocketPrivate : public QTcpSocketPrivate
|
class QSslSocketPrivate : public QTcpSocketPrivate
|
||||||
{
|
{
|
||||||
Q_DECLARE_PUBLIC(QSslSocket)
|
Q_DECLARE_PUBLIC(QSslSocket)
|
||||||
@ -122,14 +88,11 @@ public:
|
|||||||
QSslSocket::SslMode mode;
|
QSslSocket::SslMode mode;
|
||||||
bool autoStartHandshake;
|
bool autoStartHandshake;
|
||||||
bool connectionEncrypted;
|
bool connectionEncrypted;
|
||||||
bool shutdown;
|
|
||||||
bool ignoreAllSslErrors;
|
bool ignoreAllSslErrors;
|
||||||
QList<QSslError> ignoreErrorsList;
|
QList<QSslError> ignoreErrorsList;
|
||||||
bool* readyReadEmittedPointer;
|
bool* readyReadEmittedPointer;
|
||||||
|
|
||||||
QSslConfigurationPrivate configuration;
|
QSslConfigurationPrivate configuration;
|
||||||
QList<QSslError> sslErrors;
|
|
||||||
QSharedPointer<QSslContext> sslContextPointer;
|
|
||||||
|
|
||||||
// if set, this hostname is used for certificate validation instead of the hostname
|
// if set, this hostname is used for certificate validation instead of the hostname
|
||||||
// that was used for connecting to.
|
// that was used for connecting to.
|
||||||
@ -140,16 +103,14 @@ public:
|
|||||||
static bool s_loadRootCertsOnDemand;
|
static bool s_loadRootCertsOnDemand;
|
||||||
|
|
||||||
static bool supportsSsl();
|
static bool supportsSsl();
|
||||||
static long sslLibraryVersionNumber();
|
|
||||||
static QString sslLibraryVersionString();
|
|
||||||
static long sslLibraryBuildVersionNumber();
|
|
||||||
static QString sslLibraryBuildVersionString();
|
|
||||||
static void ensureInitialized();
|
static void ensureInitialized();
|
||||||
|
|
||||||
static QList<QSslCipher> defaultCiphers();
|
static QList<QSslCipher> defaultCiphers();
|
||||||
|
static QList<QSslCipher> defaultDtlsCiphers();
|
||||||
static QList<QSslCipher> supportedCiphers();
|
static QList<QSslCipher> supportedCiphers();
|
||||||
static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
|
static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
|
||||||
|
static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
|
||||||
static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
|
static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
|
||||||
static void resetDefaultCiphers();
|
|
||||||
|
|
||||||
static QList<QSslEllipticCurve> supportedEllipticCurves();
|
static QList<QSslEllipticCurve> supportedEllipticCurves();
|
||||||
static void setDefaultSupportedEllipticCurves(const QList<QSslEllipticCurve> &curves);
|
static void setDefaultSupportedEllipticCurves(const QList<QSslEllipticCurve> &curves);
|
||||||
@ -160,19 +121,19 @@ public:
|
|||||||
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
||||||
static void addDefaultCaCertificate(const QSslCertificate &cert);
|
static void addDefaultCaCertificate(const QSslCertificate &cert);
|
||||||
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
||||||
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QSslCertificate &cert,
|
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
|
||||||
const QString &peerName);
|
|
||||||
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
|
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
|
||||||
|
|
||||||
// The socket itself, including private slots.
|
// The socket itself, including private slots.
|
||||||
QTcpSocket *plainSocket;
|
QTcpSocket *plainSocket = nullptr;
|
||||||
void createPlainSocket(QIODevice::OpenMode openMode);
|
void createPlainSocket(QIODevice::OpenMode openMode);
|
||||||
static void pauseSocketNotifiers(QSslSocket*);
|
Q_NETWORK_EXPORT static void pauseSocketNotifiers(QSslSocket*);
|
||||||
static void resumeSocketNotifiers(QSslSocket*);
|
Q_NETWORK_EXPORT static void resumeSocketNotifiers(QSslSocket*);
|
||||||
// ### The 2 methods below should be made member methods once the QSslContext class is made public
|
// ### The 2 methods below should be made member methods once the QSslContext class is made public
|
||||||
static void checkSettingSslContext(QSslSocket*, QSharedPointer<QSslContext>);
|
static void checkSettingSslContext(QSslSocket*, QSharedPointer<QSslContext>);
|
||||||
static QSharedPointer<QSslContext> sslContext(QSslSocket *socket);
|
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;
|
bool bind(const QHostAddress &address, quint16, QAbstractSocket::BindMode) override;
|
||||||
void _q_connectedSlot();
|
void _q_connectedSlot();
|
||||||
void _q_hostFoundSlot();
|
void _q_hostFoundSlot();
|
||||||
@ -187,62 +148,59 @@ public:
|
|||||||
void _q_flushWriteBuffer();
|
void _q_flushWriteBuffer();
|
||||||
void _q_flushReadBuffer();
|
void _q_flushReadBuffer();
|
||||||
void _q_resumeImplementation();
|
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;
|
qint64 peek(char *data, qint64 maxSize) override;
|
||||||
virtual QByteArray peek(qint64 maxSize) override;
|
QByteArray peek(qint64 maxSize) override;
|
||||||
bool flush() override;
|
bool flush() override;
|
||||||
|
|
||||||
// Platform specific functions
|
void startClientEncryption();
|
||||||
virtual void startClientEncryption() = 0;
|
void startServerEncryption();
|
||||||
virtual void startServerEncryption() = 0;
|
void transmit();
|
||||||
virtual void transmit() = 0;
|
void disconnectFromHost();
|
||||||
virtual void disconnectFromHost() = 0;
|
void disconnected();
|
||||||
virtual void disconnected() = 0;
|
QSslCipher sessionCipher() const;
|
||||||
virtual QSslCipher sessionCipher() const = 0;
|
QSsl::SslProtocol sessionProtocol() const;
|
||||||
virtual QSsl::SslProtocol sessionProtocol() const = 0;
|
void continueHandshake();
|
||||||
virtual void continueHandshake() = 0;
|
|
||||||
|
|
||||||
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 QTlsBackend *tlsBackendInUse();
|
||||||
static void registerAdHocFactory();
|
static void registerAdHocFactory();
|
||||||
|
|
||||||
private:
|
// Needed by TlsCryptograph:
|
||||||
static bool ensureLibraryLoaded();
|
Q_NETWORK_PRIVATE_EXPORT QSslSocket::SslMode tlsMode() const;
|
||||||
static void ensureCiphersAndCertsLoaded();
|
Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate &privateConfiguration();
|
||||||
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
|
Q_NETWORK_PRIVATE_EXPORT bool isRootsOnDemandAllowed() const;
|
||||||
static QList<QByteArray> fetchSslCertificateData();
|
Q_NETWORK_PRIVATE_EXPORT QString verificationName() const;
|
||||||
#endif
|
Q_NETWORK_PRIVATE_EXPORT QString tlsHostName() const;
|
||||||
|
Q_NETWORK_PRIVATE_EXPORT QTcpSocket *plainTcpSocket() const;
|
||||||
static bool s_libraryLoaded;
|
Q_NETWORK_PRIVATE_EXPORT bool verifyErrorsHaveBeenIgnored();
|
||||||
static bool s_loadedCiphersAndCerts;
|
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:
|
protected:
|
||||||
bool verifyErrorsHaveBeenIgnored();
|
|
||||||
// Only implemented/useful in Schannel for now
|
bool hasUndecryptedData() const;
|
||||||
virtual bool hasUndecryptedData() { return false; };
|
|
||||||
bool paused;
|
bool paused;
|
||||||
bool flushTriggered;
|
bool flushTriggered;
|
||||||
bool systemOrSslErrorDetected = false;
|
|
||||||
QList<QOcspResponse> ocspResponses;
|
|
||||||
bool handshakeInterrupted = false;
|
|
||||||
bool fetchAuthorityInformation = false;
|
|
||||||
QSslCertificate caToFetch;
|
|
||||||
|
|
||||||
static inline QMutex backendMutex;
|
static inline QMutex backendMutex;
|
||||||
static inline QString activeBackendName;
|
static inline QString activeBackendName;
|
||||||
static inline QTlsBackend *tlsBackend = nullptr;
|
static inline QTlsBackend *tlsBackend = nullptr;
|
||||||
};
|
|
||||||
|
|
||||||
#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
|
std::unique_ptr<QTlsPrivate::TlsCryptograph> backend;
|
||||||
// Implemented in qsslsocket_qt.cpp
|
};
|
||||||
QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key, const QString &passPhrase);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
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 "qssl_p.h"
|
||||||
#include "qsslsocket.h"
|
#include "qsslsocket.h"
|
||||||
#include "qsslsocket_schannel_p.h"
|
#include "qtls_schannel_p.h"
|
||||||
#include "qsslcertificate.h"
|
#include "qsslcertificate.h"
|
||||||
#include "qsslcertificateextension.h"
|
#include "qsslcertificateextension.h"
|
||||||
#include "qsslcertificate_p.h"
|
#include "qsslcertificate_p.h"
|
||||||
@ -161,10 +161,99 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.schannel");
|
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 {
|
namespace {
|
||||||
bool supportsTls13();
|
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
|
QString QSchannelBackend::backendName() const
|
||||||
{
|
{
|
||||||
return builtinBackendNames[nameIndexSchannel];
|
return builtinBackendNames[nameIndexSchannel];
|
||||||
@ -222,6 +311,32 @@ QTlsPrivate::X509Certificate *QSchannelBackend::createCertificate() const
|
|||||||
return new QTlsPrivate::X509CertificateSchannel;
|
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
|
QTlsPrivate::X509PemReaderPtr QSchannelBackend::X509PemReader() const
|
||||||
{
|
{
|
||||||
return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
|
return QTlsPrivate::X509CertificateGeneric::certificatesFromPem;
|
||||||
@ -232,7 +347,7 @@ QTlsPrivate::X509DerReaderPtr QSchannelBackend::X509DerReader() const
|
|||||||
return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
|
return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(QSchannelBackend, backend)
|
Q_GLOBAL_STATIC(QSchannelBackend, backendSchannel)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -588,93 +703,17 @@ qint64 checkIncompleteData(const SecBuffer &secBuffer)
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
bool QSslSocketPrivate::s_loadRootCertsOnDemand = true;
|
|
||||||
bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
|
|
||||||
Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
|
|
||||||
|
|
||||||
void QSslSocketPrivate::ensureInitialized()
|
namespace QTlsPrivate {
|
||||||
{
|
|
||||||
const QMutexLocker<QRecursiveMutex> locker(qt_schannel_mutex);
|
|
||||||
if (s_loadedCiphersAndCerts)
|
|
||||||
return;
|
|
||||||
s_loadedCiphersAndCerts = true;
|
|
||||||
|
|
||||||
setDefaultCaCertificates(systemCaCertificates());
|
TlsCryptographSchannel::TlsCryptographSchannel()
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
SecInvalidateHandle(&credentialHandle);
|
SecInvalidateHandle(&credentialHandle);
|
||||||
SecInvalidateHandle(&contextHandle);
|
SecInvalidateHandle(&contextHandle);
|
||||||
ensureInitialized();
|
QSchannelBackend::ensureInitializedImplementation();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
|
TlsCryptographSchannel::~TlsCryptographSchannel()
|
||||||
{
|
{
|
||||||
closeCertificateStores();
|
closeCertificateStores();
|
||||||
deallocateContext();
|
deallocateContext();
|
||||||
@ -682,29 +721,51 @@ QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
|
|||||||
CertFreeCertificateContext(localCertContext);
|
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)
|
if (tokenLength == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
Q_ASSERT(d);
|
||||||
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
|
Q_ASSERT(plainSocket);
|
||||||
|
|
||||||
const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
|
const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
|
||||||
if (written != qint64(tokenLength)) {
|
if (written != qint64(tokenLength)) {
|
||||||
// Failed to write/buffer everything or an error occurred
|
// Failed to write/buffer everything or an error occurred
|
||||||
if (emitError)
|
if (emitError)
|
||||||
setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
d->setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QSslSocketBackendPrivate::targetName() const
|
QString TlsCryptographSchannel::targetName() const
|
||||||
{
|
{
|
||||||
// Used for SNI extension
|
// 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;
|
ULONG req = 0;
|
||||||
|
|
||||||
req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
|
req |= ISC_REQ_ALLOCATE_MEMORY; // Allocate memory for buffers automatically
|
||||||
@ -716,7 +777,7 @@ ULONG QSslSocketBackendPrivate::getContextRequirements()
|
|||||||
if (isClient) {
|
if (isClient) {
|
||||||
req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
|
req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
|
||||||
} else {
|
} else {
|
||||||
switch (configuration.peerVerifyMode) {
|
switch (d->privateConfiguration().peerVerifyMode) {
|
||||||
case QSslSocket::PeerVerifyMode::VerifyNone:
|
case QSslSocket::PeerVerifyMode::VerifyNone:
|
||||||
// There doesn't seem to be a way to ask for an optional client cert :-(
|
// There doesn't seem to be a way to ask for an optional client cert :-(
|
||||||
case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
|
case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
|
||||||
@ -731,14 +792,17 @@ ULONG QSslSocketBackendPrivate::getContextRequirements()
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSslSocketBackendPrivate::acquireCredentialsHandle()
|
bool TlsCryptographSchannel::acquireCredentialsHandle()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
const auto &configuration = d->privateConfiguration();
|
||||||
|
|
||||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||||
|
|
||||||
const bool isClient = mode == QSslSocket::SslClientMode;
|
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||||
const DWORD protocols = toSchannelProtocol(configuration.protocol);
|
const DWORD protocols = toSchannelProtocol(configuration.protocol);
|
||||||
if (protocols == DWORD(-1)) {
|
if (protocols == DWORD(-1)) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||||
QSslSocket::tr("Invalid protocol chosen"));
|
QSslSocket::tr("Invalid protocol chosen"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -776,7 +840,7 @@ bool QSslSocketBackendPrivate::acquireCredentialsHandle()
|
|||||||
const QString message = isClient
|
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 client.")
|
||||||
: QSslSocket::tr("The certificate provided cannot be used for a server.");
|
: QSslSocket::tr("The certificate provided cannot be used for a server.");
|
||||||
setErrorAndEmit(QAbstractSocket::SocketError::SslInvalidUserDataError, message);
|
d->setErrorAndEmit(QAbstractSocket::SocketError::SslInvalidUserDataError, message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Q_ASSERT(chainContext->cChain == 1);
|
Q_ASSERT(chainContext->cChain == 1);
|
||||||
@ -865,13 +929,13 @@ bool QSslSocketBackendPrivate::acquireCredentialsHandle()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status != SEC_E_OK) {
|
if (status != SEC_E_OK) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
|
d->setErrorAndEmit(QAbstractSocket::SslInternalError, schannelErrorToString(status));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::deallocateContext()
|
void TlsCryptographSchannel::deallocateContext()
|
||||||
{
|
{
|
||||||
if (SecIsValidHandle(&contextHandle)) {
|
if (SecIsValidHandle(&contextHandle)) {
|
||||||
DeleteSecurityContext(&contextHandle);
|
DeleteSecurityContext(&contextHandle);
|
||||||
@ -879,7 +943,7 @@ void QSslSocketBackendPrivate::deallocateContext()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::freeCredentialsHandle()
|
void TlsCryptographSchannel::freeCredentialsHandle()
|
||||||
{
|
{
|
||||||
if (SecIsValidHandle(&credentialHandle)) {
|
if (SecIsValidHandle(&credentialHandle)) {
|
||||||
FreeCredentialsHandle(&credentialHandle);
|
FreeCredentialsHandle(&credentialHandle);
|
||||||
@ -887,18 +951,21 @@ void QSslSocketBackendPrivate::freeCredentialsHandle()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::closeCertificateStores()
|
void TlsCryptographSchannel::closeCertificateStores()
|
||||||
{
|
{
|
||||||
localCertificateStore.reset();
|
localCertificateStore.reset();
|
||||||
peerCertificateStore.reset();
|
peerCertificateStore.reset();
|
||||||
caCertificateStore.reset();
|
caCertificateStore.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSslSocketBackendPrivate::createContext()
|
bool TlsCryptographSchannel::createContext()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
auto &configuration = d->privateConfiguration();
|
||||||
|
|
||||||
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
||||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||||
Q_ASSERT(mode == QSslSocket::SslClientMode);
|
Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode);
|
||||||
ULONG contextReq = getContextRequirements();
|
ULONG contextReq = getContextRequirements();
|
||||||
|
|
||||||
SecBuffer outBuffers[3];
|
SecBuffer outBuffers[3];
|
||||||
@ -951,7 +1018,7 @@ bool QSslSocketBackendPrivate::createContext()
|
|||||||
// This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
|
// This is the first call to InitializeSecurityContext, so theoretically "CONTINUE_NEEDED"
|
||||||
// should be the only non-error return-code here.
|
// should be the only non-error return-code here.
|
||||||
if (status != SEC_I_CONTINUE_NEEDED) {
|
if (status != SEC_I_CONTINUE_NEEDED) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||||
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -962,11 +1029,15 @@ bool QSslSocketBackendPrivate::createContext()
|
|||||||
return true;
|
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(SecIsValidHandle(&credentialHandle));
|
||||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||||
Q_ASSERT(mode == QSslSocket::SslServerMode);
|
Q_ASSERT(d->tlsMode() == QSslSocket::SslServerMode);
|
||||||
ULONG contextReq = getContextRequirements();
|
ULONG contextReq = getContextRequirements();
|
||||||
|
|
||||||
if (missingData > plainSocket->bytesAvailable())
|
if (missingData > plainSocket->bytesAvailable())
|
||||||
@ -1043,7 +1114,7 @@ bool QSslSocketBackendPrivate::acceptContext()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status != SEC_I_CONTINUE_NEEDED) {
|
if (status != SEC_I_CONTINUE_NEEDED) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
QSslSocket::tr("Error creating SSL context (%1)").arg(schannelErrorToString(status)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1053,10 +1124,14 @@ bool QSslSocketBackendPrivate::acceptContext()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSslSocketBackendPrivate::performHandshake()
|
bool TlsCryptographSchannel::performHandshake()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
|
Q_ASSERT(plainSocket);
|
||||||
|
|
||||||
if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
|
if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
|
||||||
setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||||
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1157,7 +1232,7 @@ bool QSslSocketBackendPrivate::performHandshake()
|
|||||||
case SEC_I_INCOMPLETE_CREDENTIALS:
|
case SEC_I_INCOMPLETE_CREDENTIALS:
|
||||||
// Schannel takes care of picking certificate to send (other than the one we can specify),
|
// 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.
|
// so if we get here then that means we don't have a certificate the server accepts.
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Server did not accept any certificate we could present."));
|
QSslSocket::tr("Server did not accept any certificate we could present."));
|
||||||
return false;
|
return false;
|
||||||
case SEC_I_CONTEXT_EXPIRED:
|
case SEC_I_CONTEXT_EXPIRED:
|
||||||
@ -1167,7 +1242,7 @@ bool QSslSocketBackendPrivate::performHandshake()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!shutdown) { // we did not initiate this
|
if (!shutdown) { // we did not initiate this
|
||||||
setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||||
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
QSslSocket::tr("The TLS/SSL connection has been closed"));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1176,7 +1251,7 @@ bool QSslSocketBackendPrivate::performHandshake()
|
|||||||
missingData = checkIncompleteData(outBuffers[0]);
|
missingData = checkIncompleteData(outBuffers[0]);
|
||||||
return true;
|
return true;
|
||||||
case SEC_E_ALGORITHM_MISMATCH:
|
case SEC_E_ALGORITHM_MISMATCH:
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Algorithm mismatch"));
|
QSslSocket::tr("Algorithm mismatch"));
|
||||||
shutdown = true; // skip sending the "Shutdown" alert
|
shutdown = true; // skip sending the "Shutdown" alert
|
||||||
return false;
|
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
|
// 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.
|
// 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)
|
// (If you came here investigating an error: md5 is insecure, update your certificate)
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
|
QSslSocket::tr("Handshake failed: %1").arg(schannelErrorToString(status)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSslSocketBackendPrivate::verifyHandshake()
|
bool TlsCryptographSchannel::verifyHandshake()
|
||||||
{
|
{
|
||||||
Q_Q(QSslSocket);
|
Q_ASSERT(d);
|
||||||
|
Q_ASSERT(q);
|
||||||
|
auto &configuration = d->privateConfiguration();
|
||||||
|
|
||||||
sslErrors.clear();
|
sslErrors.clear();
|
||||||
|
|
||||||
const bool isClient = mode == QSslSocket::SslClientMode;
|
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||||
#define CHECK_STATUS(status) \
|
#define CHECK_STATUS(status) \
|
||||||
if (status != SEC_E_OK) { \
|
if (status != SEC_E_OK) { \
|
||||||
setErrorAndEmit(QAbstractSocket::SslInternalError, \
|
d->setErrorAndEmit(QAbstractSocket::SslInternalError, \
|
||||||
QSslSocket::tr("Failed to query the TLS context: %1") \
|
QSslSocket::tr("Failed to query the TLS context: %1") \
|
||||||
.arg(schannelErrorToString(status))); \
|
.arg(schannelErrorToString(status))); \
|
||||||
return false; \
|
return false; \
|
||||||
@ -1207,7 +1285,7 @@ bool QSslSocketBackendPrivate::verifyHandshake()
|
|||||||
// Everything is set up, now make sure there's nothing wrong and query some attributes...
|
// Everything is set up, now make sure there's nothing wrong and query some attributes...
|
||||||
if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
|
if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
|
||||||
configuration.peerVerifyMode, isClient)) {
|
configuration.peerVerifyMode, isClient)) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Did not get the required attributes for the connection."));
|
QSslSocket::tr("Did not get the required attributes for the connection."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1235,7 +1313,7 @@ bool QSslSocketBackendPrivate::verifyHandshake()
|
|||||||
QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
|
QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
|
||||||
alpn.ProtocolIdSize);
|
alpn.ProtocolIdSize);
|
||||||
if (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
|
if (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Unwanted protocol was negotiated"));
|
QSslSocket::tr("Unwanted protocol was negotiated"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1285,20 +1363,22 @@ bool QSslSocketBackendPrivate::verifyHandshake()
|
|||||||
if (certificateContext && !verifyCertContext(certificateContext))
|
if (certificateContext && !verifyCertContext(certificateContext))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!checkSslErrors() || state != QAbstractSocket::ConnectedState) {
|
if (!checkSslErrors() || q->state() != QAbstractSocket::ConnectedState) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcSsl) << __func__ << "was unsuccessful. Paused:" << paused;
|
qCDebug(lcSsl) << __func__ << "was unsuccessful. Paused:" << paused;
|
||||||
#endif
|
#endif
|
||||||
// If we're paused then checkSslErrors returned false, but it's not an error
|
// 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;
|
schannelState = SchannelState::Done;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSslSocketBackendPrivate::renegotiate()
|
bool TlsCryptographSchannel::renegotiate()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
|
||||||
SecBuffer outBuffers[3];
|
SecBuffer outBuffers[3];
|
||||||
outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
|
outBuffers[0] = createSecBuffer(nullptr, 0, SECBUFFER_TOKEN);
|
||||||
outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
|
outBuffers[1] = createSecBuffer(nullptr, 0, SECBUFFER_ALERT);
|
||||||
@ -1318,7 +1398,7 @@ bool QSslSocketBackendPrivate::renegotiate()
|
|||||||
ULONG contextReq = getContextRequirements();
|
ULONG contextReq = getContextRequirements();
|
||||||
TimeStamp expiry;
|
TimeStamp expiry;
|
||||||
SECURITY_STATUS status;
|
SECURITY_STATUS status;
|
||||||
if (mode == QSslSocket::SslClientMode) {
|
if (d->tlsMode() == QSslSocket::SslClientMode) {
|
||||||
status = InitializeSecurityContext(&credentialHandle, // phCredential
|
status = InitializeSecurityContext(&credentialHandle, // phCredential
|
||||||
&contextHandle, // phContext
|
&contextHandle, // phContext
|
||||||
const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
|
const_reinterpret_cast<SEC_WCHAR *>(targetName().utf16()), // pszTargetName
|
||||||
@ -1352,7 +1432,7 @@ bool QSslSocketBackendPrivate::renegotiate()
|
|||||||
schannelState = SchannelState::PerformHandshake;
|
schannelState = SchannelState::PerformHandshake;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
|
QSslSocket::tr("Renegotiation was unsuccessful: %1").arg(schannelErrorToString(status)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1361,8 +1441,10 @@ bool QSslSocketBackendPrivate::renegotiate()
|
|||||||
\internal
|
\internal
|
||||||
reset the state in preparation for reuse of socket
|
reset the state in preparation for reuse of socket
|
||||||
*/
|
*/
|
||||||
void QSslSocketBackendPrivate::reset()
|
void TlsCryptographSchannel::reset()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
|
||||||
closeCertificateStores(); // certificate stores could've changed
|
closeCertificateStores(); // certificate stores could've changed
|
||||||
deallocateContext();
|
deallocateContext();
|
||||||
freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
|
freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
|
||||||
@ -1377,34 +1459,42 @@ void QSslSocketBackendPrivate::reset()
|
|||||||
intermediateBuffer.clear();
|
intermediateBuffer.clear();
|
||||||
schannelState = SchannelState::InitializeHandshake;
|
schannelState = SchannelState::InitializeHandshake;
|
||||||
|
|
||||||
connectionEncrypted = false;
|
|
||||||
|
d->setEncrypted(false);
|
||||||
shutdown = false;
|
shutdown = false;
|
||||||
renegotiating = false;
|
renegotiating = false;
|
||||||
|
|
||||||
missingData = 0;
|
missingData = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::startClientEncryption()
|
void TlsCryptographSchannel::startClientEncryption()
|
||||||
{
|
{
|
||||||
if (connectionEncrypted)
|
Q_ASSERT(q);
|
||||||
|
|
||||||
|
if (q->isEncrypted())
|
||||||
return; // let's not mess up the connection...
|
return; // let's not mess up the connection...
|
||||||
reset();
|
reset();
|
||||||
continueHandshake();
|
continueHandshake();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::startServerEncryption()
|
void TlsCryptographSchannel::startServerEncryption()
|
||||||
{
|
{
|
||||||
if (connectionEncrypted)
|
Q_ASSERT(q);
|
||||||
|
|
||||||
|
if (q->isEncrypted())
|
||||||
return; // let's not mess up the connection...
|
return; // let's not mess up the connection...
|
||||||
reset();
|
reset();
|
||||||
continueHandshake();
|
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
|
return; // This function should not have been called
|
||||||
|
|
||||||
// Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
|
// Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
|
||||||
@ -1416,7 +1506,9 @@ void QSslSocketBackendPrivate::transmit()
|
|||||||
return;
|
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 totalBytesWritten = 0;
|
||||||
qint64 writeBufferSize;
|
qint64 writeBufferSize;
|
||||||
while ((writeBufferSize = writeBuffer.size()) > 0) {
|
while ((writeBufferSize = writeBuffer.size()) > 0) {
|
||||||
@ -1444,7 +1536,7 @@ void QSslSocketBackendPrivate::transmit()
|
|||||||
};
|
};
|
||||||
auto status = EncryptMessage(&contextHandle, 0, &message, 0);
|
auto status = EncryptMessage(&contextHandle, 0, &message, 0);
|
||||||
if (status != SEC_E_OK) {
|
if (status != SEC_E_OK) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||||
QSslSocket::tr("Schannel failed to encrypt data: %1")
|
QSslSocket::tr("Schannel failed to encrypt data: %1")
|
||||||
.arg(schannelErrorToString(status)));
|
.arg(schannelErrorToString(status)));
|
||||||
return;
|
return;
|
||||||
@ -1461,13 +1553,14 @@ void QSslSocketBackendPrivate::transmit()
|
|||||||
if (bytesWritten >= 0) {
|
if (bytesWritten >= 0) {
|
||||||
totalBytesWritten += bytesWritten;
|
totalBytesWritten += bytesWritten;
|
||||||
} else {
|
} else {
|
||||||
setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
d->setErrorAndEmit(plainSocket->error(), plainSocket->errorString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalBytesWritten > 0) {
|
if (totalBytesWritten > 0) {
|
||||||
// Don't emit bytesWritten() recursively.
|
// Don't emit bytesWritten() recursively.
|
||||||
|
bool &emittedBytesWritten = d->tlsEmittedBytesWritten();
|
||||||
if (!emittedBytesWritten) {
|
if (!emittedBytesWritten) {
|
||||||
emittedBytesWritten = true;
|
emittedBytesWritten = true;
|
||||||
emit q->bytesWritten(totalBytesWritten);
|
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;
|
int totalRead = 0;
|
||||||
bool hadIncompleteData = false;
|
bool hadIncompleteData = false;
|
||||||
|
const auto readBufferMaxSize = d->maxReadBufferSize();
|
||||||
while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
|
while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
|
||||||
if (missingData > plainSocket->bytesAvailable()
|
if (missingData > plainSocket->bytesAvailable()
|
||||||
&& (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
|
&& (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
|
||||||
@ -1560,7 +1654,7 @@ void QSslSocketBackendPrivate::transmit()
|
|||||||
// The message has been altered, disconnect now.
|
// The message has been altered, disconnect now.
|
||||||
shutdown = true; // skips sending the shutdown alert
|
shutdown = true; // skips sending the shutdown alert
|
||||||
disconnectFromHost();
|
disconnectFromHost();
|
||||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||||
schannelErrorToString(status));
|
schannelErrorToString(status));
|
||||||
break;
|
break;
|
||||||
} else if (status == SEC_E_OUT_OF_SEQUENCE) {
|
} 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).
|
// while SEC_E_MESSAGE_ALTERED is for stream-oriented ones (what we use).
|
||||||
shutdown = true; // skips sending the shutdown alert
|
shutdown = true; // skips sending the shutdown alert
|
||||||
disconnectFromHost();
|
disconnectFromHost();
|
||||||
setErrorAndEmit(QAbstractSocket::SslInternalError,
|
d->setErrorAndEmit(QAbstractSocket::SslInternalError,
|
||||||
schannelErrorToString(status));
|
schannelErrorToString(status));
|
||||||
break;
|
break;
|
||||||
} else if (status == SEC_I_CONTEXT_EXPIRED) {
|
} else if (status == SEC_I_CONTEXT_EXPIRED) {
|
||||||
// 'remote' has initiated a shutdown
|
// 'remote' has initiated a shutdown
|
||||||
disconnectFromHost();
|
disconnectFromHost();
|
||||||
setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
d->setErrorAndEmit(QAbstractSocket::RemoteHostClosedError,
|
||||||
schannelErrorToString(status));
|
schannelErrorToString(status));
|
||||||
break;
|
break;
|
||||||
} else if (status == SEC_I_RENEGOTIATE) {
|
} else if (status == SEC_I_RENEGOTIATE) {
|
||||||
@ -1593,7 +1687,7 @@ void QSslSocketBackendPrivate::transmit()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (totalRead) {
|
if (totalRead) {
|
||||||
if (readyReadEmittedPointer)
|
if (bool *readyReadEmittedPointer = d->readyReadPointer())
|
||||||
*readyReadEmittedPointer = true;
|
*readyReadEmittedPointer = true;
|
||||||
emit q->readyRead();
|
emit q->readyRead();
|
||||||
emit q->channelReadyRead(0);
|
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;
|
DWORD shutdownToken = SCHANNEL_SHUTDOWN;
|
||||||
SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(DWORD), SECBUFFER_TOKEN);
|
SecBuffer buffer = createSecBuffer(&shutdownToken, sizeof(DWORD), SECBUFFER_TOKEN);
|
||||||
SecBufferDesc 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 (SecIsValidHandle(&contextHandle)) {
|
||||||
if (!shutdown) {
|
if (!shutdown) {
|
||||||
shutdown = true;
|
shutdown = true;
|
||||||
if (plainSocket->state() != QAbstractSocket::UnconnectedState) {
|
if (plainSocket->state() != QAbstractSocket::UnconnectedState) {
|
||||||
if (connectionEncrypted) {
|
if (q->isEncrypted()) {
|
||||||
// Read as much as possible because this is likely our last chance
|
// Read as much as possible because this is likely our last chance
|
||||||
qint64 tempMax = readBufferMaxSize;
|
qint64 tempMax = d->maxReadBufferSize();
|
||||||
readBufferMaxSize = 0;
|
d->setMaxReadBufferSize(0);
|
||||||
transmit();
|
transmit();
|
||||||
readBufferMaxSize = tempMax;
|
d->setMaxReadBufferSize(tempMax);
|
||||||
sendShutdown();
|
sendShutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1699,32 +1800,40 @@ void QSslSocketBackendPrivate::disconnectFromHost()
|
|||||||
plainSocket->disconnectFromHost();
|
plainSocket->disconnectFromHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::disconnected()
|
void TlsCryptographSchannel::disconnected()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
|
||||||
shutdown = true;
|
shutdown = true;
|
||||||
connectionEncrypted = false;
|
d->setEncrypted(false);
|
||||||
deallocateContext();
|
deallocateContext();
|
||||||
freeCredentialsHandle();
|
freeCredentialsHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
|
QSslCipher TlsCryptographSchannel::sessionCipher() const
|
||||||
{
|
{
|
||||||
if (!connectionEncrypted)
|
Q_ASSERT(q);
|
||||||
|
|
||||||
|
if (!q->isEncrypted())
|
||||||
return QSslCipher();
|
return QSslCipher();
|
||||||
return QSslCipher(QStringLiteral("Schannel"), sessionProtocol());
|
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 QSsl::SslProtocol::UnknownProtocol;
|
||||||
return toQtSslProtocol(connectionInfo.dwProtocol);
|
return toQtSslProtocol(connectionInfo.dwProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::continueHandshake()
|
void TlsCryptographSchannel::continueHandshake()
|
||||||
{
|
{
|
||||||
Q_Q(QSslSocket);
|
Q_ASSERT(q);
|
||||||
const bool isServer = mode == QSslSocket::SslServerMode;
|
Q_ASSERT(d);
|
||||||
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
|
Q_ASSERT(plainSocket);
|
||||||
|
|
||||||
|
const bool isServer = d->tlsMode() == QSslSocket::SslServerMode;
|
||||||
switch (schannelState) {
|
switch (schannelState) {
|
||||||
case SchannelState::InitializeHandshake:
|
case SchannelState::InitializeHandshake:
|
||||||
if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
|
if (!SecIsValidHandle(&credentialHandle) && !acquireCredentialsHandle()) {
|
||||||
@ -1762,13 +1871,13 @@ void QSslSocketBackendPrivate::continueHandshake()
|
|||||||
Q_FALLTHROUGH();
|
Q_FALLTHROUGH();
|
||||||
case SchannelState::Done:
|
case SchannelState::Done:
|
||||||
// connectionEncrypted is already true if we come here from a renegotiation
|
// connectionEncrypted is already true if we come here from a renegotiation
|
||||||
if (!connectionEncrypted) {
|
if (!q->isEncrypted()) {
|
||||||
connectionEncrypted = true; // all is done
|
d->setEncrypted(true); // all is done
|
||||||
emit q->encrypted();
|
emit q->encrypted();
|
||||||
}
|
}
|
||||||
renegotiating = false;
|
renegotiating = false;
|
||||||
if (pendingClose) {
|
if (d->isPendingClose()) {
|
||||||
pendingClose = false;
|
d->setPendingClose(false);
|
||||||
disconnectFromHost();
|
disconnectFromHost();
|
||||||
} else {
|
} else {
|
||||||
transmit();
|
transmit();
|
||||||
@ -1785,75 +1894,37 @@ void QSslSocketBackendPrivate::continueHandshake()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QSslCipher> QSslSocketBackendPrivate::defaultCiphers()
|
QList<QSslError> TlsCryptographSchannel::tlsErrors() const
|
||||||
{
|
{
|
||||||
QList<QSslCipher> ciphers;
|
return sslErrors;
|
||||||
// @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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
|
Copied from qsslsocket_mac.cpp, which was copied from qsslsocket_openssl.cpp
|
||||||
*/
|
*/
|
||||||
bool QSslSocketBackendPrivate::checkSslErrors()
|
bool TlsCryptographSchannel::checkSslErrors()
|
||||||
{
|
{
|
||||||
if (sslErrors.isEmpty())
|
if (sslErrors.isEmpty())
|
||||||
return true;
|
return true;
|
||||||
Q_Q(QSslSocket);
|
|
||||||
|
Q_ASSERT(q);
|
||||||
|
Q_ASSERT(d);
|
||||||
|
const auto &configuration = d->privateConfiguration();
|
||||||
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
|
|
||||||
emit q->sslErrors(sslErrors);
|
emit q->sslErrors(sslErrors);
|
||||||
|
|
||||||
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
||||||
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
||||||
&& mode == QSslSocket::SslClientMode);
|
&& d->tlsMode() == QSslSocket::SslClientMode);
|
||||||
const bool doEmitSslError = !verifyErrorsHaveBeenIgnored();
|
const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
|
||||||
// check whether we need to emit an SSL handshake error
|
// check whether we need to emit an SSL handshake error
|
||||||
if (doVerifyPeer && doEmitSslError) {
|
if (doVerifyPeer && doEmitSslError) {
|
||||||
if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
|
if (q->pauseMode() & QAbstractSocket::PauseOnSslErrors) {
|
||||||
pauseSocketNotifiers(q);
|
QSslSocketPrivate::pauseSocketNotifiers(q);
|
||||||
paused = true;
|
d->setPaused(true);
|
||||||
} else {
|
} else {
|
||||||
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
sslErrors.constFirst().errorString());
|
sslErrors.constFirst().errorString());
|
||||||
plainSocket->disconnectFromHost();
|
plainSocket->disconnectFromHost();
|
||||||
}
|
}
|
||||||
@ -1863,9 +1934,12 @@ bool QSslSocketBackendPrivate::checkSslErrors()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::initializeCertificateStores()
|
void TlsCryptographSchannel::initializeCertificateStores()
|
||||||
{
|
{
|
||||||
//// helper function which turns a chain into a certificate store
|
//// 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) {
|
auto createStoreFromCertificateChain = [](const QList<QSslCertificate> certChain, const QSslKey &privateKey) {
|
||||||
const wchar_t *passphrase = L"";
|
const wchar_t *passphrase = L"";
|
||||||
// Need to embed the private key in the certificate
|
// Need to embed the private key in the certificate
|
||||||
@ -1880,7 +1954,7 @@ void QSslSocketBackendPrivate::initializeCertificateStores()
|
|||||||
|
|
||||||
if (!configuration.localCertificateChain.isEmpty()) {
|
if (!configuration.localCertificateChain.isEmpty()) {
|
||||||
if (configuration.privateKey.isNull()) {
|
if (configuration.privateKey.isNull()) {
|
||||||
setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||||
QSslSocket::tr("Cannot provide a certificate with no key"));
|
QSslSocket::tr("Cannot provide a certificate with no key"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1898,12 +1972,14 @@ void QSslSocketBackendPrivate::initializeCertificateStores()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
|
bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
|
||||||
{
|
{
|
||||||
Q_ASSERT(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
|
// Create a collection of stores so we can pass in multiple stores as additional locations to
|
||||||
// search for the certificate chain
|
// search for the certificate chain
|
||||||
@ -2187,14 +2263,15 @@ bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
|
|||||||
// @Note: Somewhat copied from qsslsocket_mac.cpp
|
// @Note: Somewhat copied from qsslsocket_mac.cpp
|
||||||
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
||||||
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
||||||
&& mode == QSslSocket::SslClientMode);
|
&& d->tlsMode() == QSslSocket::SslClientMode);
|
||||||
// Check the peer certificate itself. First try the subject's common name
|
// 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
|
// (CN) as a wildcard, then try all alternate subject name DNS entries the
|
||||||
// same way.
|
// same way.
|
||||||
if (!configuration.peerCertificate.isNull()) {
|
if (!configuration.peerCertificate.isNull()) {
|
||||||
// but only if we're a client connecting to a server
|
// but only if we're a client connecting to a server
|
||||||
// if we're the server, don't check CN
|
// 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);
|
const QString peerName(verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName);
|
||||||
if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
|
if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
|
||||||
// No matches in common names or alternate names.
|
// No matches in common names or alternate names.
|
||||||
@ -2218,17 +2295,20 @@ bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
|
|||||||
return true;
|
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()
|
void QSslSocketPrivate::registerAdHocFactory()
|
||||||
{
|
{
|
||||||
// TLSTODO: this is a temporary solution, waiting for
|
// TLSTODO: this is a temporary solution, waiting for
|
||||||
// backends to move to ... plugins.
|
// backends to move to ... plugins.
|
||||||
if (!backend())
|
if (!backendSchannel())
|
||||||
qCWarning(lcSsl, "Failed to create backend factory");
|
qCWarning(lcTlsBackend, "Failed to create backend factory");
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
@ -37,8 +37,8 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef QSSLSOCKET_SCHANNEL_P_H
|
#ifndef QTLS_SCHANNEL_P_H
|
||||||
#define QSSLSOCKET_SCHANNEL_P_H
|
#define QTLS_SCHANNEL_P_H
|
||||||
|
|
||||||
//
|
//
|
||||||
// W A R N I N G
|
// W A R N I N G
|
||||||
@ -51,12 +51,17 @@
|
|||||||
// We mean it.
|
// We mean it.
|
||||||
//
|
//
|
||||||
|
|
||||||
QT_REQUIRE_CONFIG(schannel);
|
|
||||||
|
|
||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#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 "qsslsocket_p.h"
|
||||||
|
|
||||||
|
#include "qwincrypt_p.h"
|
||||||
|
|
||||||
#define SECURITY_WIN32
|
#define SECURITY_WIN32
|
||||||
#define SCHANNEL_USE_BLACKLISTS 1
|
#define SCHANNEL_USE_BLACKLISTS 1
|
||||||
#include <Winternl.h> // needed for UNICODE defines
|
#include <Winternl.h> // needed for UNICODE defines
|
||||||
@ -67,15 +72,17 @@ QT_REQUIRE_CONFIG(schannel);
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QSslSocketBackendPrivate final : public QSslSocketPrivate
|
namespace QTlsPrivate {
|
||||||
{
|
|
||||||
Q_DISABLE_COPY_MOVE(QSslSocketBackendPrivate)
|
class TlsCryptographSchannel final : public TlsCryptograph
|
||||||
Q_DECLARE_PUBLIC(QSslSocket)
|
{
|
||||||
public:
|
Q_DISABLE_COPY_MOVE(TlsCryptographSchannel)
|
||||||
QSslSocketBackendPrivate();
|
public:
|
||||||
~QSslSocketBackendPrivate();
|
TlsCryptographSchannel();
|
||||||
|
~TlsCryptographSchannel();
|
||||||
|
|
||||||
|
void init(QSslSocket *q, QSslSocketPrivate *d) override;
|
||||||
|
|
||||||
// Platform specific functions
|
|
||||||
void startClientEncryption() override;
|
void startClientEncryption() override;
|
||||||
void startServerEncryption() override;
|
void startServerEncryption() override;
|
||||||
void transmit() override;
|
void transmit() override;
|
||||||
@ -84,12 +91,7 @@ public:
|
|||||||
QSslCipher sessionCipher() const override;
|
QSslCipher sessionCipher() const override;
|
||||||
QSsl::SslProtocol sessionProtocol() const override;
|
QSsl::SslProtocol sessionProtocol() const override;
|
||||||
void continueHandshake() override;
|
void continueHandshake() override;
|
||||||
|
QList<QSslError> tlsErrors() const 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);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class SchannelState {
|
enum class SchannelState {
|
||||||
@ -123,7 +125,10 @@ private:
|
|||||||
|
|
||||||
bool rootCertOnDemandLoadingAllowed();
|
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_ConnectionInfo connectionInfo = {};
|
||||||
SecPkgContext_StreamSizes streamSizes = {};
|
SecPkgContext_StreamSizes streamSizes = {};
|
||||||
@ -143,8 +148,12 @@ private:
|
|||||||
qint64 missingData = 0;
|
qint64 missingData = 0;
|
||||||
|
|
||||||
bool renegotiating = false;
|
bool renegotiating = false;
|
||||||
|
bool shutdown = false;
|
||||||
|
QList<QSslError> sslErrors;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace QTlsPrivate
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
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
|
#ifndef QTLS_ST_P_H
|
||||||
#define QSSLSOCKET_MAC_P_H
|
#define QTLS_ST_P_H
|
||||||
|
|
||||||
//
|
//
|
||||||
// W A R N I N G
|
// W A R N I N G
|
||||||
@ -52,6 +52,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
|
#include "qtlsbackend_st_p.h"
|
||||||
|
|
||||||
|
#include <QtCore/qobject.h>
|
||||||
#include <QtCore/qstring.h>
|
#include <QtCore/qstring.h>
|
||||||
#include <QtCore/qglobal.h>
|
#include <QtCore/qglobal.h>
|
||||||
#include <QtCore/qlist.h>
|
#include <QtCore/qlist.h>
|
||||||
@ -64,6 +68,8 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace QTlsPrivate {
|
||||||
|
|
||||||
class QSecureTransportContext
|
class QSecureTransportContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -78,14 +84,13 @@ private:
|
|||||||
Q_DISABLE_COPY_MOVE(QSecureTransportContext)
|
Q_DISABLE_COPY_MOVE(QSecureTransportContext)
|
||||||
};
|
};
|
||||||
|
|
||||||
class QSslSocketBackendPrivate : public QSslSocketPrivate
|
class TlsCryptographSecureTransport : public TlsCryptograph
|
||||||
{
|
{
|
||||||
Q_DECLARE_PUBLIC(QSslSocket)
|
|
||||||
public:
|
public:
|
||||||
QSslSocketBackendPrivate();
|
TlsCryptographSecureTransport();
|
||||||
virtual ~QSslSocketBackendPrivate();
|
~TlsCryptographSecureTransport() override;
|
||||||
|
|
||||||
// Final-overriders (QSslSocketPrivate):
|
void init(QSslSocket *qObj, QSslSocketPrivate *dObj) override;
|
||||||
void continueHandshake() override;
|
void continueHandshake() override;
|
||||||
void disconnected() override;
|
void disconnected() override;
|
||||||
void disconnectFromHost() override;
|
void disconnectFromHost() override;
|
||||||
@ -94,17 +99,9 @@ public:
|
|||||||
void startClientEncryption() override;
|
void startClientEncryption() override;
|
||||||
void startServerEncryption() override;
|
void startServerEncryption() override;
|
||||||
void transmit() override;
|
void transmit() override;
|
||||||
|
QList<QSslError> tlsErrors() const override;
|
||||||
|
|
||||||
static QList<QSslError> verify(QList<QSslCertificate> certificateChain,
|
SSLCipherSuite SSLCipherSuite_from_QSslCipher(const QSslCipher &ciph);
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// SSL context management/properties:
|
// SSL context management/properties:
|
||||||
@ -121,18 +118,24 @@ private:
|
|||||||
bool checkSslErrors();
|
bool checkSslErrors();
|
||||||
bool startHandshake();
|
bool startHandshake();
|
||||||
|
|
||||||
bool isHandshakeComplete() const {return connectionEncrypted && !renegotiating;}
|
bool isHandshakeComplete() const;
|
||||||
|
|
||||||
// IO callbacks:
|
// IO callbacks:
|
||||||
static OSStatus ReadCallback(QSslSocketBackendPrivate *socket, char *data, size_t *dataLength);
|
static OSStatus ReadCallback(TlsCryptographSecureTransport *socket, char *data, size_t *dataLength);
|
||||||
static OSStatus WriteCallback(QSslSocketBackendPrivate *plainSocket, const char *data, size_t *dataLength);
|
static OSStatus WriteCallback(TlsCryptographSecureTransport *plainSocket, const char *data, size_t *dataLength);
|
||||||
|
|
||||||
QSecureTransportContext context;
|
QSecureTransportContext context;
|
||||||
bool renegotiating = false;
|
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
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif
|
#endif // QTLS_ST_P_H
|
@ -40,7 +40,10 @@
|
|||||||
#include "qtlsbackend_p.h"
|
#include "qtlsbackend_p.h"
|
||||||
|
|
||||||
#if QT_CONFIG(ssl)
|
#if QT_CONFIG(ssl)
|
||||||
|
#include "qsslpresharedkeyauthenticator_p.h"
|
||||||
|
#include "qsslpresharedkeyauthenticator.h"
|
||||||
#include "qsslsocket_p.h"
|
#include "qsslsocket_p.h"
|
||||||
|
#include "qsslcipher_p.h"
|
||||||
#include "qsslkey_p.h"
|
#include "qsslkey_p.h"
|
||||||
#include "qsslkey.h"
|
#include "qsslkey.h"
|
||||||
#else
|
#else
|
||||||
@ -199,6 +202,50 @@ TlsKey *X509Certificate::publicKey() const
|
|||||||
return nullptr;
|
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)
|
#if QT_CONFIG(dtls)
|
||||||
DtlsBase::~DtlsBase() = default;
|
DtlsBase::~DtlsBase() = default;
|
||||||
#endif // QT_CONFIG(dtls)
|
#endif // QT_CONFIG(dtls)
|
||||||
@ -228,6 +275,30 @@ bool QTlsBackend::isValid() const
|
|||||||
return true;
|
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
|
QString QTlsBackend::backendName() const
|
||||||
{
|
{
|
||||||
return QStringLiteral("dummyTLS");
|
return QStringLiteral("dummyTLS");
|
||||||
@ -248,6 +319,12 @@ QTlsPrivate::X509Certificate *QTlsBackend::createCertificate() const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QSslCertificate> QTlsBackend::systemCaCertificates() const
|
||||||
|
{
|
||||||
|
REPORT_MISSING_SUPPORT("does not provide system CA certificates");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
QTlsPrivate::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
|
QTlsPrivate::TlsCryptograph *QTlsBackend::createTlsCryptograph() const
|
||||||
{
|
{
|
||||||
REPORT_MISSING_SUPPORT("does not support QSslSocket");
|
REPORT_MISSING_SUPPORT("does not support QSslSocket");
|
||||||
@ -441,4 +518,189 @@ void QTlsBackend::resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend)
|
|||||||
#endif // QT_CONFIG(ssl)
|
#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
|
QT_END_NAMESPACE
|
||||||
|
@ -40,20 +40,25 @@
|
|||||||
#include "qtlsbackend_openssl_p.h"
|
#include "qtlsbackend_openssl_p.h"
|
||||||
#include "qtlskey_openssl_p.h"
|
#include "qtlskey_openssl_p.h"
|
||||||
#include "qx509_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)
|
#if QT_CONFIG(dtls)
|
||||||
#include "qdtls_openssl_p.h"
|
#include "qdtls_openssl_p.h"
|
||||||
#endif // QT_CONFIG(dtls)
|
#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 "qsslsocket_openssl_symbols_p.h"
|
||||||
|
#include "qopenssl_p.h"
|
||||||
|
|
||||||
#include <qssl.h>
|
#include <qssl.h>
|
||||||
|
|
||||||
|
#include <qdir.h>
|
||||||
|
#include <qdiriterator.h>
|
||||||
#include <qlist.h>
|
#include <qlist.h>
|
||||||
|
#include <qmutex.h>
|
||||||
|
#include <qscopeguard.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -61,6 +66,36 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.ossl");
|
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 QTlsBackendOpenSSL::getErrorsFromOpenSsl()
|
||||||
{
|
{
|
||||||
QString errorString;
|
QString errorString;
|
||||||
@ -88,6 +123,41 @@ void QTlsBackendOpenSSL::clearErrorQueue()
|
|||||||
Q_UNUSED(errs);
|
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
|
QString QTlsBackendOpenSSL::backendName() const
|
||||||
{
|
{
|
||||||
return builtinBackendNames[nameIndexOpenSSL];
|
return builtinBackendNames[nameIndexOpenSSL];
|
||||||
@ -95,9 +165,124 @@ QString QTlsBackendOpenSSL::backendName() const
|
|||||||
|
|
||||||
bool QTlsBackendOpenSSL::isValid() const
|
bool QTlsBackendOpenSSL::isValid() const
|
||||||
{
|
{
|
||||||
// TLSTODO: backend should do initialization,
|
return ensureLibraryLoaded();
|
||||||
// not socket.
|
}
|
||||||
return QSslSocket::supportsSsl();
|
|
||||||
|
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
|
QList<QSsl::SslProtocol> QTlsBackendOpenSSL::supportedProtocols() const
|
||||||
@ -167,6 +352,98 @@ QTlsPrivate::X509Certificate *QTlsBackendOpenSSL::createCertificate() const
|
|||||||
return new QTlsPrivate::X509CertificateOpenSSL;
|
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
|
QTlsPrivate::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier() const
|
||||||
{
|
{
|
||||||
#if QT_CONFIG(dtls)
|
#if QT_CONFIG(dtls)
|
||||||
@ -177,6 +454,11 @@ QTlsPrivate::DtlsCookieVerifier *QTlsBackendOpenSSL::createDtlsCookieVerifier()
|
|||||||
#endif // QT_CONFIG(dtls)
|
#endif // QT_CONFIG(dtls)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTlsPrivate::TlsCryptograph *QTlsBackendOpenSSL::createTlsCryptograph() const
|
||||||
|
{
|
||||||
|
return new QTlsPrivate::TlsCryptographOpenSSL;
|
||||||
|
}
|
||||||
|
|
||||||
QTlsPrivate::DtlsCryptograph *QTlsBackendOpenSSL::createDtlsCryptograph(QDtls *q, int mode) const
|
QTlsPrivate::DtlsCryptograph *QTlsBackendOpenSSL::createDtlsCryptograph(QDtls *q, int mode) const
|
||||||
{
|
{
|
||||||
#if QT_CONFIG(dtls)
|
#if QT_CONFIG(dtls)
|
||||||
@ -233,10 +515,7 @@ QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
|
|||||||
if (name.isEmpty())
|
if (name.isEmpty())
|
||||||
return nid;
|
return nid;
|
||||||
|
|
||||||
// TLSTODO: check if it's needed! The fact we are here,
|
ensureInitialized(); // TLSTODO: check if it's needed!
|
||||||
// means OpenSSL was loaded, symbols resolved. Is it because
|
|
||||||
// of ensureCiphers(AndCertificates)Loaded ?
|
|
||||||
QSslSocketPrivate::ensureInitialized();
|
|
||||||
#ifndef OPENSSL_NO_EC
|
#ifndef OPENSSL_NO_EC
|
||||||
const QByteArray curveNameLatin1 = name.toLatin1();
|
const QByteArray curveNameLatin1 = name.toLatin1();
|
||||||
nid = q_OBJ_sn2nid(curveNameLatin1.data());
|
nid = q_OBJ_sn2nid(curveNameLatin1.data());
|
||||||
@ -254,10 +533,7 @@ QList<int> QTlsBackendOpenSSL::ellipticCurvesIds() const
|
|||||||
if (name.isEmpty())
|
if (name.isEmpty())
|
||||||
return nid;
|
return nid;
|
||||||
|
|
||||||
// TLSTODO: check if it's needed! The fact we are here,
|
ensureInitialized();
|
||||||
// means OpenSSL was loaded, symbols resolved. Is it because
|
|
||||||
// of ensureCiphers(AndCertificates)Loaded ?
|
|
||||||
QSslSocketPrivate::ensureInitialized();
|
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_EC
|
#ifndef OPENSSL_NO_EC
|
||||||
const QByteArray curveNameLatin1 = name.toLatin1();
|
const QByteArray curveNameLatin1 = name.toLatin1();
|
||||||
@ -336,4 +612,19 @@ bool QTlsBackendOpenSSL::isTlsNamedCurve(int id) const
|
|||||||
return std::find(tlsNamedCurveNIDs, tlsNamedCurveNIDsEnd, id) != tlsNamedCurveNIDsEnd;
|
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
|
QT_END_NAMESPACE
|
||||||
|
@ -54,22 +54,44 @@
|
|||||||
#include <private/qtnetworkglobal_p.h>
|
#include <private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
#include "qssldiffiehellmanparameters.h"
|
#include "qssldiffiehellmanparameters.h"
|
||||||
|
#include "qsslcertificate.h"
|
||||||
#include "qtlsbackend_p.h"
|
#include "qtlsbackend_p.h"
|
||||||
|
|
||||||
#include <QtCore/qglobal.h>
|
#include <QtCore/qglobal.h>
|
||||||
|
#include <QtCore/qlist.h>
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QTlsBackendOpenSSL final : public QTlsBackend
|
class QTlsBackendOpenSSL final : public QTlsBackend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static QString getErrorsFromOpenSsl();
|
static QString getErrorsFromOpenSsl();
|
||||||
static void logAndClearErrorQueue();
|
static void logAndClearErrorQueue();
|
||||||
static void clearErrorQueue();
|
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:
|
private:
|
||||||
|
|
||||||
QString backendName() const override;
|
QString backendName() const override;
|
||||||
bool isValid() 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::SslProtocol> supportedProtocols() const override;
|
||||||
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
||||||
@ -80,7 +102,9 @@ private:
|
|||||||
|
|
||||||
// QSslCertificate:
|
// QSslCertificate:
|
||||||
QTlsPrivate::X509Certificate *createCertificate() const override;
|
QTlsPrivate::X509Certificate *createCertificate() const override;
|
||||||
|
QList<QSslCertificate> systemCaCertificates() const override;
|
||||||
|
|
||||||
|
QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
|
||||||
QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const override;
|
QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const override;
|
||||||
QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(QDtls *q, int mode) const override;
|
QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(QDtls *q, int mode) const override;
|
||||||
|
|
||||||
|
@ -62,11 +62,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtNetwork/qsslcertificate.h>
|
#include <QtNetwork/qsslcertificate.h>
|
||||||
#include <QtNetwork/qsslerror.h>
|
#include <QtNetwork/qsslcipher.h>
|
||||||
#include <QtNetwork/qsslkey.h>
|
#include <QtNetwork/qsslkey.h>
|
||||||
#include <QtNetwork/qssl.h>
|
#include <QtNetwork/qssl.h>
|
||||||
|
|
||||||
#include <QtCore/qloggingcategory.h>
|
#include <QtCore/qloggingcategory.h>
|
||||||
|
#include <QtCore/qsharedpointer.h>
|
||||||
#include <QtCore/qnamespace.h>
|
#include <QtCore/qnamespace.h>
|
||||||
#include <QtCore/qobject.h>
|
#include <QtCore/qobject.h>
|
||||||
#include <QtCore/qglobal.h>
|
#include <QtCore/qglobal.h>
|
||||||
@ -78,11 +79,17 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QSslPreSharedKeyAuthenticator;
|
||||||
|
class QSslSocketPrivate;
|
||||||
class QHostAddress;
|
class QHostAddress;
|
||||||
|
class QSslContext;
|
||||||
|
|
||||||
|
class QSslSocket;
|
||||||
class QByteArray;
|
class QByteArray;
|
||||||
class QSslCipher;
|
class QSslCipher;
|
||||||
class QUdpSocket;
|
class QUdpSocket;
|
||||||
class QIODevice;
|
class QIODevice;
|
||||||
|
class QSslError;
|
||||||
class QSslKey;
|
class QSslKey;
|
||||||
|
|
||||||
namespace QTlsPrivate {
|
namespace QTlsPrivate {
|
||||||
@ -93,9 +100,8 @@ namespace QTlsPrivate {
|
|||||||
// however strange they are, for now preserved to ease the transition
|
// however strange they are, for now preserved to ease the transition
|
||||||
// (this may change in future - for example, 'decodeDer' is not just
|
// (this may change in future - for example, 'decodeDer' is not just
|
||||||
// decoding DER, it's initializing a key from DER. Note, QSslKey requires
|
// decoding DER, it's initializing a key from DER. Note, QSslKey requires
|
||||||
// a real TLS library because private keys tend to be encrypted. This
|
// a real TLS library because private keys tend to be encrypted.
|
||||||
// base class does not need a working TLS library.
|
class Q_NETWORK_PRIVATE_EXPORT TlsKey {
|
||||||
class TlsKey {
|
|
||||||
public:
|
public:
|
||||||
virtual ~TlsKey();
|
virtual ~TlsKey();
|
||||||
|
|
||||||
@ -137,7 +143,7 @@ public:
|
|||||||
|
|
||||||
// An abstraction hiding OpenSSL's X509 or our generic
|
// An abstraction hiding OpenSSL's X509 or our generic
|
||||||
// 'derData'-based code.
|
// 'derData'-based code.
|
||||||
class X509Certificate
|
class Q_NETWORK_PRIVATE_EXPORT X509Certificate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~X509Certificate();
|
virtual ~X509Certificate();
|
||||||
@ -191,12 +197,43 @@ using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertif
|
|||||||
QList<QSslCertificate> *caCertificates,
|
QList<QSslCertificate> *caCertificates,
|
||||||
const QByteArray &passPhrase);
|
const QByteArray &passPhrase);
|
||||||
|
|
||||||
|
#if QT_CONFIG(ssl)
|
||||||
// TLS over TCP. Handshake, encryption/decryption.
|
// 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;
|
class TlsCryptograph;
|
||||||
|
#endif // QT_CONFIG(ssl)
|
||||||
|
|
||||||
#if QT_CONFIG(dtls)
|
#if QT_CONFIG(dtls)
|
||||||
|
|
||||||
class DtlsBase
|
class Q_NETWORK_PRIVATE_EXPORT DtlsBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~DtlsBase();
|
virtual ~DtlsBase();
|
||||||
@ -217,7 +254,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// DTLS cookie: generation and verification.
|
// DTLS cookie: generation and verification.
|
||||||
class DtlsCookieVerifier : virtual public DtlsBase
|
class Q_NETWORK_EXPORT DtlsCookieVerifier : virtual public DtlsBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
|
virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram,
|
||||||
@ -226,7 +263,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TLS over UDP. Handshake, encryption/decryption.
|
// TLS over UDP. Handshake, encryption/decryption.
|
||||||
class DtlsCryptograph : virtual public DtlsBase
|
class Q_NETWORK_PRIVATE_EXPORT DtlsCryptograph : virtual public DtlsBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -279,6 +316,11 @@ public:
|
|||||||
~QTlsBackend() override;
|
~QTlsBackend() override;
|
||||||
|
|
||||||
virtual bool isValid() const;
|
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 QString backendName() const = 0;
|
||||||
virtual QList<QSsl::SslProtocol> supportedProtocols() const = 0;
|
virtual QList<QSsl::SslProtocol> supportedProtocols() const = 0;
|
||||||
@ -289,6 +331,8 @@ public:
|
|||||||
virtual QTlsPrivate::TlsKey *createKey() const;
|
virtual QTlsPrivate::TlsKey *createKey() const;
|
||||||
virtual QTlsPrivate::X509Certificate *createCertificate() const;
|
virtual QTlsPrivate::X509Certificate *createCertificate() const;
|
||||||
|
|
||||||
|
virtual QList<QSslCertificate> systemCaCertificates() const;
|
||||||
|
|
||||||
// TLS and DTLS:
|
// TLS and DTLS:
|
||||||
virtual QTlsPrivate::TlsCryptograph *createTlsCryptograph() const;
|
virtual QTlsPrivate::TlsCryptograph *createTlsCryptograph() const;
|
||||||
virtual QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(class QDtls *qObject, int mode) 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 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)
|
Q_DISABLE_COPY_MOVE(QTlsBackend)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,7 +62,18 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
class QSchannelBackend : public QTlsBackend
|
class QSchannelBackend : public QTlsBackend
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
static void ensureInitializedImplementation();
|
||||||
|
|
||||||
private:
|
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;
|
QString backendName() const override;
|
||||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||||
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
QList<QSsl::SupportedFeature> supportedFeatures() const override;
|
||||||
@ -71,8 +82,15 @@ private:
|
|||||||
QTlsPrivate::TlsKey *createKey() const override;
|
QTlsPrivate::TlsKey *createKey() const override;
|
||||||
QTlsPrivate::X509Certificate *createCertificate() 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::X509PemReaderPtr X509PemReader() const override;
|
||||||
QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
|
QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
|
||||||
|
|
||||||
|
static bool s_loadedCiphersAndCerts;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -40,11 +40,234 @@
|
|||||||
#include "qtlsbackend_st_p.h"
|
#include "qtlsbackend_st_p.h"
|
||||||
#include "qtlskey_st_p.h"
|
#include "qtlskey_st_p.h"
|
||||||
#include "qx509_st_p.h"
|
#include "qx509_st_p.h"
|
||||||
|
#include "qtls_st_p.h"
|
||||||
|
|
||||||
|
#include <QtCore/qsysinfo.h>
|
||||||
|
#include <QtCore/qmutex.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC(QRecursiveMutex, qt_securetransport_mutex)
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcTlsBackend, "qt.tlsbackend.securetransport");
|
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
|
QString QSecureTransportBackend::backendName() const
|
||||||
{
|
{
|
||||||
return builtinBackendNames[nameIndexSecureTransport];
|
return builtinBackendNames[nameIndexSecureTransport];
|
||||||
@ -60,6 +283,11 @@ QTlsPrivate::X509Certificate *QSecureTransportBackend::createCertificate() const
|
|||||||
return new QTlsPrivate::X509CertificateSecureTransport;
|
return new QTlsPrivate::X509CertificateSecureTransport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QSslCertificate> QSecureTransportBackend::systemCaCertificates() const
|
||||||
|
{
|
||||||
|
return QTlsPrivate::systemCaCertificates();
|
||||||
|
}
|
||||||
|
|
||||||
QList<QSsl::SslProtocol> QSecureTransportBackend::supportedProtocols() const
|
QList<QSsl::SslProtocol> QSecureTransportBackend::supportedProtocols() const
|
||||||
{
|
{
|
||||||
QList<QSsl::SslProtocol> protocols;
|
QList<QSsl::SslProtocol> protocols;
|
||||||
@ -104,5 +332,10 @@ QTlsPrivate::X509DerReaderPtr QSecureTransportBackend::X509DerReader() const
|
|||||||
return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
|
return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QTlsPrivate::TlsCryptograph *QSecureTransportBackend::createTlsCryptograph() const
|
||||||
|
{
|
||||||
|
return new QTlsPrivate::TlsCryptographSecureTransport;
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -63,6 +63,11 @@ QT_BEGIN_NAMESPACE
|
|||||||
class QSecureTransportBackend : public QTlsBackend
|
class QSecureTransportBackend : public QTlsBackend
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
QString tlsLibraryVersionString() const override;
|
||||||
|
virtual QString tlsLibraryBuildVersionString() const override;
|
||||||
|
virtual void ensureInitialized() const override;
|
||||||
|
|
||||||
QString backendName() const override;
|
QString backendName() const override;
|
||||||
|
|
||||||
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
QList<QSsl::SslProtocol> supportedProtocols() const override;
|
||||||
@ -72,8 +77,14 @@ private:
|
|||||||
QTlsPrivate::TlsKey *createKey() const override;
|
QTlsPrivate::TlsKey *createKey() const override;
|
||||||
QTlsPrivate::X509Certificate *createCertificate() const override;
|
QTlsPrivate::X509Certificate *createCertificate() const override;
|
||||||
|
|
||||||
|
QList<QSslCertificate> systemCaCertificates() const override;
|
||||||
|
|
||||||
QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
|
QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
|
||||||
QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
|
QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
|
||||||
|
|
||||||
|
QTlsPrivate::TlsCryptograph *createTlsCryptograph() const override;
|
||||||
|
|
||||||
|
static bool s_loadedCiphersAndCerts;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
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/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||||
@ -37,8 +37,8 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef QTLS_UTILS_P_H
|
#ifndef QWINCRYPT_P_H
|
||||||
#define QTLS_UTILS_P_H
|
#define QWINCRYPT_P_H
|
||||||
|
|
||||||
//
|
//
|
||||||
// W A R N I N G
|
// W A R N I N G
|
||||||
@ -53,47 +53,29 @@
|
|||||||
|
|
||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
#if QT_CONFIG(openssl)
|
#include <QtCore/qt_windows.h>
|
||||||
#include <QtNetwork/private/qsslsocket_openssl_p.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QtNetwork/private/qssl_p.h>
|
|
||||||
|
|
||||||
#include <QtCore/qglobal.h>
|
#include <QtCore/qglobal.h>
|
||||||
#include <QtCore/qdebug.h>
|
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#ifndef HCRYPTPROV_LEGACY
|
||||||
|
#define HCRYPTPROV_LEGACY HCRYPTPROV
|
||||||
|
#endif // !HCRYPTPROV_LEGACY
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
namespace QTlslUtils
|
struct QHCertStoreDeleter {
|
||||||
{
|
void operator()(HCERTSTORE store)
|
||||||
|
{
|
||||||
template <class NativeTlsType, void (*Deleter)(NativeTlsType *)>
|
CertCloseStore(store, 0);
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
template<class NativeTlsType>
|
// A simple RAII type used by Schannel code and Window CA fetcher class:
|
||||||
using Deleter = std::unique_ptr<NativeTlsType, void (*)(NativeTlsType *)>;
|
using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
|
||||||
|
|
||||||
} // namespace QTlsUtils
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QTLS_UTILS_P_H
|
#endif // QWINCRYPT_P_H
|
@ -52,7 +52,8 @@
|
|||||||
#include "qsslsocket_p.h" // Transitively includes Wincrypt.h
|
#include "qsslsocket_p.h" // Transitively includes Wincrypt.h
|
||||||
|
|
||||||
#if QT_CONFIG(openssl)
|
#if QT_CONFIG(openssl)
|
||||||
#include "qsslsocket_openssl_p.h"
|
#include "qopenssl_p.h"
|
||||||
|
#include "qx509_openssl_p.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -77,7 +78,9 @@ Q_GLOBAL_STATIC(QWindowsCaRootFetcherThread, windowsCaRootFetcherThread);
|
|||||||
|
|
||||||
#if QT_CONFIG(openssl)
|
#if QT_CONFIG(openssl)
|
||||||
namespace {
|
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,
|
const QList<QSslCertificate> buildVerifiedChain(const QList<QSslCertificate> &caCertificates,
|
||||||
PCCERT_CHAIN_CONTEXT chainContext,
|
PCCERT_CHAIN_CONTEXT chainContext,
|
||||||
const QString &peerVerifyName)
|
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.
|
// 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())
|
if (tlsErrors.size())
|
||||||
verifiedChain.clear();
|
verifiedChain.clear();
|
||||||
|
|
||||||
@ -195,7 +198,7 @@ void QWindowsCaRootFetcher::start()
|
|||||||
qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
|
qCDebug(lcSsl) << " - NOT TRUSTED" << chain->TrustStatus.dwErrorStatus;
|
||||||
if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
|
if (chain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED)
|
||||||
qCDebug(lcSsl) << " - 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++) {
|
for (unsigned int i = 0; i < chain->cChain; i++) {
|
||||||
if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
|
if (chain->rgpChain[i]->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR)
|
||||||
qCDebug(lcSsl) << " - TRUSTED SIMPLE CHAIN" << i;
|
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/
|
** Contact: https://www.qt.io/licensing/
|
||||||
**
|
**
|
||||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||||
@ -40,15 +40,15 @@
|
|||||||
#ifndef QWINDOWSCAROOTFETCHER_P_H
|
#ifndef QWINDOWSCAROOTFETCHER_P_H
|
||||||
#define QWINDOWSCAROOTFETCHER_P_H
|
#define QWINDOWSCAROOTFETCHER_P_H
|
||||||
|
|
||||||
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
#include <QtCore/QtGlobal>
|
#include <QtCore/QtGlobal>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
#include "qsslsocket_p.h"
|
|
||||||
|
|
||||||
#include "qsslsocket.h"
|
|
||||||
#include "qsslcertificate.h"
|
#include "qsslcertificate.h"
|
||||||
|
#include "qsslsocket.h"
|
||||||
|
|
||||||
#include <memory>
|
#include "qwincrypt_p.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// W A R N I N G
|
// W A R N I N G
|
||||||
|
@ -43,7 +43,8 @@
|
|||||||
#include "qx509_openssl_p.h"
|
#include "qx509_openssl_p.h"
|
||||||
|
|
||||||
#include "qsslsocket_openssl_symbols_p.h"
|
#include "qsslsocket_openssl_symbols_p.h"
|
||||||
|
#include "qtlsbackend_openssl_p.h"
|
||||||
|
#include "qtls_openssl_p.h"
|
||||||
#include "qsslsocket.h"
|
#include "qsslsocket.h"
|
||||||
|
|
||||||
#include <QtNetwork/qhostaddress.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.
|
// TLSTODO: verification callback has to change as soon as TlsCryptographer is in place.
|
||||||
// This is a temporary solution for now to ease the transition.
|
// This is a temporary solution for now to ease the transition.
|
||||||
const auto offset = QSslSocketBackendPrivate::s_indexForSSLExtraData
|
const auto offset = QTlsBackendOpenSSL::s_indexForSSLExtraData
|
||||||
+ QSslSocketBackendPrivate::errorOffsetInExData;
|
+ 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())))
|
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));
|
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
|
// 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
|
// 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.
|
// 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());
|
roots.append(QSslSocketPrivate::systemCaCertificates());
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
return verify(roots, chain, hostName);
|
return verify(roots, chain, hostName);
|
||||||
|
@ -53,8 +53,7 @@
|
|||||||
|
|
||||||
#include <private/qtnetworkglobal_p.h>
|
#include <private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
// TLSTODO: only temporary, and only because of QSslErrorEntry!
|
#include <private/qopenssl_p.h>
|
||||||
#include <private/qsslsocket_openssl_p.h>
|
|
||||||
|
|
||||||
#include <private/qtlsbackend_p.h>
|
#include <private/qtlsbackend_p.h>
|
||||||
#include <private/qx509_base_p.h>
|
#include <private/qx509_base_p.h>
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||||
|
|
||||||
#include <QtNetwork/private/qsslsocket_openssl_symbols_p.h>
|
#include <QtNetwork/private/qsslsocket_openssl_symbols_p.h>
|
||||||
#include <QtNetwork/private/qsslsocket_openssl_p.h>
|
|
||||||
|
|
||||||
#include <QtNetwork/qsslcertificate.h>
|
#include <QtNetwork/qsslcertificate.h>
|
||||||
#include <QtNetwork/qtcpserver.h>
|
#include <QtNetwork/qtcpserver.h>
|
||||||
|
@ -59,7 +59,6 @@
|
|||||||
#include "private/qtlsbackend_p.h"
|
#include "private/qtlsbackend_p.h"
|
||||||
|
|
||||||
#ifndef QT_NO_OPENSSL
|
#ifndef QT_NO_OPENSSL
|
||||||
#include "private/qsslsocket_openssl_p.h"
|
|
||||||
#include "private/qsslsocket_openssl_symbols_p.h"
|
#include "private/qsslsocket_openssl_symbols_p.h"
|
||||||
#endif // QT_NO_OPENSSL
|
#endif // QT_NO_OPENSSL
|
||||||
|
|
||||||
@ -244,9 +243,6 @@ private slots:
|
|||||||
void writeBigChunk();
|
void writeBigChunk();
|
||||||
void blacklistedCertificates();
|
void blacklistedCertificates();
|
||||||
void versionAccessors();
|
void versionAccessors();
|
||||||
#ifndef QT_NO_OPENSSL
|
|
||||||
void sslOptions();
|
|
||||||
#endif
|
|
||||||
void encryptWithoutConnecting();
|
void encryptWithoutConnecting();
|
||||||
void resume_data();
|
void resume_data();
|
||||||
void resume();
|
void resume();
|
||||||
@ -3001,60 +2997,6 @@ void tst_QSslSocket::versionAccessors()
|
|||||||
qDebug() << QString::number(QSslSocket::sslLibraryVersionNumber(), 16);
|
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()
|
void tst_QSslSocket::encryptWithoutConnecting()
|
||||||
{
|
{
|
||||||
if (!QSslSocket::supportsSsl())
|
if (!QSslSocket::supportsSsl())
|
||||||
|
@ -44,9 +44,6 @@
|
|||||||
|
|
||||||
#ifdef QT_BUILD_INTERNAL
|
#ifdef QT_BUILD_INTERNAL
|
||||||
#include <QtNetwork/private/qhostinfo_p.h>
|
#include <QtNetwork/private/qhostinfo_p.h>
|
||||||
#ifndef QT_NO_OPENSSL
|
|
||||||
#include <QtNetwork/private/qsslsocket_openssl_p.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QSharedPointer<char>)
|
Q_DECLARE_METATYPE(QSharedPointer<char>)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user