Stop using QSslConfigurationPrivate inside the plugin code
It was reasonable while backends were a part of QtNetwork. Now if moving them outside (or just trying to implement a new backend as a plugin), accessing data-members of QSslConfigurationPrivate means that any plugin knows about memory layout actual only for the version of Qt it was built with/for. Instead, we have to use the public class. Since it does not have all needed setters and some data-members have no access at all, we provide an API in QTlsBackend (which stays a part of QtNetwork) that knows the actual memory layout. Task-number: QTBUG-65922 Pick-to: dev Change-Id: I5ca1de4f982b4b11d9a87c4b40413367dcb83c16 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
9391ba5514
commit
31cc0df760
@ -65,37 +65,12 @@ void QDtlsBasePrivate::clearDtlsError()
|
|||||||
|
|
||||||
QSslConfiguration QDtlsBasePrivate::configuration() const
|
QSslConfiguration QDtlsBasePrivate::configuration() const
|
||||||
{
|
{
|
||||||
auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration);
|
return dtlsConfiguration;
|
||||||
copyPrivate->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
|
|
||||||
QSslConfiguration copy(copyPrivate);
|
|
||||||
copyPrivate->sessionCipher = sessionCipher;
|
|
||||||
copyPrivate->sessionProtocol = sessionProtocol;
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
|
void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
|
||||||
{
|
{
|
||||||
dtlsConfiguration.localCertificateChain = configuration.localCertificateChain();
|
dtlsConfiguration = configuration;
|
||||||
dtlsConfiguration.privateKey = configuration.privateKey();
|
|
||||||
dtlsConfiguration.ciphers = configuration.ciphers();
|
|
||||||
dtlsConfiguration.ellipticCurves = configuration.ellipticCurves();
|
|
||||||
dtlsConfiguration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint();
|
|
||||||
dtlsConfiguration.dhParams = configuration.diffieHellmanParameters();
|
|
||||||
dtlsConfiguration.caCertificates = configuration.caCertificates();
|
|
||||||
dtlsConfiguration.peerVerifyDepth = configuration.peerVerifyDepth();
|
|
||||||
dtlsConfiguration.peerVerifyMode = configuration.peerVerifyMode();
|
|
||||||
dtlsConfiguration.protocol = configuration.protocol();
|
|
||||||
dtlsConfiguration.sslOptions = configuration.d->sslOptions;
|
|
||||||
dtlsConfiguration.sslSession = configuration.sessionTicket();
|
|
||||||
dtlsConfiguration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
|
|
||||||
dtlsConfiguration.nextAllowedProtocols = configuration.allowedNextProtocols();
|
|
||||||
dtlsConfiguration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol();
|
|
||||||
dtlsConfiguration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus();
|
|
||||||
dtlsConfiguration.dtlsCookieEnabled = configuration.dtlsCookieVerificationEnabled();
|
|
||||||
dtlsConfiguration.allowRootCertOnDemandLoading = configuration.d->allowRootCertOnDemandLoading;
|
|
||||||
dtlsConfiguration.backendConfig = configuration.backendConfiguration();
|
|
||||||
|
|
||||||
clearDtlsError();
|
clearDtlsError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
QT_REQUIRE_CONFIG(dtls);
|
QT_REQUIRE_CONFIG(dtls);
|
||||||
|
|
||||||
#include "qsslconfiguration_p.h"
|
#include "qsslconfiguration.h"
|
||||||
#include "qtlsbackend_p.h"
|
#include "qtlsbackend_p.h"
|
||||||
#include "qsslcipher.h"
|
#include "qsslcipher.h"
|
||||||
#include "qsslsocket.h"
|
#include "qsslsocket.h"
|
||||||
@ -96,7 +96,7 @@ public:
|
|||||||
|
|
||||||
QDtlsError errorCode = QDtlsError::NoError;
|
QDtlsError errorCode = QDtlsError::NoError;
|
||||||
QString errorDescription;
|
QString errorDescription;
|
||||||
QSslConfigurationPrivate dtlsConfiguration;
|
QSslConfiguration dtlsConfiguration;
|
||||||
QSslSocket::SslMode mode = QSslSocket::SslClientMode;
|
QSslSocket::SslMode mode = QSslSocket::SslClientMode;
|
||||||
QSslCipher sessionCipher;
|
QSslCipher sessionCipher;
|
||||||
QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
|
QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;
|
||||||
|
@ -664,20 +664,15 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol)) {
|
if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol())) {
|
||||||
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
|
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
|
||||||
QDtls::tr("Invalid protocol version, DTLS protocol expected"));
|
QDtls::tr("Invalid protocol version, DTLS protocol expected"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a deep copy of our configuration
|
const bool rootsOnDemand = QTlsBackend::rootLoadingOnDemandAllowed(dtlsBase->dtlsConfiguration);
|
||||||
auto configurationCopy = new QSslConfigurationPrivate(dtlsBase->dtlsConfiguration);
|
TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode, dtlsBase->dtlsConfiguration,
|
||||||
configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
|
rootsOnDemand));
|
||||||
|
|
||||||
// DTLSTODO: check we do not set something DTLS-incompatible there ...
|
|
||||||
TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode,
|
|
||||||
configurationCopy,
|
|
||||||
dtlsBase->dtlsConfiguration.allowRootCertOnDemandLoading));
|
|
||||||
|
|
||||||
if (newContext->error() != QSslError::NoError) {
|
if (newContext->error() != QSslError::NoError) {
|
||||||
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString());
|
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString());
|
||||||
@ -695,14 +690,14 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
|
|||||||
QTlsBackendOpenSSL::s_indexForSSLExtraData,
|
QTlsBackendOpenSSL::s_indexForSSLExtraData,
|
||||||
this);
|
this);
|
||||||
|
|
||||||
if (set != 1 && configurationCopy->peerVerifyMode != QSslSocket::VerifyNone) {
|
if (set != 1 && dtlsBase->dtlsConfiguration.peerVerifyMode() != QSslSocket::VerifyNone) {
|
||||||
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
|
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
|
||||||
msgFunctionFailed("SSL_set_ex_data"));
|
msgFunctionFailed("SSL_set_ex_data"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtlsBase->mode == QSslSocket::SslServerMode) {
|
if (dtlsBase->mode == QSslSocket::SslServerMode) {
|
||||||
if (dtlsBase->dtlsConfiguration.dtlsCookieEnabled)
|
if (dtlsBase->dtlsConfiguration.dtlsCookieVerificationEnabled())
|
||||||
q_SSL_set_options(newConnection.data(), SSL_OP_COOKIE_EXCHANGE);
|
q_SSL_set_options(newConnection.data(), SSL_OP_COOKIE_EXCHANGE);
|
||||||
q_SSL_set_psk_server_callback(newConnection.data(), dtlscallbacks::q_PSK_server_callback);
|
q_SSL_set_psk_server_callback(newConnection.data(), dtlscallbacks::q_PSK_server_callback);
|
||||||
} else {
|
} else {
|
||||||
@ -936,7 +931,7 @@ bool QDtlsPrivateOpenSSL::startHandshake(QUdpSocket *socket, const QByteArray &d
|
|||||||
if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
|
if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieEnabled) {
|
if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieVerificationEnabled()) {
|
||||||
dtls.secret = secret;
|
dtls.secret = secret;
|
||||||
dtls.hashAlgorithm = hashAlgorithm;
|
dtls.hashAlgorithm = hashAlgorithm;
|
||||||
// Let's prepare the state machine so that message sequence 1 does not
|
// Let's prepare the state machine so that message sequence 1 does not
|
||||||
@ -1040,8 +1035,8 @@ bool QDtlsPrivateOpenSSL::continueHandshake(QUdpSocket *socket, const QByteArray
|
|||||||
storePeerCertificates();
|
storePeerCertificates();
|
||||||
fetchNegotiatedParameters();
|
fetchNegotiatedParameters();
|
||||||
|
|
||||||
const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode == QSslSocket::VerifyPeer
|
const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode() == QSslSocket::VerifyPeer
|
||||||
|| (dtlsConfiguration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
|| (dtlsConfiguration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
|
||||||
&& mode == QSslSocket::SslClientMode);
|
&& mode == QSslSocket::SslClientMode);
|
||||||
|
|
||||||
if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) {
|
if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) {
|
||||||
@ -1308,7 +1303,7 @@ 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)
|
||||||
QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint,
|
QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint(),
|
||||||
max_psk_len);
|
max_psk_len);
|
||||||
pskAuthenticator.swap(authenticator);
|
pskAuthenticator.swap(authenticator);
|
||||||
}
|
}
|
||||||
@ -1331,17 +1326,18 @@ unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned c
|
|||||||
|
|
||||||
bool QDtlsPrivateOpenSSL::verifyPeer()
|
bool QDtlsPrivateOpenSSL::verifyPeer()
|
||||||
{
|
{
|
||||||
// DTLSTODO: Windows-specific code for CA fetcher is not here yet.
|
|
||||||
QList<QSslError> errors;
|
QList<QSslError> errors;
|
||||||
|
|
||||||
// Check the whole chain for blacklisting (including root, as we check for
|
// Check the whole chain for blacklisting (including root, as we check for
|
||||||
// subjectInfo and issuer)
|
// subjectInfo and issuer)
|
||||||
for (const QSslCertificate &cert : qAsConst(dtlsConfiguration.peerCertificateChain)) {
|
const auto &peerCertificateChain = dtlsConfiguration.peerCertificateChain();
|
||||||
|
for (const QSslCertificate &cert : peerCertificateChain) {
|
||||||
if (QSslCertificatePrivate::isBlacklisted(cert))
|
if (QSslCertificatePrivate::isBlacklisted(cert))
|
||||||
errors << QSslError(QSslError::CertificateBlacklisted, cert);
|
errors << QSslError(QSslError::CertificateBlacklisted, cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dtlsConfiguration.peerCertificate.isNull()) {
|
const auto peerCertificate = dtlsConfiguration.peerCertificate();
|
||||||
|
if (peerCertificate.isNull()) {
|
||||||
errors << QSslError(QSslError::NoPeerCertificate);
|
errors << QSslError(QSslError::NoPeerCertificate);
|
||||||
} else if (mode == QSslSocket::SslClientMode) {
|
} else if (mode == 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
|
||||||
@ -1358,15 +1354,15 @@ bool QDtlsPrivateOpenSSL::verifyPeer()
|
|||||||
name = dtls.udpSocket->peerName();
|
name = dtls.udpSocket->peerName();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
|
if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(peerCertificate, name))
|
||||||
errors << QSslError(QSslError::HostNameMismatch, dtlsConfiguration.peerCertificate);
|
errors << QSslError(QSslError::HostNameMismatch, peerCertificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate errors from the error list into QSslErrors
|
// Translate errors from the error list into QSslErrors
|
||||||
using CertClass = QTlsPrivate::X509CertificateOpenSSL;
|
using CertClass = QTlsPrivate::X509CertificateOpenSSL;
|
||||||
errors.reserve(errors.size() + opensslErrors.size());
|
errors.reserve(errors.size() + opensslErrors.size());
|
||||||
for (const auto &error : qAsConst(opensslErrors)) {
|
for (const auto &error : qAsConst(opensslErrors)) {
|
||||||
const auto value = dtlsConfiguration.peerCertificateChain.value(error.depth);
|
const auto value = peerCertificateChain.value(error.depth);
|
||||||
errors << CertClass::openSSLErrorToQSslError(error.code, value);
|
errors << CertClass::openSSLErrorToQSslError(error.code, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1382,13 +1378,17 @@ void QDtlsPrivateOpenSSL::storePeerCertificates()
|
|||||||
// peer certificate and the chain may be empty if the peer didn't present
|
// peer certificate and the chain may be empty if the peer didn't present
|
||||||
// any certificate.
|
// any certificate.
|
||||||
X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data());
|
X509 *x509 = q_SSL_get_peer_certificate(dtls.tlsConnection.data());
|
||||||
dtlsConfiguration.peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
|
const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
|
||||||
|
QTlsBackend::storePeerCertificate(dtlsConfiguration, peerCertificate);
|
||||||
q_X509_free(x509);
|
q_X509_free(x509);
|
||||||
if (dtlsConfiguration.peerCertificateChain.isEmpty()) {
|
|
||||||
|
auto peerCertificateChain = dtlsConfiguration.peerCertificateChain();
|
||||||
|
if (peerCertificateChain.isEmpty()) {
|
||||||
auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
|
auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
|
||||||
dtlsConfiguration.peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack);
|
peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack);
|
||||||
if (!dtlsConfiguration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
|
if (!peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
|
||||||
dtlsConfiguration.peerCertificateChain.prepend(dtlsConfiguration.peerCertificate);
|
peerCertificateChain.prepend(peerCertificate);
|
||||||
|
QTlsBackend::storePeerCertificateChain(dtlsConfiguration, peerCertificateChain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1441,8 +1441,7 @@ void QDtlsPrivateOpenSSL::resetDtls()
|
|||||||
connectionEncrypted = false;
|
connectionEncrypted = false;
|
||||||
tlsErrors.clear();
|
tlsErrors.clear();
|
||||||
tlsErrorsToIgnore.clear();
|
tlsErrorsToIgnore.clear();
|
||||||
dtlsConfiguration.peerCertificate.clear();
|
QTlsBackend::clearPeerCertificates(dtlsConfiguration);
|
||||||
dtlsConfiguration.peerCertificateChain.clear();
|
|
||||||
connectionWasShutdown = false;
|
connectionWasShutdown = false;
|
||||||
handshakeState = QDtls::HandshakeNotStarted;
|
handshakeState = QDtls::HandshakeNotStarted;
|
||||||
sessionCipher = {};
|
sessionCipher = {};
|
||||||
|
@ -72,11 +72,6 @@ class QSslKey;
|
|||||||
class QSslEllipticCurve;
|
class QSslEllipticCurve;
|
||||||
class QSslDiffieHellmanParameters;
|
class QSslDiffieHellmanParameters;
|
||||||
|
|
||||||
namespace dtlsopenssl
|
|
||||||
{
|
|
||||||
class DtlsState;
|
|
||||||
}
|
|
||||||
|
|
||||||
class QSslConfigurationPrivate;
|
class QSslConfigurationPrivate;
|
||||||
class Q_NETWORK_EXPORT QSslConfiguration
|
class Q_NETWORK_EXPORT QSslConfiguration
|
||||||
{
|
{
|
||||||
@ -202,8 +197,7 @@ private:
|
|||||||
friend class QSslSocket;
|
friend class QSslSocket;
|
||||||
friend class QSslConfigurationPrivate;
|
friend class QSslConfigurationPrivate;
|
||||||
friend class QSslContext;
|
friend class QSslContext;
|
||||||
friend class QDtlsBasePrivate;
|
friend class QTlsBackend;
|
||||||
friend class dtlsopenssl::DtlsState;
|
|
||||||
QSslConfiguration(QSslConfigurationPrivate *dd);
|
QSslConfiguration(QSslConfigurationPrivate *dd);
|
||||||
QSharedDataPointer<QSslConfigurationPrivate> d;
|
QSharedDataPointer<QSslConfigurationPrivate> d;
|
||||||
};
|
};
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate: public QSharedData
|
class QSslConfigurationPrivate: public QSharedData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QSslConfigurationPrivate()
|
QSslConfigurationPrivate()
|
||||||
@ -114,7 +114,7 @@ public:
|
|||||||
bool allowRootCertOnDemandLoading;
|
bool allowRootCertOnDemandLoading;
|
||||||
bool peerSessionShared;
|
bool peerSessionShared;
|
||||||
|
|
||||||
static bool peerSessionWasShared(const QSslConfiguration &configuration);
|
Q_AUTOTEST_EXPORT static bool peerSessionWasShared(const QSslConfiguration &configuration);
|
||||||
|
|
||||||
QSsl::SslOptions sslOptions;
|
QSsl::SslOptions sslOptions;
|
||||||
|
|
||||||
|
@ -3120,14 +3120,6 @@ QSslSocket::SslMode QSslSocketPrivate::tlsMode() const
|
|||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
\internal
|
|
||||||
*/
|
|
||||||
QSslConfigurationPrivate &QSslSocketPrivate::privateConfiguration()
|
|
||||||
{
|
|
||||||
return configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
|
@ -172,7 +172,6 @@ public:
|
|||||||
|
|
||||||
// Needed by TlsCryptograph:
|
// Needed by TlsCryptograph:
|
||||||
Q_NETWORK_PRIVATE_EXPORT QSslSocket::SslMode tlsMode() const;
|
Q_NETWORK_PRIVATE_EXPORT QSslSocket::SslMode tlsMode() const;
|
||||||
Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate &privateConfiguration();
|
|
||||||
Q_NETWORK_PRIVATE_EXPORT bool isRootsOnDemandAllowed() const;
|
Q_NETWORK_PRIVATE_EXPORT bool isRootsOnDemandAllowed() const;
|
||||||
Q_NETWORK_PRIVATE_EXPORT QString verificationName() const;
|
Q_NETWORK_PRIVATE_EXPORT QString verificationName() const;
|
||||||
Q_NETWORK_PRIVATE_EXPORT QString tlsHostName() const;
|
Q_NETWORK_PRIVATE_EXPORT QString tlsHostName() const;
|
||||||
|
@ -560,7 +560,6 @@ bool TlsCryptographOpenSSL::startHandshake()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto mode = d->tlsMode();
|
const auto mode = d->tlsMode();
|
||||||
auto &configuration = d->privateConfiguration();
|
|
||||||
|
|
||||||
pendingFatalAlert = false;
|
pendingFatalAlert = false;
|
||||||
errorsReportedFromCallback = false;
|
errorsReportedFromCallback = false;
|
||||||
@ -581,10 +580,14 @@ bool TlsCryptographOpenSSL::startHandshake()
|
|||||||
if (!lastErrors.isEmpty() || errorsReportedFromCallback)
|
if (!lastErrors.isEmpty() || errorsReportedFromCallback)
|
||||||
storePeerCertificates();
|
storePeerCertificates();
|
||||||
|
|
||||||
|
// storePeerCertificate() if called above - would update the
|
||||||
|
// configuration with peer's certificates.
|
||||||
|
auto configuration = q->sslConfiguration();
|
||||||
if (!errorsReportedFromCallback) {
|
if (!errorsReportedFromCallback) {
|
||||||
|
const auto &peerCertificateChain = configuration.peerCertificateChain();
|
||||||
for (const auto ¤tError : qAsConst(lastErrors)) {
|
for (const auto ¤tError : qAsConst(lastErrors)) {
|
||||||
emit q->peerVerifyError(QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(currentError.code,
|
emit q->peerVerifyError(QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(currentError.code,
|
||||||
configuration.peerCertificateChain.value(currentError.depth)));
|
peerCertificateChain.value(currentError.depth)));
|
||||||
if (q->state() != QAbstractSocket::ConnectedState)
|
if (q->state() != QAbstractSocket::ConnectedState)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -627,8 +630,11 @@ bool TlsCryptographOpenSSL::startHandshake()
|
|||||||
// Start translating errors.
|
// Start translating errors.
|
||||||
QList<QSslError> errors;
|
QList<QSslError> errors;
|
||||||
|
|
||||||
// check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer)
|
// Note, the storePeerCerificates() probably updated the configuration at this point.
|
||||||
for (const QSslCertificate &cert : qAsConst(configuration.peerCertificateChain)) {
|
configuration = q->sslConfiguration();
|
||||||
|
// Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer)
|
||||||
|
const auto &peerCertificateChain = configuration.peerCertificateChain();
|
||||||
|
for (const QSslCertificate &cert : peerCertificateChain) {
|
||||||
if (QSslCertificatePrivate::isBlacklisted(cert)) {
|
if (QSslCertificatePrivate::isBlacklisted(cert)) {
|
||||||
QSslError error(QSslError::CertificateBlacklisted, cert);
|
QSslError error(QSslError::CertificateBlacklisted, cert);
|
||||||
errors << error;
|
errors << error;
|
||||||
@ -638,14 +644,14 @@ bool TlsCryptographOpenSSL::startHandshake()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
&& mode == QSslSocket::SslClientMode);
|
||||||
|
|
||||||
#if QT_CONFIG(ocsp)
|
#if QT_CONFIG(ocsp)
|
||||||
// For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early,
|
// For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early,
|
||||||
// if it's enabled in QSslSocket::SslServerMode. This can change.
|
// if it's enabled in QSslSocket::SslServerMode. This can change.
|
||||||
if (!configuration.peerCertificate.isNull() && configuration.ocspStaplingEnabled && doVerifyPeer) {
|
if (!configuration.peerCertificate().isNull() && configuration.ocspStaplingEnabled() && doVerifyPeer) {
|
||||||
if (!checkOcspStatus()) {
|
if (!checkOcspStatus()) {
|
||||||
if (ocspErrors.isEmpty()) {
|
if (ocspErrors.isEmpty()) {
|
||||||
{
|
{
|
||||||
@ -669,16 +675,16 @@ bool TlsCryptographOpenSSL::startHandshake()
|
|||||||
// 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
|
||||||
const auto verificationPeerName = d->verificationName();
|
const auto verificationPeerName = d->verificationName();
|
||||||
if (mode == QSslSocket::SslClientMode) {
|
if (mode == QSslSocket::SslClientMode) {
|
||||||
QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
|
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.
|
||||||
QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
|
QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
|
||||||
errors << error;
|
errors << error;
|
||||||
emit q->peerVerifyError(error);
|
emit q->peerVerifyError(error);
|
||||||
if (q->state() != QAbstractSocket::ConnectedState)
|
if (q->state() != QAbstractSocket::ConnectedState)
|
||||||
@ -700,7 +706,7 @@ bool TlsCryptographOpenSSL::startHandshake()
|
|||||||
// Translate errors from the error list into QSslErrors.
|
// Translate errors from the error list into QSslErrors.
|
||||||
errors.reserve(errors.size() + errorList.size());
|
errors.reserve(errors.size() + errorList.size());
|
||||||
for (const auto &error : qAsConst(errorList))
|
for (const auto &error : qAsConst(errorList))
|
||||||
errors << X509CertificateOpenSSL::openSSLErrorToQSslError(error.code, configuration.peerCertificateChain.value(error.depth));
|
errors << X509CertificateOpenSSL::openSSLErrorToQSslError(error.code, peerCertificateChain.value(error.depth));
|
||||||
|
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
sslErrors = errors;
|
sslErrors = errors;
|
||||||
@ -762,7 +768,6 @@ void TlsCryptographOpenSSL::continueHandshake()
|
|||||||
auto *plainSocket = d->plainTcpSocket();
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
Q_ASSERT(plainSocket);
|
Q_ASSERT(plainSocket);
|
||||||
|
|
||||||
auto &configuration = d->privateConfiguration();
|
|
||||||
const auto mode = d->tlsMode();
|
const auto mode = d->tlsMode();
|
||||||
|
|
||||||
// if we have a max read buffer size, reset the plain socket's to match
|
// if we have a max read buffer size, reset the plain socket's to match
|
||||||
@ -770,7 +775,7 @@ void TlsCryptographOpenSSL::continueHandshake()
|
|||||||
plainSocket->setReadBufferSize(maxSize);
|
plainSocket->setReadBufferSize(maxSize);
|
||||||
|
|
||||||
if (q_SSL_session_reused(ssl))
|
if (q_SSL_session_reused(ssl))
|
||||||
configuration.peerSessionShared = true;
|
QTlsBackend::setPeerSessionShared(d, true);
|
||||||
|
|
||||||
#ifdef QT_DECRYPT_SSL_TRAFFIC
|
#ifdef QT_DECRYPT_SSL_TRAFFIC
|
||||||
if (q_SSL_get_session(ssl)) {
|
if (q_SSL_get_session(ssl)) {
|
||||||
@ -803,26 +808,29 @@ void TlsCryptographOpenSSL::continueHandshake()
|
|||||||
}
|
}
|
||||||
#endif // QT_DECRYPT_SSL_TRAFFIC
|
#endif // QT_DECRYPT_SSL_TRAFFIC
|
||||||
|
|
||||||
|
const auto &configuration = q->sslConfiguration();
|
||||||
// Cache this SSL session inside the QSslContext
|
// Cache this SSL session inside the QSslContext
|
||||||
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) {
|
if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionSharing))) {
|
||||||
if (!sslContextPointer->cacheSession(ssl)) {
|
if (!sslContextPointer->cacheSession(ssl)) {
|
||||||
sslContextPointer.clear(); // we could not cache the session
|
sslContextPointer.clear(); // we could not cache the session
|
||||||
} else {
|
} else {
|
||||||
// Cache the session for permanent usage as well
|
// Cache the session for permanent usage as well
|
||||||
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) {
|
if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionPersistence))) {
|
||||||
if (!sslContextPointer->sessionASN1().isEmpty())
|
if (!sslContextPointer->sessionASN1().isEmpty())
|
||||||
configuration.sslSession = sslContextPointer->sessionASN1();
|
QTlsBackend::setSessionAsn1(d, sslContextPointer->sessionASN1());
|
||||||
configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint();
|
QTlsBackend::setSessionLifetimeHint(d, sslContextPointer->sessionTicketLifeTimeHint());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(OPENSSL_NO_NEXTPROTONEG)
|
#if !defined(OPENSSL_NO_NEXTPROTONEG)
|
||||||
|
|
||||||
configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
|
QTlsBackend::setAlpnStatus(d, sslContextPointer->npnContext().status);
|
||||||
if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
|
if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
|
||||||
// we could not agree -> be conservative and use HTTP/1.1
|
// we could not agree -> be conservative and use HTTP/1.1
|
||||||
configuration.nextNegotiatedProtocol = QByteArrayLiteral("http/1.1");
|
// T.P.: I have to admit, this is a really strange notion of 'conservative',
|
||||||
|
// given the protocol-neutral nature of ALPN/NPN.
|
||||||
|
QTlsBackend::setNegotiatedProtocol(d, QByteArrayLiteral("http/1.1"));
|
||||||
} else {
|
} else {
|
||||||
const unsigned char *proto = nullptr;
|
const unsigned char *proto = nullptr;
|
||||||
unsigned int proto_len = 0;
|
unsigned int proto_len = 0;
|
||||||
@ -830,7 +838,7 @@ void TlsCryptographOpenSSL::continueHandshake()
|
|||||||
q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
|
q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
|
||||||
if (proto_len && mode == QSslSocket::SslClientMode) {
|
if (proto_len && mode == QSslSocket::SslClientMode) {
|
||||||
// Client does not have a callback that sets it ...
|
// Client does not have a callback that sets it ...
|
||||||
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
|
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!proto_len) { // Test if NPN was more lucky ...
|
if (!proto_len) { // Test if NPN was more lucky ...
|
||||||
@ -838,16 +846,16 @@ void TlsCryptographOpenSSL::continueHandshake()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (proto_len)
|
if (proto_len)
|
||||||
configuration.nextNegotiatedProtocol = QByteArray(reinterpret_cast<const char *>(proto), proto_len);
|
QTlsBackend::setNegotiatedProtocol(d, QByteArray(reinterpret_cast<const char *>(proto), proto_len));
|
||||||
else
|
else
|
||||||
configuration.nextNegotiatedProtocol.clear();
|
QTlsBackend::setNegotiatedProtocol(d,{});
|
||||||
}
|
}
|
||||||
#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
|
#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
|
||||||
|
|
||||||
if (mode == QSslSocket::SslClientMode) {
|
if (mode == QSslSocket::SslClientMode) {
|
||||||
EVP_PKEY *key;
|
EVP_PKEY *key;
|
||||||
if (q_SSL_get_server_tmp_key(ssl, &key))
|
if (q_SSL_get_server_tmp_key(ssl, &key))
|
||||||
configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey);
|
QTlsBackend::setEphemeralKey(d, QSslKey(key, QSsl::PublicKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
d->setEncrypted(true);
|
d->setEncrypted(true);
|
||||||
@ -1175,12 +1183,11 @@ bool TlsCryptographOpenSSL::checkSslErrors()
|
|||||||
|
|
||||||
emit q->sslErrors(sslErrors);
|
emit q->sslErrors(sslErrors);
|
||||||
|
|
||||||
auto &configuration = d->privateConfiguration();
|
const auto vfyMode = q->peerVerifyMode();
|
||||||
const auto mode = d->tlsMode();
|
const auto mode = d->tlsMode();
|
||||||
|
|
||||||
bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
bool doVerifyPeer = vfyMode == QSslSocket::VerifyPeer || (vfyMode == QSslSocket::AutoVerifyPeer
|
||||||
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
&& mode == QSslSocket::SslClientMode);
|
||||||
&& mode == QSslSocket::SslClientMode);
|
|
||||||
bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
|
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) {
|
||||||
@ -1204,7 +1211,9 @@ int TlsCryptographOpenSSL::handleNewSessionTicket(SSL *connection)
|
|||||||
// 0 would tell OpenSSL to deref (but they still have it in the
|
// 0 would tell OpenSSL to deref (but they still have it in the
|
||||||
// internal cache).
|
// internal cache).
|
||||||
Q_ASSERT(connection);
|
Q_ASSERT(connection);
|
||||||
|
|
||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
|
Q_ASSERT(d);
|
||||||
|
|
||||||
if (q->sslConfiguration().testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
|
if (q->sslConfiguration().testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
|
||||||
// We silently ignore, do nothing, remove from cache.
|
// We silently ignore, do nothing, remove from cache.
|
||||||
@ -1244,9 +1253,8 @@ int TlsCryptographOpenSSL::handleNewSessionTicket(SSL *connection)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &configuration = d->privateConfiguration();
|
QTlsBackend::setSessionAsn1(d, sessionTicket);
|
||||||
configuration.sslSession = sessionTicket;
|
QTlsBackend::setSessionLifetimeHint(d, q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
|
||||||
configuration.sslSessionTicketLifeTimeHint = int(q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
|
|
||||||
|
|
||||||
emit q->newSessionTicketReceived();
|
emit q->newSessionTicketReceived();
|
||||||
return 0;
|
return 0;
|
||||||
@ -1344,17 +1352,11 @@ bool TlsCryptographOpenSSL::initSslContext()
|
|||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
|
|
||||||
// If no external context was set (e.g. by QHttpNetworkConnection) we will
|
// If no external context was set (e.g. by QHttpNetworkConnection) we will
|
||||||
// create a default context
|
// create a new one.
|
||||||
auto &configuration = d->privateConfiguration();
|
|
||||||
const auto mode = d->tlsMode();
|
const auto mode = d->tlsMode();
|
||||||
|
const auto configuration = q->sslConfiguration();
|
||||||
if (!sslContextPointer) {
|
if (!sslContextPointer)
|
||||||
// create a deep copy of our configuration
|
sslContextPointer = QSslContext::sharedFromConfiguration(mode, configuration, d->isRootsOnDemandAllowed());
|
||||||
QSslConfigurationPrivate *configurationCopy = new QSslConfigurationPrivate(configuration);
|
|
||||||
configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
|
|
||||||
sslContextPointer = QSslContext::sharedFromPrivateConfiguration(mode, configurationCopy,
|
|
||||||
d->isRootsOnDemandAllowed());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sslContextPointer->error() != QSslError::NoError) {
|
if (sslContextPointer->error() != QSslError::NoError) {
|
||||||
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
|
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
|
||||||
@ -1369,7 +1371,7 @@ bool TlsCryptographOpenSSL::initSslContext()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configuration.protocol != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
|
if (configuration.protocol() != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
|
||||||
const auto verificationPeerName = d->verificationName();
|
const auto verificationPeerName = d->verificationName();
|
||||||
// Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
|
// Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
|
||||||
QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
|
QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
|
||||||
@ -1379,7 +1381,7 @@ bool TlsCryptographOpenSSL::initSslContext()
|
|||||||
// only send the SNI header if the URL is valid and not an IP
|
// only send the SNI header if the URL is valid and not an IP
|
||||||
if (!ace.isEmpty()
|
if (!ace.isEmpty()
|
||||||
&& !QHostAddress().setAddress(tlsHostName)
|
&& !QHostAddress().setAddress(tlsHostName)
|
||||||
&& !(configuration.sslOptions & QSsl::SslOptionDisableServerNameIndication)) {
|
&& !(configuration.testSslOption(QSsl::SslOptionDisableServerNameIndication))) {
|
||||||
// We don't send the trailing dot from the host header if present see
|
// We don't send the trailing dot from the host header if present see
|
||||||
// https://tools.ietf.org/html/rfc6066#section-3
|
// https://tools.ietf.org/html/rfc6066#section-3
|
||||||
if (ace.endsWith('.'))
|
if (ace.endsWith('.'))
|
||||||
@ -1433,7 +1435,7 @@ bool TlsCryptographOpenSSL::initSslContext()
|
|||||||
#endif // OPENSSL_NO_PSK
|
#endif // OPENSSL_NO_PSK
|
||||||
|
|
||||||
#if QT_CONFIG(ocsp)
|
#if QT_CONFIG(ocsp)
|
||||||
if (configuration.ocspStaplingEnabled) {
|
if (configuration.ocspStaplingEnabled()) {
|
||||||
if (mode == QSslSocket::SslServerMode) {
|
if (mode == QSslSocket::SslServerMode) {
|
||||||
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||||
QSslSocket::tr("Server-side QSslSocket does not support OCSP stapling"));
|
QSslSocket::tr("Server-side QSslSocket does not support OCSP stapling"));
|
||||||
@ -1447,8 +1449,9 @@ bool TlsCryptographOpenSSL::initSslContext()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ocspResponseDer.clear();
|
ocspResponseDer.clear();
|
||||||
auto responsePos = configuration.backendConfig.find("Qt-OCSP-response");
|
const auto backendConfig = configuration.backendConfiguration();
|
||||||
if (responsePos != configuration.backendConfig.end()) {
|
auto responsePos = backendConfig.find("Qt-OCSP-response");
|
||||||
|
if (responsePos != backendConfig.end()) {
|
||||||
// This is our private, undocumented 'API' we use for the auto-testing of
|
// This is our private, undocumented 'API' we use for the auto-testing of
|
||||||
// OCSP-stapling. It must be a der-encoded OCSP response, presumably set
|
// OCSP-stapling. It must be a der-encoded OCSP response, presumably set
|
||||||
// by tst_QOcsp.
|
// by tst_QOcsp.
|
||||||
@ -1491,18 +1494,22 @@ void TlsCryptographOpenSSL::destroySslContext()
|
|||||||
void TlsCryptographOpenSSL::storePeerCertificates()
|
void TlsCryptographOpenSSL::storePeerCertificates()
|
||||||
{
|
{
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
auto &configuration = d->privateConfiguration();
|
|
||||||
// Store the peer certificate and chain. For clients, the peer certificate
|
// Store the peer certificate and chain. For clients, the peer certificate
|
||||||
// chain includes the peer certificate; for servers, it doesn't. Both the
|
// chain includes the peer certificate; for servers, it doesn't. Both the
|
||||||
// peer certificate and the chain may be empty if the peer didn't present
|
// peer certificate and the chain may be empty if the peer didn't present
|
||||||
// any certificate.
|
// any certificate.
|
||||||
X509 *x509 = q_SSL_get_peer_certificate(ssl);
|
X509 *x509 = q_SSL_get_peer_certificate(ssl);
|
||||||
configuration.peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
|
|
||||||
|
const auto peerCertificate = QTlsPrivate::X509CertificateOpenSSL::certificateFromX509(x509);
|
||||||
|
QTlsBackend::storePeerCertificate(d, peerCertificate);
|
||||||
q_X509_free(x509);
|
q_X509_free(x509);
|
||||||
if (configuration.peerCertificateChain.isEmpty()) {
|
auto peerCertificateChain = q->peerCertificateChain();
|
||||||
configuration.peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(q_SSL_get_peer_cert_chain(ssl));
|
if (peerCertificateChain.isEmpty()) {
|
||||||
if (!configuration.peerCertificate.isNull() && d->tlsMode() == QSslSocket::SslServerMode)
|
peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(q_SSL_get_peer_cert_chain(ssl));
|
||||||
configuration.peerCertificateChain.prepend(configuration.peerCertificate);
|
if (!peerCertificate.isNull() && d->tlsMode() == QSslSocket::SslServerMode)
|
||||||
|
peerCertificateChain.prepend(peerCertificate);
|
||||||
|
QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1513,9 +1520,9 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
|
|||||||
Q_ASSERT(ssl);
|
Q_ASSERT(ssl);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
|
|
||||||
auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode
|
Q_ASSERT(d->tlsMode() == QSslSocket::SslClientMode); // See initSslContext() for SslServerMode
|
||||||
Q_ASSERT(configuration.peerVerifyMode != QSslSocket::VerifyNone);
|
Q_ASSERT(configuration.peerVerifyMode() != QSslSocket::VerifyNone);
|
||||||
|
|
||||||
const auto clearErrorQueue = qScopeGuard([] {
|
const auto clearErrorQueue = qScopeGuard([] {
|
||||||
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
QTlsBackendOpenSSL::logAndClearErrorQueue();
|
||||||
@ -1605,10 +1612,10 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
|
|||||||
// issuer's public key.
|
// issuer's public key.
|
||||||
ocspResponses.push_back(QOcspResponse());
|
ocspResponses.push_back(QOcspResponse());
|
||||||
QOcspResponsePrivate *dResponse = ocspResponses.back().d.data();
|
QOcspResponsePrivate *dResponse = ocspResponses.back().d.data();
|
||||||
dResponse->subjectCert = configuration.peerCertificate;
|
dResponse->subjectCert = configuration.peerCertificate();
|
||||||
bool matchFound = false;
|
bool matchFound = false;
|
||||||
if (configuration.peerCertificate.isSelfSigned()) {
|
if (dResponse->subjectCert.isSelfSigned()) {
|
||||||
dResponse->signerCert = configuration.peerCertificate;
|
dResponse->signerCert = configuration.peerCertificate();
|
||||||
matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509);
|
matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509);
|
||||||
} else {
|
} else {
|
||||||
const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl);
|
const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl);
|
||||||
@ -1635,7 +1642,7 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
|
|||||||
|
|
||||||
if (!matchFound) {
|
if (!matchFound) {
|
||||||
dResponse->signerCert.clear();
|
dResponse->signerCert.clear();
|
||||||
ocspErrors.push_back({QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate});
|
ocspErrors.push_back({QSslError::OcspResponseCertIdUnknown, configuration.peerCertificate()});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the response is valid time-wise:
|
// Check if the response is valid time-wise:
|
||||||
@ -1663,7 +1670,7 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
|
|||||||
// next < this ? -> NEXT_BEFORE_THIS
|
// next < this ? -> NEXT_BEFORE_THIS
|
||||||
// OK.
|
// OK.
|
||||||
if (!q_OCSP_check_validity(thisUpdate, nextUpdate, 60, -1))
|
if (!q_OCSP_check_validity(thisUpdate, nextUpdate, 60, -1))
|
||||||
ocspErrors.push_back({QSslError::OcspResponseExpired, configuration.peerCertificate});
|
ocspErrors.push_back({QSslError::OcspResponseExpired, configuration.peerCertificate()});
|
||||||
|
|
||||||
// And finally, the status:
|
// And finally, the status:
|
||||||
switch (certStatus) {
|
switch (certStatus) {
|
||||||
@ -1674,11 +1681,11 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
|
|||||||
case V_OCSP_CERTSTATUS_REVOKED:
|
case V_OCSP_CERTSTATUS_REVOKED:
|
||||||
dResponse->certificateStatus = QOcspCertificateStatus::Revoked;
|
dResponse->certificateStatus = QOcspCertificateStatus::Revoked;
|
||||||
dResponse->revocationReason = qt_OCSP_revocation_reason(reason);
|
dResponse->revocationReason = qt_OCSP_revocation_reason(reason);
|
||||||
ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate});
|
ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate()});
|
||||||
break;
|
break;
|
||||||
case V_OCSP_CERTSTATUS_UNKNOWN:
|
case V_OCSP_CERTSTATUS_UNKNOWN:
|
||||||
dResponse->certificateStatus = QOcspCertificateStatus::Unknown;
|
dResponse->certificateStatus = QOcspCertificateStatus::Unknown;
|
||||||
ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate});
|
ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate()});
|
||||||
}
|
}
|
||||||
|
|
||||||
return !ocspErrors.size();
|
return !ocspErrors.size();
|
||||||
@ -1722,7 +1729,7 @@ unsigned TlsCryptographOpenSSL::pskServerTlsCallback(const char *identity, unsig
|
|||||||
QSslPreSharedKeyAuthenticator authenticator;
|
QSslPreSharedKeyAuthenticator authenticator;
|
||||||
|
|
||||||
// Fill in some read-only fields (for the user)
|
// Fill in some read-only fields (for the user)
|
||||||
QTlsBackend::setupServerPskAuth(&authenticator, identity, d->privateConfiguration().preSharedKeyIdentityHint,
|
QTlsBackend::setupServerPskAuth(&authenticator, identity, q->sslConfiguration().preSharedKeyIdentityHint(),
|
||||||
max_psk_len);
|
max_psk_len);
|
||||||
emit q->preSharedKeyAuthenticationRequired(&authenticator);
|
emit q->preSharedKeyAuthenticationRequired(&authenticator);
|
||||||
|
|
||||||
@ -1747,7 +1754,7 @@ void TlsCryptographOpenSSL::fetchCaRootForCert(const QSslCertificate &cert)
|
|||||||
//so the request is done in a worker thread.
|
//so the request is done in a worker thread.
|
||||||
QList<QSslCertificate> customRoots;
|
QList<QSslCertificate> customRoots;
|
||||||
if (fetchAuthorityInformation)
|
if (fetchAuthorityInformation)
|
||||||
customRoots = d->privateConfiguration().caCertificates;
|
customRoots = q->sslConfiguration().caCertificates();
|
||||||
|
|
||||||
//Remember we are fetching and what we are fetching:
|
//Remember we are fetching and what we are fetching:
|
||||||
caToFetch = cert;
|
caToFetch = cert;
|
||||||
@ -1771,12 +1778,11 @@ void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate t
|
|||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
|
|
||||||
auto &configuration = d->privateConfiguration();
|
|
||||||
//Done, fetched already:
|
//Done, fetched already:
|
||||||
caToFetch = QSslCertificate{};
|
caToFetch = QSslCertificate{};
|
||||||
|
|
||||||
if (fetchAuthorityInformation) {
|
if (fetchAuthorityInformation) {
|
||||||
if (!configuration.caCertificates.contains(trustedRoot))
|
if (!q->sslConfiguration().caCertificates().contains(trustedRoot))
|
||||||
trustedRoot = QSslCertificate{};
|
trustedRoot = QSslCertificate{};
|
||||||
fetchAuthorityInformation = false;
|
fetchAuthorityInformation = false;
|
||||||
}
|
}
|
||||||
@ -1789,8 +1795,7 @@ void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate t
|
|||||||
QSslConfiguration::setDefaultConfiguration(defaultConfig);
|
QSslConfiguration::setDefaultConfiguration(defaultConfig);
|
||||||
}
|
}
|
||||||
//Add the new root cert to this socket for future connections
|
//Add the new root cert to this socket for future connections
|
||||||
if (!configuration.caCertificates.contains(trustedRoot))
|
QTlsBackend::addTustedRoot(d, trustedRoot);
|
||||||
configuration.caCertificates += trustedRoot;
|
|
||||||
//Remove the broken chain ssl errors (as chain is verified by windows)
|
//Remove the broken chain ssl errors (as chain is verified by windows)
|
||||||
for (int i=sslErrors.count() - 1; i >= 0; --i) {
|
for (int i=sslErrors.count() - 1; i >= 0; --i) {
|
||||||
if (sslErrors.at(i).certificate() == cert) {
|
if (sslErrors.at(i).certificate() == cert) {
|
||||||
|
@ -764,6 +764,7 @@ QString TlsCryptographSchannel::targetName() const
|
|||||||
ULONG TlsCryptographSchannel::getContextRequirements()
|
ULONG TlsCryptographSchannel::getContextRequirements()
|
||||||
{
|
{
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
|
Q_ASSERT(q);
|
||||||
|
|
||||||
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||||
ULONG req = 0;
|
ULONG req = 0;
|
||||||
@ -777,7 +778,7 @@ ULONG TlsCryptographSchannel::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 (d->privateConfiguration().peerVerifyMode) {
|
switch (q->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:
|
||||||
@ -795,12 +796,13 @@ ULONG TlsCryptographSchannel::getContextRequirements()
|
|||||||
bool TlsCryptographSchannel::acquireCredentialsHandle()
|
bool TlsCryptographSchannel::acquireCredentialsHandle()
|
||||||
{
|
{
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
const auto &configuration = d->privateConfiguration();
|
Q_ASSERT(q);
|
||||||
|
const auto &configuration = q->sslConfiguration();
|
||||||
|
|
||||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||||
|
|
||||||
const bool isClient = d->tlsMode() == 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)) {
|
||||||
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
|
||||||
QSslSocket::tr("Invalid protocol chosen"));
|
QSslSocket::tr("Invalid protocol chosen"));
|
||||||
@ -820,7 +822,7 @@ bool TlsCryptographSchannel::acquireCredentialsHandle()
|
|||||||
// Check if user has specified a certificate chain but it could not be loaded.
|
// Check if user has specified a certificate chain but it could not be loaded.
|
||||||
// This happens if there was something wrong with the certificate chain or there was no private
|
// This happens if there was something wrong with the certificate chain or there was no private
|
||||||
// key.
|
// key.
|
||||||
if (!configuration.localCertificateChain.isEmpty() && !localCertificateStore)
|
if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
|
||||||
return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
|
return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
|
||||||
|
|
||||||
if (localCertificateStore != nullptr) {
|
if (localCertificateStore != nullptr) {
|
||||||
@ -859,7 +861,7 @@ bool TlsCryptographSchannel::acquireCredentialsHandle()
|
|||||||
TLS_PARAMETERS tlsParameters = {
|
TLS_PARAMETERS tlsParameters = {
|
||||||
0,
|
0,
|
||||||
nullptr,
|
nullptr,
|
||||||
toSchannelProtocolNegated(configuration.protocol), // what protocols to disable
|
toSchannelProtocolNegated(configuration.protocol()), // what protocols to disable
|
||||||
0,
|
0,
|
||||||
nullptr,
|
nullptr,
|
||||||
0
|
0
|
||||||
@ -960,8 +962,9 @@ void TlsCryptographSchannel::closeCertificateStores()
|
|||||||
|
|
||||||
bool TlsCryptographSchannel::createContext()
|
bool TlsCryptographSchannel::createContext()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(q);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
|
|
||||||
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
||||||
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
|
||||||
@ -989,8 +992,8 @@ bool TlsCryptographSchannel::createContext()
|
|||||||
SecBufferDesc alpnBufferDesc;
|
SecBufferDesc alpnBufferDesc;
|
||||||
bool useAlpn = false;
|
bool useAlpn = false;
|
||||||
#ifdef SUPPORTS_ALPN
|
#ifdef SUPPORTS_ALPN
|
||||||
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
|
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
|
||||||
QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
|
QByteArray alpnString = createAlpnString(configuration.allowedNextProtocols());
|
||||||
useAlpn = !alpnString.isEmpty();
|
useAlpn = !alpnString.isEmpty();
|
||||||
SecBuffer alpnBuffers[1];
|
SecBuffer alpnBuffers[1];
|
||||||
alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
|
alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
|
||||||
@ -1032,7 +1035,8 @@ bool TlsCryptographSchannel::createContext()
|
|||||||
bool TlsCryptographSchannel::acceptContext()
|
bool TlsCryptographSchannel::acceptContext()
|
||||||
{
|
{
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
auto &configuration = d->privateConfiguration();
|
Q_ASSERT(q);
|
||||||
|
const auto &configuration = q->sslConfiguration();
|
||||||
auto *plainSocket = d->plainTcpSocket();
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
|
|
||||||
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
Q_ASSERT(SecIsValidHandle(&credentialHandle));
|
||||||
@ -1052,9 +1056,9 @@ bool TlsCryptographSchannel::acceptContext()
|
|||||||
inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
|
inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
|
||||||
|
|
||||||
#ifdef SUPPORTS_ALPN
|
#ifdef SUPPORTS_ALPN
|
||||||
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
|
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
|
||||||
// The string must be alive when we call AcceptSecurityContext
|
// The string must be alive when we call AcceptSecurityContext
|
||||||
QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
|
QByteArray alpnString = createAlpnString(configuration.allowedNextProtocols());
|
||||||
if (!alpnString.isEmpty()) {
|
if (!alpnString.isEmpty()) {
|
||||||
inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
|
inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
|
||||||
} else
|
} else
|
||||||
@ -1269,7 +1273,7 @@ bool TlsCryptographSchannel::verifyHandshake()
|
|||||||
{
|
{
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
|
|
||||||
sslErrors.clear();
|
sslErrors.clear();
|
||||||
|
|
||||||
@ -1284,7 +1288,7 @@ bool TlsCryptographSchannel::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)) {
|
||||||
d->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;
|
||||||
@ -1303,7 +1307,8 @@ bool TlsCryptographSchannel::verifyHandshake()
|
|||||||
CHECK_STATUS(status);
|
CHECK_STATUS(status);
|
||||||
|
|
||||||
#ifdef SUPPORTS_ALPN
|
#ifdef SUPPORTS_ALPN
|
||||||
if (!configuration.nextAllowedProtocols.isEmpty() && supportsAlpn()) {
|
const auto allowedProtos = configuration.allowedNextProtocols();
|
||||||
|
if (!allowedProtos.isEmpty() && supportsAlpn()) {
|
||||||
SecPkgContext_ApplicationProtocol alpn;
|
SecPkgContext_ApplicationProtocol alpn;
|
||||||
status = QueryContextAttributes(&contextHandle,
|
status = QueryContextAttributes(&contextHandle,
|
||||||
SECPKG_ATTR_APPLICATION_PROTOCOL,
|
SECPKG_ATTR_APPLICATION_PROTOCOL,
|
||||||
@ -1312,16 +1317,16 @@ bool TlsCryptographSchannel::verifyHandshake()
|
|||||||
if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
|
if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
|
||||||
QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
|
QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
|
||||||
alpn.ProtocolIdSize);
|
alpn.ProtocolIdSize);
|
||||||
if (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
|
if (!allowedProtos.contains(negotiatedProto)) {
|
||||||
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
|
||||||
QSslSocket::tr("Unwanted protocol was negotiated"));
|
QSslSocket::tr("Unwanted protocol was negotiated"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
configuration.nextNegotiatedProtocol = negotiatedProto;
|
QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
|
||||||
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
|
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
|
||||||
} else {
|
} else {
|
||||||
configuration.nextNegotiatedProtocol = "";
|
QTlsBackend::setNegotiatedProtocol(d, {});
|
||||||
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationUnsupported;
|
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationUnsupported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // supports ALPN
|
#endif // supports ALPN
|
||||||
@ -1343,9 +1348,9 @@ bool TlsCryptographSchannel::verifyHandshake()
|
|||||||
// To work around this we don't request a certificate at all for QueryPeer.
|
// To work around this we don't request a certificate at all for QueryPeer.
|
||||||
// For servers AutoVerifyPeer is supposed to be treated the same as QueryPeer.
|
// For servers AutoVerifyPeer is supposed to be treated the same as QueryPeer.
|
||||||
// This means that servers using Schannel will only request client certificate for "VerifyPeer".
|
// This means that servers using Schannel will only request client certificate for "VerifyPeer".
|
||||||
if ((!isClient && configuration.peerVerifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
|
if ((!isClient && configuration.peerVerifyMode() == QSslSocket::PeerVerifyMode::VerifyPeer)
|
||||||
|| (isClient && configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::VerifyNone
|
|| (isClient && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::VerifyNone
|
||||||
&& configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::QueryPeer)) {
|
&& configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::QueryPeer)) {
|
||||||
if (status != SEC_E_OK) {
|
if (status != SEC_E_OK) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcSsl) << "Couldn't retrieve peer certificate, status:"
|
qCDebug(lcSsl) << "Couldn't retrieve peer certificate, status:"
|
||||||
@ -1909,13 +1914,13 @@ bool TlsCryptographSchannel::checkSslErrors()
|
|||||||
|
|
||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
const auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
auto *plainSocket = d->plainTcpSocket();
|
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
|
||||||
&& d->tlsMode() == QSslSocket::SslClientMode);
|
&& d->tlsMode() == QSslSocket::SslClientMode);
|
||||||
const bool doEmitSslError = !d->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
|
||||||
@ -1938,7 +1943,8 @@ 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);
|
Q_ASSERT(d);
|
||||||
const auto &configuration = d->privateConfiguration();
|
Q_ASSERT(q);
|
||||||
|
const auto &configuration = q->sslConfiguration();
|
||||||
|
|
||||||
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"";
|
||||||
@ -1952,22 +1958,22 @@ void TlsCryptographSchannel::initializeCertificateStores()
|
|||||||
return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
|
return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!configuration.localCertificateChain.isEmpty()) {
|
if (!configuration.localCertificateChain().isEmpty()) {
|
||||||
if (configuration.privateKey.isNull()) {
|
if (configuration.privateKey().isNull()) {
|
||||||
d->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;
|
||||||
}
|
}
|
||||||
if (localCertificateStore == nullptr) {
|
if (localCertificateStore == nullptr) {
|
||||||
localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain,
|
localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
|
||||||
configuration.privateKey);
|
configuration.privateKey());
|
||||||
if (localCertificateStore == nullptr)
|
if (localCertificateStore == nullptr)
|
||||||
qCWarning(lcSsl, "Failed to load certificate chain!");
|
qCWarning(lcSsl, "Failed to load certificate chain!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configuration.caCertificates.isEmpty() && !caCertificateStore) {
|
if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
|
||||||
caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates,
|
caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
|
||||||
{}); // No private key for the CA certs
|
{}); // No private key for the CA certs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1977,7 +1983,6 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
|
|||||||
Q_ASSERT(certContext);
|
Q_ASSERT(certContext);
|
||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
auto &configuration = d->privateConfiguration();
|
|
||||||
|
|
||||||
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
|
||||||
|
|
||||||
@ -2038,8 +2043,7 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
|
|||||||
: szOID_PKIX_KP_CLIENT_AUTH);
|
: szOID_PKIX_KP_CLIENT_AUTH);
|
||||||
parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
|
parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
|
||||||
|
|
||||||
configuration.peerCertificate.clear();
|
QTlsBackend::clearPeerCertificates(d);
|
||||||
configuration.peerCertificateChain.clear();
|
|
||||||
const CERT_CHAIN_CONTEXT *chainContext = nullptr;
|
const CERT_CHAIN_CONTEXT *chainContext = nullptr;
|
||||||
auto freeCertChain = qScopeGuard([&chainContext]() {
|
auto freeCertChain = qScopeGuard([&chainContext]() {
|
||||||
if (chainContext)
|
if (chainContext)
|
||||||
@ -2106,23 +2110,26 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DWORD verifyDepth = chain->cElement;
|
DWORD verifyDepth = chain->cElement;
|
||||||
if (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
|
if (q->peerVerifyDepth() > 0 && DWORD(q->peerVerifyDepth()) < verifyDepth)
|
||||||
verifyDepth = DWORD(configuration.peerVerifyDepth);
|
verifyDepth = DWORD(q->peerVerifyDepth());
|
||||||
|
|
||||||
|
const auto &caCertificates = q->sslConfiguration().caCertificates();
|
||||||
|
QList<QSslCertificate> peerCertificateChain;
|
||||||
for (DWORD i = 0; i < verifyDepth; i++) {
|
for (DWORD i = 0; i < verifyDepth; i++) {
|
||||||
CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
|
CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
|
||||||
QSslCertificate certificate = getCertificateFromChainElement(element);
|
QSslCertificate certificate = getCertificateFromChainElement(element);
|
||||||
const QList<QSslCertificateExtension> extensions = certificate.extensions();
|
const QList<QSslCertificateExtension> extensions = certificate.extensions();
|
||||||
|
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcSsl) << "issuer:" << certificate.issuerDisplayName()
|
qCDebug(lcTlsBackend) << "issuer:" << certificate.issuerDisplayName()
|
||||||
<< "\nsubject:" << certificate.subjectDisplayName()
|
<< "\nsubject:" << certificate.subjectDisplayName()
|
||||||
<< "\nQSslCertificate info:" << certificate
|
<< "\nQSslCertificate info:" << certificate
|
||||||
<< "\nextended error info:" << element->pwszExtendedErrorInfo
|
<< "\nextended error info:" << element->pwszExtendedErrorInfo
|
||||||
<< "\nerror status:" << element->TrustStatus.dwErrorStatus;
|
<< "\nerror status:" << element->TrustStatus.dwErrorStatus;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
configuration.peerCertificateChain.append(certificate);
|
peerCertificateChain.append(certificate);
|
||||||
|
QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
|
||||||
|
|
||||||
if (certificate.isBlacklisted()) {
|
if (certificate.isBlacklisted()) {
|
||||||
const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
|
const auto error = QSslError(QSslError::CertificateBlacklisted, certificate);
|
||||||
@ -2178,7 +2185,7 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
|
|||||||
}
|
}
|
||||||
if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
|
if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) {
|
||||||
// Override this error if we have the certificate inside our trusted CAs list.
|
// Override this error if we have the certificate inside our trusted CAs list.
|
||||||
const bool isTrustedRoot = configuration.caCertificates.contains(certificate);
|
const bool isTrustedRoot = caCertificates.contains(certificate);
|
||||||
if (!isTrustedRoot) {
|
if (!isTrustedRoot) {
|
||||||
auto error = QSslError(QSslError::CertificateUntrusted, certificate);
|
auto error = QSslError(QSslError::CertificateUntrusted, certificate);
|
||||||
sslErrors += error;
|
sslErrors += error;
|
||||||
@ -2257,25 +2264,26 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!configuration.peerCertificateChain.isEmpty())
|
if (!peerCertificateChain.isEmpty())
|
||||||
configuration.peerCertificate = configuration.peerCertificateChain.first();
|
QTlsBackend::storePeerCertificate(d, peerCertificateChain.first());
|
||||||
|
|
||||||
|
const auto &configuration = q->sslConfiguration(); // Probably, updated by QTlsBackend::storePeerCertificate etc.
|
||||||
// @Note: Somewhat copied from qsslsocket_mac.cpp
|
// @Note: Somewhat copied from qsslsocket_mac.cpp
|
||||||
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|
const bool doVerifyPeer = q->peerVerifyMode() == QSslSocket::VerifyPeer
|
||||||
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
|
|| (q->peerVerifyMode() == QSslSocket::AutoVerifyPeer
|
||||||
&& d->tlsMode() == 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 (d->tlsMode() == QSslSocket::SslClientMode) {
|
if (d->tlsMode() == QSslSocket::SslClientMode) {
|
||||||
const auto verificationPeerName = d->verificationName();
|
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.
|
||||||
const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
|
const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
|
||||||
sslErrors += error;
|
sslErrors += error;
|
||||||
emit q->peerVerifyError(error);
|
emit q->peerVerifyError(error);
|
||||||
if (q->state() != QAbstractSocket::ConnectedState)
|
if (q->state() != QAbstractSocket::ConnectedState)
|
||||||
|
@ -346,7 +346,7 @@ void TlsCryptographSecureTransport::continueHandshake()
|
|||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
d->setEncrypted(true);
|
d->setEncrypted(true);
|
||||||
#ifdef QSSLSOCKET_DEBU
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << d->plainTcpSocket() << "connection encrypted";
|
qCDebug(lcTlsBackend) << d->plainTcpSocket() << "connection encrypted";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -355,12 +355,12 @@ void TlsCryptographSecureTransport::continueHandshake()
|
|||||||
// a callback during handshake. We can only set our list of preferred protocols
|
// a callback during handshake. We can only set our list of preferred protocols
|
||||||
// (and send it during handshake) and then receive what our peer has sent to us.
|
// (and send it during handshake) and then receive what our peer has sent to us.
|
||||||
// And here we can finally try to find a match (if any).
|
// And here we can finally try to find a match (if any).
|
||||||
auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
|
if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
|
||||||
const auto &requestedProtocols = configuration.nextAllowedProtocols;
|
const auto &requestedProtocols = configuration.allowedNextProtocols();
|
||||||
if (const int requestedCount = requestedProtocols.size()) {
|
if (const int requestedCount = requestedProtocols.size()) {
|
||||||
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
|
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
|
||||||
configuration.nextNegotiatedProtocol.clear();
|
QTlsBackend::setNegotiatedProtocol(d, {});
|
||||||
|
|
||||||
QCFType<CFArrayRef> cfArray;
|
QCFType<CFArrayRef> cfArray;
|
||||||
const OSStatus result = SSLCopyALPNProtocols(context, &cfArray);
|
const OSStatus result = SSLCopyALPNProtocols(context, &cfArray);
|
||||||
@ -374,12 +374,12 @@ void TlsCryptographSecureTransport::continueHandshake()
|
|||||||
const auto requestedName = QString::fromLatin1(requestedProtocols[i]);
|
const auto requestedName = QString::fromLatin1(requestedProtocols[i]);
|
||||||
for (int j = 0; j < size; ++j) {
|
for (int j = 0; j < size; ++j) {
|
||||||
if (requestedName == peerProtocols[j]) {
|
if (requestedName == peerProtocols[j]) {
|
||||||
configuration.nextNegotiatedProtocol = requestedName.toLatin1();
|
QTlsBackend::setNegotiatedProtocol(d, requestedName.toLatin1());
|
||||||
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
|
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (configuration.nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNegotiated)
|
if (configuration.nextProtocolNegotiationStatus() == QSslConfiguration::NextProtocolNegotiationNegotiated)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -678,9 +678,9 @@ bool TlsCryptographSecureTransport::initSslContext()
|
|||||||
|
|
||||||
SSLSetConnection(context, this);
|
SSLSetConnection(context, this);
|
||||||
|
|
||||||
auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
if (mode == QSslSocket::SslServerMode
|
if (mode == QSslSocket::SslServerMode
|
||||||
&& !configuration.localCertificateChain.isEmpty()) {
|
&& !configuration.localCertificateChain().isEmpty()) {
|
||||||
QString errorDescription;
|
QString errorDescription;
|
||||||
QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
|
QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
|
||||||
if (!setSessionCertificate(errorDescription, errorCode)) {
|
if (!setSessionCertificate(errorDescription, errorCode)) {
|
||||||
@ -698,7 +698,7 @@ bool TlsCryptographSecureTransport::initSslContext()
|
|||||||
|
|
||||||
#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13_4, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
|
#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_13_4, __IPHONE_11_0, __TVOS_11_0, __WATCHOS_4_0)
|
||||||
if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
|
if (__builtin_available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)) {
|
||||||
const auto protocolNames = configuration.nextAllowedProtocols;
|
const auto protocolNames = configuration.allowedNextProtocols();
|
||||||
QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
|
QCFType<CFMutableArrayRef> cfNames(CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
|
||||||
if (cfNames) {
|
if (cfNames) {
|
||||||
for (const QByteArray &name : protocolNames) {
|
for (const QByteArray &name : protocolNames) {
|
||||||
@ -748,7 +748,7 @@ bool TlsCryptographSecureTransport::initSslContext()
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
} else {
|
} else {
|
||||||
if (configuration.peerVerifyMode != QSslSocket::VerifyNone) {
|
if (configuration.peerVerifyMode() != QSslSocket::VerifyNone) {
|
||||||
// kAlwaysAuthenticate - always fails even if we set break on client auth.
|
// kAlwaysAuthenticate - always fails even if we set break on client auth.
|
||||||
OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
|
OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
|
||||||
if (err == errSecSuccess) {
|
if (err == errSecSuccess) {
|
||||||
@ -769,9 +769,9 @@ bool TlsCryptographSecureTransport::initSslContext()
|
|||||||
SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
|
SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (configuration.ciphers.size() > 0) {
|
if (configuration.ciphers().size() > 0) {
|
||||||
QVector<SSLCipherSuite> cfCiphers;
|
QVector<SSLCipherSuite> cfCiphers;
|
||||||
for (const QSslCipher &cipher : configuration.ciphers) {
|
for (const QSslCipher &cipher : configuration.ciphers()) {
|
||||||
if (auto sslCipher = TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(cipher))
|
if (auto sslCipher = TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(cipher))
|
||||||
cfCiphers << sslCipher;
|
cfCiphers << sslCipher;
|
||||||
}
|
}
|
||||||
@ -798,7 +798,7 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
|
|||||||
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
|
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
|
||||||
|
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
const auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
|
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
auto *plainSocket = d->plainTcpSocket();
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
@ -806,12 +806,12 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
|
|||||||
|
|
||||||
QSslCertificate localCertificate;
|
QSslCertificate localCertificate;
|
||||||
|
|
||||||
if (!configuration.localCertificateChain.isEmpty())
|
if (!configuration.localCertificateChain().isEmpty())
|
||||||
localCertificate = configuration.localCertificateChain.at(0);
|
localCertificate = configuration.localCertificateChain().at(0);
|
||||||
|
|
||||||
if (!localCertificate.isNull()) {
|
if (!localCertificate.isNull()) {
|
||||||
// Require a private key as well.
|
// Require a private key as well.
|
||||||
if (configuration.privateKey.isNull()) {
|
if (configuration.privateKey().isNull()) {
|
||||||
errorCode = QAbstractSocket::SslInvalidUserDataError;
|
errorCode = QAbstractSocket::SslInvalidUserDataError;
|
||||||
errorDescription = QStringLiteral("Cannot provide a certificate with no key");
|
errorDescription = QStringLiteral("Cannot provide a certificate with no key");
|
||||||
return false;
|
return false;
|
||||||
@ -819,8 +819,8 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
|
|||||||
|
|
||||||
// import certificates and key
|
// import certificates and key
|
||||||
const QString passPhrase(QString::fromLatin1("foobar"));
|
const QString passPhrase(QString::fromLatin1("foobar"));
|
||||||
QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain,
|
QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain(),
|
||||||
configuration.privateKey, passPhrase).toCFData();
|
configuration.privateKey(), passPhrase).toCFData();
|
||||||
QCFType<CFStringRef> password = passPhrase.toCFString();
|
QCFType<CFStringRef> password = passPhrase.toCFString();
|
||||||
const void *keys[2] = { kSecImportExportPassphrase };
|
const void *keys[2] = { kSecImportExportPassphrase };
|
||||||
const void *values[2] = { password };
|
const void *values[2] = { password };
|
||||||
@ -904,14 +904,15 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
|
|||||||
bool TlsCryptographSecureTransport::setSessionProtocol()
|
bool TlsCryptographSecureTransport::setSessionProtocol()
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
|
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
|
||||||
|
Q_ASSERT(q);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
// SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
|
// SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
|
||||||
// Calling SSLSetProtocolVersionMax/Min with any of these two constants results
|
// Calling SSLSetProtocolVersionMax/Min with any of these two constants results
|
||||||
// in errInvalidParam and a failure to set the protocol version. This means
|
// in errInvalidParam and a failure to set the protocol version. This means
|
||||||
// no TLS 1.3 on macOS and iOS.
|
// no TLS 1.3 on macOS and iOS.
|
||||||
const auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
auto *plainSocket = d->plainTcpSocket();
|
auto *plainSocket = d->plainTcpSocket();
|
||||||
switch (configuration.protocol) {
|
switch (configuration.protocol()) {
|
||||||
case QSsl::TlsV1_3:
|
case QSsl::TlsV1_3:
|
||||||
case QSsl::TlsV1_3OrLater:
|
case QSsl::TlsV1_3OrLater:
|
||||||
qCWarning(lcTlsBackend) << plainSocket << "SecureTransport does not support TLS 1.3";
|
qCWarning(lcTlsBackend) << plainSocket << "SecureTransport does not support TLS 1.3";
|
||||||
@ -921,48 +922,48 @@ bool TlsCryptographSecureTransport::setSessionProtocol()
|
|||||||
|
|
||||||
OSStatus err = errSecSuccess;
|
OSStatus err = errSecSuccess;
|
||||||
|
|
||||||
if (configuration.protocol == QSsl::TlsV1_0) {
|
if (configuration.protocol() == QSsl::TlsV1_0) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.0";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.0";
|
||||||
#endif
|
#endif
|
||||||
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
||||||
if (err == errSecSuccess)
|
if (err == errSecSuccess)
|
||||||
err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
|
err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
|
||||||
} else if (configuration.protocol == QSsl::TlsV1_1) {
|
} else if (configuration.protocol() == QSsl::TlsV1_1) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1";
|
||||||
#endif
|
#endif
|
||||||
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
|
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
|
||||||
if (err == errSecSuccess)
|
if (err == errSecSuccess)
|
||||||
err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
|
err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
|
||||||
} else if (configuration.protocol == QSsl::TlsV1_2) {
|
} else if (configuration.protocol() == QSsl::TlsV1_2) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
|
||||||
#endif
|
#endif
|
||||||
err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
|
err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
|
||||||
if (err == errSecSuccess)
|
if (err == errSecSuccess)
|
||||||
err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
|
err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
|
||||||
} else if (configuration.protocol == QSsl::AnyProtocol) {
|
} else if (configuration.protocol() == QSsl::AnyProtocol) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : any";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : any";
|
||||||
#endif
|
#endif
|
||||||
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
||||||
} else if (configuration.protocol == QSsl::SecureProtocols) {
|
} else if (configuration.protocol() == QSsl::SecureProtocols) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
|
||||||
#endif
|
#endif
|
||||||
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
||||||
} else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
|
} else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
|
||||||
#endif
|
#endif
|
||||||
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
|
||||||
} else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
|
} else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
|
||||||
#endif
|
#endif
|
||||||
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
|
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
|
||||||
} else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
|
} else if (configuration.protocol() == QSsl::TlsV1_2OrLater) {
|
||||||
#ifdef QSSLSOCKET_DEBUG
|
#ifdef QSSLSOCKET_DEBUG
|
||||||
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
|
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
|
||||||
#endif
|
#endif
|
||||||
@ -979,9 +980,10 @@ bool TlsCryptographSecureTransport::setSessionProtocol()
|
|||||||
|
|
||||||
bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
|
bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(q);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
const auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
|
const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode();
|
||||||
return d->tlsMode() == QSslSocket::SslServerMode
|
return d->tlsMode() == QSslSocket::SslServerMode
|
||||||
&& (verifyMode == QSslSocket::QueryPeer
|
&& (verifyMode == QSslSocket::QueryPeer
|
||||||
|| verifyMode == QSslSocket::AutoVerifyPeer
|
|| verifyMode == QSslSocket::AutoVerifyPeer
|
||||||
@ -990,24 +992,24 @@ bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
|
|||||||
|
|
||||||
bool TlsCryptographSecureTransport::verifySessionProtocol() const
|
bool TlsCryptographSecureTransport::verifySessionProtocol() const
|
||||||
{
|
{
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(q);
|
||||||
|
|
||||||
const auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
bool protocolOk = false;
|
bool protocolOk = false;
|
||||||
if (configuration.protocol == QSsl::AnyProtocol)
|
if (configuration.protocol() == QSsl::AnyProtocol)
|
||||||
protocolOk = true;
|
protocolOk = true;
|
||||||
else if (configuration.protocol == QSsl::SecureProtocols)
|
else if (configuration.protocol() == QSsl::SecureProtocols)
|
||||||
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
|
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
|
||||||
else if (configuration.protocol == QSsl::TlsV1_0OrLater)
|
else if (configuration.protocol() == QSsl::TlsV1_0OrLater)
|
||||||
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
|
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
|
||||||
else if (configuration.protocol == QSsl::TlsV1_1OrLater)
|
else if (configuration.protocol() == QSsl::TlsV1_1OrLater)
|
||||||
protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
|
protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
|
||||||
else if (configuration.protocol == QSsl::TlsV1_2OrLater)
|
else if (configuration.protocol() == QSsl::TlsV1_2OrLater)
|
||||||
protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
|
protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
|
||||||
else if (configuration.protocol == QSsl::TlsV1_3OrLater)
|
else if (configuration.protocol() == QSsl::TlsV1_3OrLater)
|
||||||
protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
|
protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
|
||||||
else
|
else
|
||||||
protocolOk = (sessionProtocol() == configuration.protocol);
|
protocolOk = (sessionProtocol() == configuration.protocol());
|
||||||
|
|
||||||
return protocolOk;
|
return protocolOk;
|
||||||
}
|
}
|
||||||
@ -1017,9 +1019,8 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
|
|||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
|
|
||||||
auto &configuration = d->privateConfiguration();
|
|
||||||
const auto mode = d->tlsMode();
|
const auto mode = d->tlsMode();
|
||||||
const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
|
const QSslSocket::PeerVerifyMode verifyMode = q->peerVerifyMode();
|
||||||
const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
|
const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
|
||||||
|
|
||||||
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
|
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
|
||||||
@ -1060,21 +1061,22 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration.peerCertificate.clear();
|
QTlsBackend::clearPeerCertificates(d);
|
||||||
configuration.peerCertificateChain.clear();
|
|
||||||
|
|
||||||
|
QList<QSslCertificate> peerCertificateChain;
|
||||||
const CFIndex certCount = SecTrustGetCertificateCount(trust);
|
const CFIndex certCount = SecTrustGetCertificateCount(trust);
|
||||||
for (CFIndex i = 0; i < certCount; ++i) {
|
for (CFIndex i = 0; i < certCount; ++i) {
|
||||||
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
|
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
|
||||||
QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
|
QCFType<CFDataRef> derData = SecCertificateCopyData(cert);
|
||||||
configuration.peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
|
peerCertificateChain << QSslCertificate(QByteArray::fromCFData(derData), QSsl::Der);
|
||||||
}
|
}
|
||||||
|
QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
|
||||||
|
|
||||||
if (configuration.peerCertificateChain.size())
|
if (peerCertificateChain.size())
|
||||||
configuration.peerCertificate = configuration.peerCertificateChain.at(0);
|
QTlsBackend::storePeerCertificate(d, peerCertificateChain.at(0));
|
||||||
|
|
||||||
// Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
|
// Check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer):
|
||||||
for (const QSslCertificate &cert : qAsConst(configuration.peerCertificateChain)) {
|
for (const QSslCertificate &cert : qAsConst(peerCertificateChain)) {
|
||||||
if (QSslCertificatePrivate::isBlacklisted(cert) && !canIgnoreVerify) {
|
if (QSslCertificatePrivate::isBlacklisted(cert) && !canIgnoreVerify) {
|
||||||
const QSslError error(QSslError::CertificateBlacklisted, cert);
|
const QSslError error(QSslError::CertificateBlacklisted, cert);
|
||||||
errors << error;
|
errors << error;
|
||||||
@ -1090,15 +1092,16 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
|
|||||||
// 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()) {
|
const auto &peerCertificate = q->peerCertificate();
|
||||||
|
if (!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
|
||||||
const QString verificationPeerName = d->verificationName();
|
const QString verificationPeerName = d->verificationName();
|
||||||
if (mode == QSslSocket::SslClientMode) {
|
if (mode == QSslSocket::SslClientMode) {
|
||||||
const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
|
const QString peerName(verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
|
||||||
if (!isMatchingHostname(configuration.peerCertificate, peerName) && !canIgnoreVerify) {
|
if (!isMatchingHostname(peerCertificate, peerName) && !canIgnoreVerify) {
|
||||||
// No matches in common names or alternate names.
|
// No matches in common names or alternate names.
|
||||||
const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
|
const QSslError error(QSslError::HostNameMismatch, peerCertificate);
|
||||||
errors << error;
|
errors << error;
|
||||||
emit q->peerVerifyError(error);
|
emit q->peerVerifyError(error);
|
||||||
if (q->state() != QAbstractSocket::ConnectedState)
|
if (q->state() != QAbstractSocket::ConnectedState)
|
||||||
@ -1119,7 +1122,8 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
|
|||||||
|
|
||||||
// verify certificate chain
|
// verify certificate chain
|
||||||
QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
|
QCFType<CFMutableArrayRef> certArray = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
|
||||||
for (const QSslCertificate &cert : qAsConst(configuration.caCertificates)) {
|
const auto &caCertificates = q->sslConfiguration().caCertificates();
|
||||||
|
for (const QSslCertificate &cert : caCertificates) {
|
||||||
QCFType<CFDataRef> certData = cert.toDer().toCFData();
|
QCFType<CFDataRef> certData = cert.toDer().toCFData();
|
||||||
if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
|
if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
|
||||||
CFArrayAppendValue(certArray, secRef);
|
CFArrayAppendValue(certArray, secRef);
|
||||||
@ -1165,7 +1169,7 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (!canIgnoreVerify) {
|
if (!canIgnoreVerify) {
|
||||||
const QSslError error(QSslError::CertificateUntrusted, configuration.peerCertificate);
|
const QSslError error(QSslError::CertificateUntrusted, peerCertificate);
|
||||||
errors << error;
|
errors << error;
|
||||||
emit q->peerVerifyError(error);
|
emit q->peerVerifyError(error);
|
||||||
}
|
}
|
||||||
@ -1199,9 +1203,9 @@ bool TlsCryptographSecureTransport::checkSslErrors()
|
|||||||
|
|
||||||
emit q->sslErrors(sslErrors);
|
emit q->sslErrors(sslErrors);
|
||||||
const auto mode = d->tlsMode();
|
const auto mode = d->tlsMode();
|
||||||
const auto &configuration = d->privateConfiguration();
|
const auto &configuration = q->sslConfiguration();
|
||||||
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);
|
&& mode == QSslSocket::SslClientMode);
|
||||||
const bool doEmitSslError = !d->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
|
||||||
|
@ -701,6 +701,92 @@ void QTlsBackend::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
|
|||||||
QSslSocketPrivate::setDefaultCaCertificates(certs);
|
QSslSocketPrivate::setDefaultCaCertificates(certs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QTlsBackend::rootLoadingOnDemandAllowed(const QSslConfiguration &configuration)
|
||||||
|
{
|
||||||
|
return configuration.d->allowRootCertOnDemandLoading;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::storePeerCertificate(QSslConfiguration &configuration,
|
||||||
|
const QSslCertificate &peerCert)
|
||||||
|
{
|
||||||
|
configuration.d->peerCertificate = peerCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::storePeerCertificateChain(QSslConfiguration &configuration,
|
||||||
|
const QList<QSslCertificate> &peerChain)
|
||||||
|
{
|
||||||
|
configuration.d->peerCertificateChain = peerChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::clearPeerCertificates(QSslConfiguration &configuration)
|
||||||
|
{
|
||||||
|
configuration.d->peerCertificate.clear();
|
||||||
|
configuration.d->peerCertificateChain.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::clearPeerCertificates(QSslSocketPrivate *d)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.peerCertificate.clear();
|
||||||
|
d->configuration.peerCertificateChain.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::setPeerSessionShared(QSslSocketPrivate *d, bool shared)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.peerSessionShared = shared;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.sslSession = asn1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::setSessionLifetimeHint(QSslSocketPrivate *d, int hint)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.sslSessionTicketLifeTimeHint = hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.nextProtocolNegotiationStatus = st;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.nextNegotiatedProtocol = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.peerCertificate = peerCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::storePeerCertificateChain(QSslSocketPrivate *d,
|
||||||
|
const QList<QSslCertificate> &peerChain)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.peerCertificateChain = peerChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
if (!d->configuration.caCertificates.contains(rootCert))
|
||||||
|
d->configuration.caCertificates += rootCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTlsBackend::setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key)
|
||||||
|
{
|
||||||
|
Q_ASSERT(d);
|
||||||
|
d->configuration.ephemeralServerKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // QT_CONFIG(ssl)
|
#endif // QT_CONFIG(ssl)
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -405,6 +405,29 @@ public:
|
|||||||
static void resetDefaultEllipticCurves();
|
static void resetDefaultEllipticCurves();
|
||||||
|
|
||||||
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
|
||||||
|
|
||||||
|
// Many thanks to people who designed QSslConfiguration with hidden
|
||||||
|
// data-members, that sneakily set by some 'friend' classes, having
|
||||||
|
// some twisted logic.
|
||||||
|
static bool rootLoadingOnDemandAllowed(const QSslConfiguration &configuration);
|
||||||
|
static void storePeerCertificate(QSslConfiguration &configuration, const QSslCertificate &peerCert);
|
||||||
|
static void storePeerCertificateChain(QSslConfiguration &configuration,
|
||||||
|
const QList<QSslCertificate> &peerCertificateChain);
|
||||||
|
static void clearPeerCertificates(QSslConfiguration &configuration);
|
||||||
|
// And those are even worse, this is where we don't have the original configuration,
|
||||||
|
// and can have only a copy. So instead we go to d->privateConfiguration.someMember:
|
||||||
|
static void clearPeerCertificates(QSslSocketPrivate *d);
|
||||||
|
static void setPeerSessionShared(QSslSocketPrivate *d, bool shared);
|
||||||
|
static void setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1);
|
||||||
|
static void setSessionLifetimeHint(QSslSocketPrivate *d, int hint);
|
||||||
|
using AlpnNegotiationStatus = QSslConfiguration::NextProtocolNegotiationStatus;
|
||||||
|
static void setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st);
|
||||||
|
static void setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol);
|
||||||
|
static void storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert);
|
||||||
|
static void storePeerCertificateChain(QSslSocketPrivate *d, const QList<QSslCertificate> &peerChain);
|
||||||
|
static void addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert);
|
||||||
|
// The next one - is a "very important" feature! Kidding ...
|
||||||
|
static void setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key);
|
||||||
#endif // QT_CONFIG(ssl)
|
#endif // QT_CONFIG(ssl)
|
||||||
|
|
||||||
Q_DISABLE_COPY_MOVE(QTlsBackend)
|
Q_DISABLE_COPY_MOVE(QTlsBackend)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user