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
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>
(cherry picked from commit 31cc0df7607a4d5887812c304aac0001c2cd7705)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Timur Pocheptsov 2021-03-12 12:12:59 +01:00 committed by Qt Cherry-pick Bot
parent 63a0d263cf
commit b4f3c5d646
12 changed files with 334 additions and 249 deletions

View File

@ -65,37 +65,12 @@ void QDtlsBasePrivate::clearDtlsError()
QSslConfiguration QDtlsBasePrivate::configuration() const
{
auto copyPrivate = new QSslConfigurationPrivate(dtlsConfiguration);
copyPrivate->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
QSslConfiguration copy(copyPrivate);
copyPrivate->sessionCipher = sessionCipher;
copyPrivate->sessionProtocol = sessionProtocol;
return copy;
return dtlsConfiguration;
}
void QDtlsBasePrivate::setConfiguration(const QSslConfiguration &configuration)
{
dtlsConfiguration.localCertificateChain = configuration.localCertificateChain();
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();
dtlsConfiguration = configuration;
clearDtlsError();
}

View File

@ -55,7 +55,7 @@
QT_REQUIRE_CONFIG(dtls);
#include "qsslconfiguration_p.h"
#include "qsslconfiguration.h"
#include "qtlsbackend_p.h"
#include "qsslcipher.h"
#include "qsslsocket.h"
@ -96,7 +96,7 @@ public:
QDtlsError errorCode = QDtlsError::NoError;
QString errorDescription;
QSslConfigurationPrivate dtlsConfiguration;
QSslConfiguration dtlsConfiguration;
QSslSocket::SslMode mode = QSslSocket::SslClientMode;
QSslCipher sessionCipher;
QSsl::SslProtocol sessionProtocol = QSsl::UnknownProtocol;

View File

@ -664,20 +664,15 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
return false;
}
if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol)) {
if (!QDtlsBasePrivate::isDtlsProtocol(dtlsBase->dtlsConfiguration.protocol())) {
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
QDtls::tr("Invalid protocol version, DTLS protocol expected"));
return false;
}
// Create a deep copy of our configuration
auto configurationCopy = new QSslConfigurationPrivate(dtlsBase->dtlsConfiguration);
configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
// DTLSTODO: check we do not set something DTLS-incompatible there ...
TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode,
configurationCopy,
dtlsBase->dtlsConfiguration.allowRootCertOnDemandLoading));
const bool rootsOnDemand = QTlsBackend::rootLoadingOnDemandAllowed(dtlsBase->dtlsConfiguration);
TlsContext newContext(QSslContext::sharedFromConfiguration(dtlsBase->mode, dtlsBase->dtlsConfiguration,
rootsOnDemand));
if (newContext->error() != QSslError::NoError) {
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError, newContext->errorString());
@ -695,14 +690,14 @@ bool DtlsState::initCtxAndConnection(QDtlsBasePrivate *dtlsBase)
QTlsBackendOpenSSL::s_indexForSSLExtraData,
this);
if (set != 1 && configurationCopy->peerVerifyMode != QSslSocket::VerifyNone) {
if (set != 1 && dtlsBase->dtlsConfiguration.peerVerifyMode() != QSslSocket::VerifyNone) {
dtlsBase->setDtlsError(QDtlsError::TlsInitializationError,
msgFunctionFailed("SSL_set_ex_data"));
return false;
}
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_psk_server_callback(newConnection.data(), dtlscallbacks::q_PSK_server_callback);
} else {
@ -936,7 +931,7 @@ bool QDtlsPrivateOpenSSL::startHandshake(QUdpSocket *socket, const QByteArray &d
if (!dtls.init(this, socket, remoteAddress, remotePort, dgram))
return false;
if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieEnabled) {
if (mode == QSslSocket::SslServerMode && dtlsConfiguration.dtlsCookieVerificationEnabled()) {
dtls.secret = secret;
dtls.hashAlgorithm = hashAlgorithm;
// 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();
fetchNegotiatedParameters();
const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode == QSslSocket::VerifyPeer
|| (dtlsConfiguration.peerVerifyMode == QSslSocket::AutoVerifyPeer
const bool doVerifyPeer = dtlsConfiguration.peerVerifyMode() == QSslSocket::VerifyPeer
|| (dtlsConfiguration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
&& mode == QSslSocket::SslClientMode);
if (!doVerifyPeer || verifyPeer() || tlsErrorsWereIgnored()) {
@ -1308,7 +1303,7 @@ unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned c
{
QSslPreSharedKeyAuthenticator authenticator;
// Fill in some read-only fields (for the user)
QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint,
QTlsBackend::setupServerPskAuth(&authenticator, identity, dtlsConfiguration.preSharedKeyIdentityHint(),
max_psk_len);
pskAuthenticator.swap(authenticator);
}
@ -1331,17 +1326,18 @@ unsigned QDtlsPrivateOpenSSL::pskServerCallback(const char *identity, unsigned c
bool QDtlsPrivateOpenSSL::verifyPeer()
{
// DTLSTODO: Windows-specific code for CA fetcher is not here yet.
QList<QSslError> errors;
// Check the whole chain for blacklisting (including root, as we check for
// subjectInfo and issuer)
for (const QSslCertificate &cert : qAsConst(dtlsConfiguration.peerCertificateChain)) {
const auto &peerCertificateChain = dtlsConfiguration.peerCertificateChain();
for (const QSslCertificate &cert : peerCertificateChain) {
if (QSslCertificatePrivate::isBlacklisted(cert))
errors << QSslError(QSslError::CertificateBlacklisted, cert);
}
if (dtlsConfiguration.peerCertificate.isNull()) {
const auto peerCertificate = dtlsConfiguration.peerCertificate();
if (peerCertificate.isNull()) {
errors << QSslError(QSslError::NoPeerCertificate);
} else if (mode == QSslSocket::SslClientMode) {
// Check the peer certificate itself. First try the subject's common name
@ -1358,15 +1354,15 @@ bool QDtlsPrivateOpenSSL::verifyPeer()
name = dtls.udpSocket->peerName();
}
if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(dtlsConfiguration.peerCertificate, name))
errors << QSslError(QSslError::HostNameMismatch, dtlsConfiguration.peerCertificate);
if (!QTlsPrivate::TlsCryptograph::isMatchingHostname(peerCertificate, name))
errors << QSslError(QSslError::HostNameMismatch, peerCertificate);
}
// Translate errors from the error list into QSslErrors
using CertClass = QTlsPrivate::X509CertificateOpenSSL;
errors.reserve(errors.size() + opensslErrors.size());
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);
}
@ -1382,13 +1378,17 @@ void QDtlsPrivateOpenSSL::storePeerCertificates()
// peer certificate and the chain may be empty if the peer didn't present
// any certificate.
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);
if (dtlsConfiguration.peerCertificateChain.isEmpty()) {
auto peerCertificateChain = dtlsConfiguration.peerCertificateChain();
if (peerCertificateChain.isEmpty()) {
auto stack = q_SSL_get_peer_cert_chain(dtls.tlsConnection.data());
dtlsConfiguration.peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack);
if (!dtlsConfiguration.peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
dtlsConfiguration.peerCertificateChain.prepend(dtlsConfiguration.peerCertificate);
peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(stack);
if (!peerCertificate.isNull() && mode == QSslSocket::SslServerMode)
peerCertificateChain.prepend(peerCertificate);
QTlsBackend::storePeerCertificateChain(dtlsConfiguration, peerCertificateChain);
}
}
@ -1441,8 +1441,7 @@ void QDtlsPrivateOpenSSL::resetDtls()
connectionEncrypted = false;
tlsErrors.clear();
tlsErrorsToIgnore.clear();
dtlsConfiguration.peerCertificate.clear();
dtlsConfiguration.peerCertificateChain.clear();
QTlsBackend::clearPeerCertificates(dtlsConfiguration);
connectionWasShutdown = false;
handshakeState = QDtls::HandshakeNotStarted;
sessionCipher = {};

View File

@ -72,11 +72,6 @@ class QSslKey;
class QSslEllipticCurve;
class QSslDiffieHellmanParameters;
namespace dtlsopenssl
{
class DtlsState;
}
class QSslConfigurationPrivate;
class Q_NETWORK_EXPORT QSslConfiguration
{
@ -202,8 +197,7 @@ private:
friend class QSslSocket;
friend class QSslConfigurationPrivate;
friend class QSslContext;
friend class QDtlsBasePrivate;
friend class dtlsopenssl::DtlsState;
friend class QTlsBackend;
QSslConfiguration(QSslConfigurationPrivate *dd);
QSharedDataPointer<QSslConfigurationPrivate> d;
};

View File

@ -79,7 +79,7 @@
QT_BEGIN_NAMESPACE
class Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate: public QSharedData
class QSslConfigurationPrivate: public QSharedData
{
public:
QSslConfigurationPrivate()
@ -114,7 +114,7 @@ public:
bool allowRootCertOnDemandLoading;
bool peerSessionShared;
static bool peerSessionWasShared(const QSslConfiguration &configuration);
Q_AUTOTEST_EXPORT static bool peerSessionWasShared(const QSslConfiguration &configuration);
QSsl::SslOptions sslOptions;

View File

@ -3120,14 +3120,6 @@ QSslSocket::SslMode QSslSocketPrivate::tlsMode() const
return mode;
}
/*!
\internal
*/
QSslConfigurationPrivate &QSslSocketPrivate::privateConfiguration()
{
return configuration;
}
/*!
\internal
*/

View File

@ -172,7 +172,6 @@ public:
// Needed by TlsCryptograph:
Q_NETWORK_PRIVATE_EXPORT QSslSocket::SslMode tlsMode() const;
Q_NETWORK_PRIVATE_EXPORT QSslConfigurationPrivate &privateConfiguration();
Q_NETWORK_PRIVATE_EXPORT bool isRootsOnDemandAllowed() const;
Q_NETWORK_PRIVATE_EXPORT QString verificationName() const;
Q_NETWORK_PRIVATE_EXPORT QString tlsHostName() const;

View File

@ -561,7 +561,6 @@ bool TlsCryptographOpenSSL::startHandshake()
return false;
const auto mode = d->tlsMode();
auto &configuration = d->privateConfiguration();
pendingFatalAlert = false;
errorsReportedFromCallback = false;
@ -582,10 +581,14 @@ bool TlsCryptographOpenSSL::startHandshake()
if (!lastErrors.isEmpty() || errorsReportedFromCallback)
storePeerCertificates();
// storePeerCertificate() if called above - would update the
// configuration with peer's certificates.
auto configuration = q->sslConfiguration();
if (!errorsReportedFromCallback) {
const auto &peerCertificateChain = configuration.peerCertificateChain();
for (const auto &currentError : qAsConst(lastErrors)) {
emit q->peerVerifyError(QTlsPrivate::X509CertificateOpenSSL::openSSLErrorToQSslError(currentError.code,
configuration.peerCertificateChain.value(currentError.depth)));
peerCertificateChain.value(currentError.depth)));
if (q->state() != QAbstractSocket::ConnectedState)
break;
}
@ -628,8 +631,11 @@ bool TlsCryptographOpenSSL::startHandshake()
// Start translating errors.
QList<QSslError> errors;
// check the whole chain for blacklisting (including root, as we check for subjectInfo and issuer)
for (const QSslCertificate &cert : qAsConst(configuration.peerCertificateChain)) {
// Note, the storePeerCerificates() probably updated the configuration at this point.
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)) {
QSslError error(QSslError::CertificateBlacklisted, cert);
errors << error;
@ -639,14 +645,14 @@ bool TlsCryptographOpenSSL::startHandshake()
}
}
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
&& mode == QSslSocket::SslClientMode);
#if QT_CONFIG(ocsp)
// For now it's always QSslSocket::SslClientMode - initSslContext() will bail out early,
// 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 (ocspErrors.isEmpty()) {
{
@ -670,16 +676,16 @@ bool TlsCryptographOpenSSL::startHandshake()
// Check the peer certificate itself. First try the subject's common name
// (CN) as a wildcard, then try all alternate subject name DNS entries the
// same way.
if (!configuration.peerCertificate.isNull()) {
if (!configuration.peerCertificate().isNull()) {
// but only if we're a client connecting to a server
// if we're the server, don't check CN
const auto verificationPeerName = d->verificationName();
if (mode == QSslSocket::SslClientMode) {
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.
QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
errors << error;
emit q->peerVerifyError(error);
if (q->state() != QAbstractSocket::ConnectedState)
@ -701,7 +707,7 @@ bool TlsCryptographOpenSSL::startHandshake()
// Translate errors from the error list into QSslErrors.
errors.reserve(errors.size() + errorList.size());
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()) {
sslErrors = errors;
@ -763,7 +769,6 @@ void TlsCryptographOpenSSL::continueHandshake()
auto *plainSocket = d->plainTcpSocket();
Q_ASSERT(plainSocket);
auto &configuration = d->privateConfiguration();
const auto mode = d->tlsMode();
// if we have a max read buffer size, reset the plain socket's to match
@ -771,7 +776,7 @@ void TlsCryptographOpenSSL::continueHandshake()
plainSocket->setReadBufferSize(maxSize);
if (q_SSL_session_reused(ssl))
configuration.peerSessionShared = true;
QTlsBackend::setPeerSessionShared(d, true);
#ifdef QT_DECRYPT_SSL_TRAFFIC
if (q_SSL_get_session(ssl)) {
@ -804,26 +809,29 @@ void TlsCryptographOpenSSL::continueHandshake()
}
#endif // QT_DECRYPT_SSL_TRAFFIC
const auto &configuration = q->sslConfiguration();
// Cache this SSL session inside the QSslContext
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionSharing)) {
if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionSharing))) {
if (!sslContextPointer->cacheSession(ssl)) {
sslContextPointer.clear(); // we could not cache the session
} else {
// Cache the session for permanent usage as well
if (!(configuration.sslOptions & QSsl::SslOptionDisableSessionPersistence)) {
if (!(configuration.testSslOption(QSsl::SslOptionDisableSessionPersistence))) {
if (!sslContextPointer->sessionASN1().isEmpty())
configuration.sslSession = sslContextPointer->sessionASN1();
configuration.sslSessionTicketLifeTimeHint = sslContextPointer->sessionTicketLifeTimeHint();
QTlsBackend::setSessionAsn1(d, sslContextPointer->sessionASN1());
QTlsBackend::setSessionLifetimeHint(d, sslContextPointer->sessionTicketLifeTimeHint());
}
}
}
#if !defined(OPENSSL_NO_NEXTPROTONEG)
configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
QTlsBackend::setAlpnStatus(d, sslContextPointer->npnContext().status);
if (sslContextPointer->npnContext().status == QSslConfiguration::NextProtocolNegotiationUnsupported) {
// 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 {
const unsigned char *proto = nullptr;
unsigned int proto_len = 0;
@ -831,7 +839,7 @@ void TlsCryptographOpenSSL::continueHandshake()
q_SSL_get0_alpn_selected(ssl, &proto, &proto_len);
if (proto_len && mode == QSslSocket::SslClientMode) {
// 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 ...
@ -839,16 +847,16 @@ void TlsCryptographOpenSSL::continueHandshake()
}
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
configuration.nextNegotiatedProtocol.clear();
QTlsBackend::setNegotiatedProtocol(d,{});
}
#endif // !defined(OPENSSL_NO_NEXTPROTONEG)
if (mode == QSslSocket::SslClientMode) {
EVP_PKEY *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);
@ -1176,12 +1184,11 @@ bool TlsCryptographOpenSSL::checkSslErrors()
emit q->sslErrors(sslErrors);
auto &configuration = d->privateConfiguration();
const auto vfyMode = q->peerVerifyMode();
const auto mode = d->tlsMode();
bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
&& mode == QSslSocket::SslClientMode);
bool doVerifyPeer = vfyMode == QSslSocket::VerifyPeer || (vfyMode == QSslSocket::AutoVerifyPeer
&& mode == QSslSocket::SslClientMode);
bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
// check whether we need to emit an SSL handshake error
if (doVerifyPeer && doEmitSslError) {
@ -1205,7 +1212,9 @@ int TlsCryptographOpenSSL::handleNewSessionTicket(SSL *connection)
// 0 would tell OpenSSL to deref (but they still have it in the
// internal cache).
Q_ASSERT(connection);
Q_ASSERT(q);
Q_ASSERT(d);
if (q->sslConfiguration().testSslOption(QSsl::SslOptionDisableSessionPersistence)) {
// We silently ignore, do nothing, remove from cache.
@ -1245,9 +1254,8 @@ int TlsCryptographOpenSSL::handleNewSessionTicket(SSL *connection)
return 0;
}
auto &configuration = d->privateConfiguration();
configuration.sslSession = sessionTicket;
configuration.sslSessionTicketLifeTimeHint = int(q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
QTlsBackend::setSessionAsn1(d, sessionTicket);
QTlsBackend::setSessionLifetimeHint(d, q_SSL_SESSION_get_ticket_lifetime_hint(currentSession));
emit q->newSessionTicketReceived();
return 0;
@ -1345,17 +1353,11 @@ bool TlsCryptographOpenSSL::initSslContext()
Q_ASSERT(d);
// If no external context was set (e.g. by QHttpNetworkConnection) we will
// create a default context
auto &configuration = d->privateConfiguration();
// create a new one.
const auto mode = d->tlsMode();
if (!sslContextPointer) {
// create a deep copy of our configuration
QSslConfigurationPrivate *configurationCopy = new QSslConfigurationPrivate(configuration);
configurationCopy->ref.storeRelaxed(0); // the QSslConfiguration constructor refs up
sslContextPointer = QSslContext::sharedFromPrivateConfiguration(mode, configurationCopy,
d->isRootsOnDemandAllowed());
}
const auto configuration = q->sslConfiguration();
if (!sslContextPointer)
sslContextPointer = QSslContext::sharedFromConfiguration(mode, configuration, d->isRootsOnDemandAllowed());
if (sslContextPointer->error() != QSslError::NoError) {
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError, sslContextPointer->errorString());
@ -1370,7 +1372,7 @@ bool TlsCryptographOpenSSL::initSslContext()
return false;
}
if (configuration.protocol != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
if (configuration.protocol() != QSsl::UnknownProtocol && mode == QSslSocket::SslClientMode) {
const auto verificationPeerName = d->verificationName();
// Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
@ -1380,7 +1382,7 @@ bool TlsCryptographOpenSSL::initSslContext()
// only send the SNI header if the URL is valid and not an IP
if (!ace.isEmpty()
&& !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
// https://tools.ietf.org/html/rfc6066#section-3
if (ace.endsWith('.'))
@ -1434,7 +1436,7 @@ bool TlsCryptographOpenSSL::initSslContext()
#endif // OPENSSL_NO_PSK
#if QT_CONFIG(ocsp)
if (configuration.ocspStaplingEnabled) {
if (configuration.ocspStaplingEnabled()) {
if (mode == QSslSocket::SslServerMode) {
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
QSslSocket::tr("Server-side QSslSocket does not support OCSP stapling"));
@ -1448,8 +1450,9 @@ bool TlsCryptographOpenSSL::initSslContext()
}
ocspResponseDer.clear();
auto responsePos = configuration.backendConfig.find("Qt-OCSP-response");
if (responsePos != configuration.backendConfig.end()) {
const auto backendConfig = configuration.backendConfiguration();
auto responsePos = backendConfig.find("Qt-OCSP-response");
if (responsePos != backendConfig.end()) {
// 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
// by tst_QOcsp.
@ -1492,18 +1495,22 @@ void TlsCryptographOpenSSL::destroySslContext()
void TlsCryptographOpenSSL::storePeerCertificates()
{
Q_ASSERT(d);
auto &configuration = d->privateConfiguration();
// Store the peer certificate and chain. For clients, the peer certificate
// 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
// any certificate.
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);
if (configuration.peerCertificateChain.isEmpty()) {
configuration.peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(q_SSL_get_peer_cert_chain(ssl));
if (!configuration.peerCertificate.isNull() && d->tlsMode() == QSslSocket::SslServerMode)
configuration.peerCertificateChain.prepend(configuration.peerCertificate);
auto peerCertificateChain = q->peerCertificateChain();
if (peerCertificateChain.isEmpty()) {
peerCertificateChain = QTlsPrivate::X509CertificateOpenSSL::stackOfX509ToQSslCertificates(q_SSL_get_peer_cert_chain(ssl));
if (!peerCertificate.isNull() && d->tlsMode() == QSslSocket::SslServerMode)
peerCertificateChain.prepend(peerCertificate);
QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
}
}
@ -1514,9 +1521,9 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
Q_ASSERT(ssl);
Q_ASSERT(d);
auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
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([] {
QTlsBackendOpenSSL::logAndClearErrorQueue();
@ -1606,10 +1613,10 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
// issuer's public key.
ocspResponses.push_back(QOcspResponse());
QOcspResponsePrivate *dResponse = ocspResponses.back().d.data();
dResponse->subjectCert = configuration.peerCertificate;
dResponse->subjectCert = configuration.peerCertificate();
bool matchFound = false;
if (configuration.peerCertificate.isSelfSigned()) {
dResponse->signerCert = configuration.peerCertificate;
if (dResponse->subjectCert.isSelfSigned()) {
dResponse->signerCert = configuration.peerCertificate();
matchFound = qt_OCSP_certificate_match(singleResponse, peerX509, peerX509);
} else {
const STACK_OF(X509) *certs = q_SSL_get_peer_cert_chain(ssl);
@ -1636,7 +1643,7 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
if (!matchFound) {
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:
@ -1664,7 +1671,7 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
// next < this ? -> NEXT_BEFORE_THIS
// OK.
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:
switch (certStatus) {
@ -1675,11 +1682,11 @@ bool TlsCryptographOpenSSL::checkOcspStatus()
case V_OCSP_CERTSTATUS_REVOKED:
dResponse->certificateStatus = QOcspCertificateStatus::Revoked;
dResponse->revocationReason = qt_OCSP_revocation_reason(reason);
ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate});
ocspErrors.push_back({QSslError::CertificateRevoked, configuration.peerCertificate()});
break;
case V_OCSP_CERTSTATUS_UNKNOWN:
dResponse->certificateStatus = QOcspCertificateStatus::Unknown;
ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate});
ocspErrors.push_back({QSslError::OcspStatusUnknown, configuration.peerCertificate()});
}
return !ocspErrors.size();
@ -1723,7 +1730,7 @@ unsigned TlsCryptographOpenSSL::pskServerTlsCallback(const char *identity, unsig
QSslPreSharedKeyAuthenticator authenticator;
// 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);
emit q->preSharedKeyAuthenticationRequired(&authenticator);
@ -1748,7 +1755,7 @@ void TlsCryptographOpenSSL::fetchCaRootForCert(const QSslCertificate &cert)
//so the request is done in a worker thread.
QList<QSslCertificate> customRoots;
if (fetchAuthorityInformation)
customRoots = d->privateConfiguration().caCertificates;
customRoots = q->sslConfiguration().caCertificates();
//Remember we are fetching and what we are fetching:
caToFetch = cert;
@ -1772,12 +1779,11 @@ void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate t
Q_ASSERT(d);
Q_ASSERT(q);
auto &configuration = d->privateConfiguration();
//Done, fetched already:
caToFetch = QSslCertificate{};
if (fetchAuthorityInformation) {
if (!configuration.caCertificates.contains(trustedRoot))
if (!q->sslConfiguration().caCertificates().contains(trustedRoot))
trustedRoot = QSslCertificate{};
fetchAuthorityInformation = false;
}
@ -1790,8 +1796,7 @@ void TlsCryptographOpenSSL::caRootLoaded(QSslCertificate cert, QSslCertificate t
QSslConfiguration::setDefaultConfiguration(defaultConfig);
}
//Add the new root cert to this socket for future connections
if (!configuration.caCertificates.contains(trustedRoot))
configuration.caCertificates += trustedRoot;
QTlsBackend::addTustedRoot(d, trustedRoot);
//Remove the broken chain ssl errors (as chain is verified by windows)
for (int i=sslErrors.count() - 1; i >= 0; --i) {
if (sslErrors.at(i).certificate() == cert) {

View File

@ -764,6 +764,7 @@ QString TlsCryptographSchannel::targetName() const
ULONG TlsCryptographSchannel::getContextRequirements()
{
Q_ASSERT(d);
Q_ASSERT(q);
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
ULONG req = 0;
@ -777,7 +778,7 @@ ULONG TlsCryptographSchannel::getContextRequirements()
if (isClient) {
req |= ISC_REQ_MANUAL_CRED_VALIDATION; // Manually validate certificate
} else {
switch (d->privateConfiguration().peerVerifyMode) {
switch (q->peerVerifyMode()) {
case QSslSocket::PeerVerifyMode::VerifyNone:
// There doesn't seem to be a way to ask for an optional client cert :-(
case QSslSocket::PeerVerifyMode::AutoVerifyPeer:
@ -795,12 +796,13 @@ ULONG TlsCryptographSchannel::getContextRequirements()
bool TlsCryptographSchannel::acquireCredentialsHandle()
{
Q_ASSERT(d);
const auto &configuration = d->privateConfiguration();
Q_ASSERT(q);
const auto &configuration = q->sslConfiguration();
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
const DWORD protocols = toSchannelProtocol(configuration.protocol);
const DWORD protocols = toSchannelProtocol(configuration.protocol());
if (protocols == DWORD(-1)) {
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
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.
// This happens if there was something wrong with the certificate chain or there was no private
// key.
if (!configuration.localCertificateChain.isEmpty() && !localCertificateStore)
if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
if (localCertificateStore != nullptr) {
@ -859,7 +861,7 @@ bool TlsCryptographSchannel::acquireCredentialsHandle()
TLS_PARAMETERS tlsParameters = {
0,
nullptr,
toSchannelProtocolNegated(configuration.protocol), // what protocols to disable
toSchannelProtocolNegated(configuration.protocol()), // what protocols to disable
0,
nullptr,
0
@ -960,8 +962,9 @@ void TlsCryptographSchannel::closeCertificateStores()
bool TlsCryptographSchannel::createContext()
{
Q_ASSERT(q);
Q_ASSERT(d);
auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
Q_ASSERT(SecIsValidHandle(&credentialHandle));
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
@ -989,8 +992,8 @@ bool TlsCryptographSchannel::createContext()
SecBufferDesc alpnBufferDesc;
bool useAlpn = false;
#ifdef SUPPORTS_ALPN
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
QByteArray alpnString = createAlpnString(configuration.allowedNextProtocols());
useAlpn = !alpnString.isEmpty();
SecBuffer alpnBuffers[1];
alpnBuffers[0] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
@ -1032,7 +1035,8 @@ bool TlsCryptographSchannel::createContext()
bool TlsCryptographSchannel::acceptContext()
{
Q_ASSERT(d);
auto &configuration = d->privateConfiguration();
Q_ASSERT(q);
const auto &configuration = q->sslConfiguration();
auto *plainSocket = d->plainTcpSocket();
Q_ASSERT(SecIsValidHandle(&credentialHandle));
@ -1052,9 +1056,9 @@ bool TlsCryptographSchannel::acceptContext()
inBuffers[0] = createSecBuffer(intermediateBuffer, SECBUFFER_TOKEN);
#ifdef SUPPORTS_ALPN
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
// The string must be alive when we call AcceptSecurityContext
QByteArray alpnString = createAlpnString(configuration.nextAllowedProtocols);
QByteArray alpnString = createAlpnString(configuration.allowedNextProtocols());
if (!alpnString.isEmpty()) {
inBuffers[1] = createSecBuffer(alpnString, SECBUFFER_APPLICATION_PROTOCOLS);
} else
@ -1269,7 +1273,7 @@ bool TlsCryptographSchannel::verifyHandshake()
{
Q_ASSERT(d);
Q_ASSERT(q);
auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
sslErrors.clear();
@ -1284,7 +1288,7 @@ bool TlsCryptographSchannel::verifyHandshake()
// Everything is set up, now make sure there's nothing wrong and query some attributes...
if (!matchesContextRequirements(contextAttributes, getContextRequirements(),
configuration.peerVerifyMode, isClient)) {
configuration.peerVerifyMode(), isClient)) {
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
QSslSocket::tr("Did not get the required attributes for the connection."));
return false;
@ -1303,7 +1307,8 @@ bool TlsCryptographSchannel::verifyHandshake()
CHECK_STATUS(status);
#ifdef SUPPORTS_ALPN
if (!configuration.nextAllowedProtocols.isEmpty() && supportsAlpn()) {
const auto allowedProtos = configuration.allowedNextProtocols();
if (!allowedProtos.isEmpty() && supportsAlpn()) {
SecPkgContext_ApplicationProtocol alpn;
status = QueryContextAttributes(&contextHandle,
SECPKG_ATTR_APPLICATION_PROTOCOL,
@ -1312,16 +1317,16 @@ bool TlsCryptographSchannel::verifyHandshake()
if (alpn.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
QByteArray negotiatedProto = QByteArray((const char *)alpn.ProtocolId,
alpn.ProtocolIdSize);
if (!configuration.nextAllowedProtocols.contains(negotiatedProto)) {
if (!allowedProtos.contains(negotiatedProto)) {
d->setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
QSslSocket::tr("Unwanted protocol was negotiated"));
return false;
}
configuration.nextNegotiatedProtocol = negotiatedProto;
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
QTlsBackend::setNegotiatedProtocol(d, negotiatedProto);
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
} else {
configuration.nextNegotiatedProtocol = "";
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationUnsupported;
QTlsBackend::setNegotiatedProtocol(d, {});
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationUnsupported);
}
}
#endif // supports ALPN
@ -1343,9 +1348,9 @@ bool TlsCryptographSchannel::verifyHandshake()
// 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.
// This means that servers using Schannel will only request client certificate for "VerifyPeer".
if ((!isClient && configuration.peerVerifyMode == QSslSocket::PeerVerifyMode::VerifyPeer)
|| (isClient && configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::VerifyNone
&& configuration.peerVerifyMode != QSslSocket::PeerVerifyMode::QueryPeer)) {
if ((!isClient && configuration.peerVerifyMode() == QSslSocket::PeerVerifyMode::VerifyPeer)
|| (isClient && configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::VerifyNone
&& configuration.peerVerifyMode() != QSslSocket::PeerVerifyMode::QueryPeer)) {
if (status != SEC_E_OK) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcSsl) << "Couldn't retrieve peer certificate, status:"
@ -1909,13 +1914,13 @@ bool TlsCryptographSchannel::checkSslErrors()
Q_ASSERT(q);
Q_ASSERT(d);
const auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
auto *plainSocket = d->plainTcpSocket();
emit q->sslErrors(sslErrors);
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
&& d->tlsMode() == QSslSocket::SslClientMode);
const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
// 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
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) {
const wchar_t *passphrase = L"";
@ -1952,22 +1958,22 @@ void TlsCryptographSchannel::initializeCertificateStores()
return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
};
if (!configuration.localCertificateChain.isEmpty()) {
if (configuration.privateKey.isNull()) {
if (!configuration.localCertificateChain().isEmpty()) {
if (configuration.privateKey().isNull()) {
d->setErrorAndEmit(QAbstractSocket::SslInvalidUserDataError,
QSslSocket::tr("Cannot provide a certificate with no key"));
return;
}
if (localCertificateStore == nullptr) {
localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain,
configuration.privateKey);
localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
configuration.privateKey());
if (localCertificateStore == nullptr)
qCWarning(lcSsl, "Failed to load certificate chain!");
}
}
if (!configuration.caCertificates.isEmpty() && !caCertificateStore) {
caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates,
if (!configuration.caCertificates().isEmpty() && !caCertificateStore) {
caCertificateStore = createStoreFromCertificateChain(configuration.caCertificates(),
{}); // No private key for the CA certs
}
}
@ -1977,7 +1983,6 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
Q_ASSERT(certContext);
Q_ASSERT(q);
Q_ASSERT(d);
auto &configuration = d->privateConfiguration();
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
@ -2038,8 +2043,7 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
: szOID_PKIX_KP_CLIENT_AUTH);
parameters.RequestedUsage.Usage.rgpszUsageIdentifier = &oid;
configuration.peerCertificate.clear();
configuration.peerCertificateChain.clear();
QTlsBackend::clearPeerCertificates(d);
const CERT_CHAIN_CONTEXT *chainContext = nullptr;
auto freeCertChain = qScopeGuard([&chainContext]() {
if (chainContext)
@ -2106,23 +2110,26 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
}
DWORD verifyDepth = chain->cElement;
if (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
verifyDepth = DWORD(configuration.peerVerifyDepth);
if (q->peerVerifyDepth() > 0 && DWORD(q->peerVerifyDepth()) < verifyDepth)
verifyDepth = DWORD(q->peerVerifyDepth());
const auto &caCertificates = q->sslConfiguration().caCertificates();
QList<QSslCertificate> peerCertificateChain;
for (DWORD i = 0; i < verifyDepth; i++) {
CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
QSslCertificate certificate = getCertificateFromChainElement(element);
const QList<QSslCertificateExtension> extensions = certificate.extensions();
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcSsl) << "issuer:" << certificate.issuerDisplayName()
<< "\nsubject:" << certificate.subjectDisplayName()
<< "\nQSslCertificate info:" << certificate
<< "\nextended error info:" << element->pwszExtendedErrorInfo
<< "\nerror status:" << element->TrustStatus.dwErrorStatus;
qCDebug(lcTlsBackend) << "issuer:" << certificate.issuerDisplayName()
<< "\nsubject:" << certificate.subjectDisplayName()
<< "\nQSslCertificate info:" << certificate
<< "\nextended error info:" << element->pwszExtendedErrorInfo
<< "\nerror status:" << element->TrustStatus.dwErrorStatus;
#endif
configuration.peerCertificateChain.append(certificate);
peerCertificateChain.append(certificate);
QTlsBackend::storePeerCertificateChain(d, peerCertificateChain);
if (certificate.isBlacklisted()) {
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) {
// 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) {
auto error = QSslError(QSslError::CertificateUntrusted, certificate);
sslErrors += error;
@ -2257,25 +2264,26 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
}
}
if (!configuration.peerCertificateChain.isEmpty())
configuration.peerCertificate = configuration.peerCertificateChain.first();
if (!peerCertificateChain.isEmpty())
QTlsBackend::storePeerCertificate(d, peerCertificateChain.first());
const auto &configuration = q->sslConfiguration(); // Probably, updated by QTlsBackend::storePeerCertificate etc.
// @Note: Somewhat copied from qsslsocket_mac.cpp
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
const bool doVerifyPeer = q->peerVerifyMode() == QSslSocket::VerifyPeer
|| (q->peerVerifyMode() == QSslSocket::AutoVerifyPeer
&& d->tlsMode() == QSslSocket::SslClientMode);
// Check the peer certificate itself. First try the subject's common name
// (CN) as a wildcard, then try all alternate subject name DNS entries the
// same way.
if (!configuration.peerCertificate.isNull()) {
if (!configuration.peerCertificate().isNull()) {
// but only if we're a client connecting to a server
// if we're the server, don't check CN
if (d->tlsMode() == QSslSocket::SslClientMode) {
const auto verificationPeerName = d->verificationName();
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.
const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate());
sslErrors += error;
emit q->peerVerifyError(error);
if (q->state() != QAbstractSocket::ConnectedState)

View File

@ -346,7 +346,7 @@ void TlsCryptographSecureTransport::continueHandshake()
Q_ASSERT(q);
Q_ASSERT(d);
d->setEncrypted(true);
#ifdef QSSLSOCKET_DEBU
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << d->plainTcpSocket() << "connection encrypted";
#endif
@ -355,12 +355,12 @@ void TlsCryptographSecureTransport::continueHandshake()
// 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 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, *)) {
const auto &requestedProtocols = configuration.nextAllowedProtocols;
const auto &requestedProtocols = configuration.allowedNextProtocols();
if (const int requestedCount = requestedProtocols.size()) {
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNone;
configuration.nextNegotiatedProtocol.clear();
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNone);
QTlsBackend::setNegotiatedProtocol(d, {});
QCFType<CFArrayRef> cfArray;
const OSStatus result = SSLCopyALPNProtocols(context, &cfArray);
@ -374,12 +374,12 @@ void TlsCryptographSecureTransport::continueHandshake()
const auto requestedName = QString::fromLatin1(requestedProtocols[i]);
for (int j = 0; j < size; ++j) {
if (requestedName == peerProtocols[j]) {
configuration.nextNegotiatedProtocol = requestedName.toLatin1();
configuration.nextProtocolNegotiationStatus = QSslConfiguration::NextProtocolNegotiationNegotiated;
QTlsBackend::setNegotiatedProtocol(d, requestedName.toLatin1());
QTlsBackend::setAlpnStatus(d, QSslConfiguration::NextProtocolNegotiationNegotiated);
break;
}
}
if (configuration.nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNegotiated)
if (configuration.nextProtocolNegotiationStatus() == QSslConfiguration::NextProtocolNegotiationNegotiated)
break;
}
}
@ -678,9 +678,9 @@ bool TlsCryptographSecureTransport::initSslContext()
SSLSetConnection(context, this);
auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
if (mode == QSslSocket::SslServerMode
&& !configuration.localCertificateChain.isEmpty()) {
&& !configuration.localCertificateChain().isEmpty()) {
QString errorDescription;
QAbstractSocket::SocketError errorCode = QAbstractSocket::UnknownSocketError;
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 (__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));
if (cfNames) {
for (const QByteArray &name : protocolNames) {
@ -748,7 +748,7 @@ bool TlsCryptographSecureTransport::initSslContext()
}
//
} else {
if (configuration.peerVerifyMode != QSslSocket::VerifyNone) {
if (configuration.peerVerifyMode() != QSslSocket::VerifyNone) {
// kAlwaysAuthenticate - always fails even if we set break on client auth.
OSStatus err = SSLSetClientSideAuthenticate(context, kTryAuthenticate);
if (err == errSecSuccess) {
@ -769,9 +769,9 @@ bool TlsCryptographSecureTransport::initSslContext()
SSLSetDiffieHellmanParams(context, dhparam, sizeof(dhparam));
#endif
}
if (configuration.ciphers.size() > 0) {
if (configuration.ciphers().size() > 0) {
QVector<SSLCipherSuite> cfCiphers;
for (const QSslCipher &cipher : configuration.ciphers) {
for (const QSslCipher &cipher : configuration.ciphers()) {
if (auto sslCipher = TlsCryptographSecureTransport::SSLCipherSuite_from_QSslCipher(cipher))
cfCiphers << sslCipher;
}
@ -798,7 +798,7 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
Q_ASSERT(d);
const auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
#ifdef QSSLSOCKET_DEBUG
auto *plainSocket = d->plainTcpSocket();
@ -806,12 +806,12 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
QSslCertificate localCertificate;
if (!configuration.localCertificateChain.isEmpty())
localCertificate = configuration.localCertificateChain.at(0);
if (!configuration.localCertificateChain().isEmpty())
localCertificate = configuration.localCertificateChain().at(0);
if (!localCertificate.isNull()) {
// Require a private key as well.
if (configuration.privateKey.isNull()) {
if (configuration.privateKey().isNull()) {
errorCode = QAbstractSocket::SslInvalidUserDataError;
errorDescription = QStringLiteral("Cannot provide a certificate with no key");
return false;
@ -819,8 +819,8 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
// import certificates and key
const QString passPhrase(QString::fromLatin1("foobar"));
QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain,
configuration.privateKey, passPhrase).toCFData();
QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain(),
configuration.privateKey(), passPhrase).toCFData();
QCFType<CFStringRef> password = passPhrase.toCFString();
const void *keys[2] = { kSecImportExportPassphrase };
const void *values[2] = { password };
@ -904,14 +904,15 @@ bool TlsCryptographSecureTransport::setSessionCertificate(QString &errorDescript
bool TlsCryptographSecureTransport::setSessionProtocol()
{
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
Q_ASSERT(q);
Q_ASSERT(d);
// SecureTransport has kTLSProtocol13 constant and also, kTLSProtocolMaxSupported.
// Calling SSLSetProtocolVersionMax/Min with any of these two constants results
// in errInvalidParam and a failure to set the protocol version. This means
// no TLS 1.3 on macOS and iOS.
const auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
auto *plainSocket = d->plainTcpSocket();
switch (configuration.protocol) {
switch (configuration.protocol()) {
case QSsl::TlsV1_3:
case QSsl::TlsV1_3OrLater:
qCWarning(lcTlsBackend) << plainSocket << "SecureTransport does not support TLS 1.3";
@ -921,48 +922,48 @@ bool TlsCryptographSecureTransport::setSessionProtocol()
OSStatus err = errSecSuccess;
if (configuration.protocol == QSsl::TlsV1_0) {
if (configuration.protocol() == QSsl::TlsV1_0) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.0";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
if (err == errSecSuccess)
err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
} else if (configuration.protocol == QSsl::TlsV1_1) {
} else if (configuration.protocol() == QSsl::TlsV1_1) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
if (err == errSecSuccess)
err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
} else if (configuration.protocol == QSsl::TlsV1_2) {
} else if (configuration.protocol() == QSsl::TlsV1_2) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
if (err == errSecSuccess)
err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
} else if (configuration.protocol == QSsl::AnyProtocol) {
} else if (configuration.protocol() == QSsl::AnyProtocol) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : any";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
} else if (configuration.protocol == QSsl::SecureProtocols) {
} else if (configuration.protocol() == QSsl::SecureProtocols) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
} else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
} else if (configuration.protocol() == QSsl::TlsV1_0OrLater) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1 - TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
} else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
} else if (configuration.protocol() == QSsl::TlsV1_1OrLater) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
#endif
err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
} else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
} else if (configuration.protocol() == QSsl::TlsV1_2OrLater) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcTlsBackend) << plainSocket << "requesting : TLSv1.2";
#endif
@ -979,9 +980,10 @@ bool TlsCryptographSecureTransport::setSessionProtocol()
bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
{
Q_ASSERT(q);
Q_ASSERT(d);
const auto &configuration = d->privateConfiguration();
const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
const auto &configuration = q->sslConfiguration();
const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode();
return d->tlsMode() == QSslSocket::SslServerMode
&& (verifyMode == QSslSocket::QueryPeer
|| verifyMode == QSslSocket::AutoVerifyPeer
@ -990,24 +992,24 @@ bool TlsCryptographSecureTransport::canIgnoreTrustVerificationFailure() const
bool TlsCryptographSecureTransport::verifySessionProtocol() const
{
Q_ASSERT(d);
Q_ASSERT(q);
const auto &configuration = d->privateConfiguration();
const auto &configuration = q->sslConfiguration();
bool protocolOk = false;
if (configuration.protocol == QSsl::AnyProtocol)
if (configuration.protocol() == QSsl::AnyProtocol)
protocolOk = true;
else if (configuration.protocol == QSsl::SecureProtocols)
else if (configuration.protocol() == QSsl::SecureProtocols)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
else if (configuration.protocol == QSsl::TlsV1_0OrLater)
else if (configuration.protocol() == QSsl::TlsV1_0OrLater)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_0);
else if (configuration.protocol == QSsl::TlsV1_1OrLater)
else if (configuration.protocol() == QSsl::TlsV1_1OrLater)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_1);
else if (configuration.protocol == QSsl::TlsV1_2OrLater)
else if (configuration.protocol() == QSsl::TlsV1_2OrLater)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_2);
else if (configuration.protocol == QSsl::TlsV1_3OrLater)
else if (configuration.protocol() == QSsl::TlsV1_3OrLater)
protocolOk = (sessionProtocol() >= QSsl::TlsV1_3OrLater);
else
protocolOk = (sessionProtocol() == configuration.protocol);
protocolOk = (sessionProtocol() == configuration.protocol());
return protocolOk;
}
@ -1017,9 +1019,8 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
Q_ASSERT(q);
Q_ASSERT(d);
auto &configuration = d->privateConfiguration();
const auto mode = d->tlsMode();
const QSslSocket::PeerVerifyMode verifyMode = configuration.peerVerifyMode;
const QSslSocket::PeerVerifyMode verifyMode = q->peerVerifyMode();
const bool canIgnoreVerify = canIgnoreTrustVerificationFailure();
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
@ -1060,21 +1061,22 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
return false;
}
configuration.peerCertificate.clear();
configuration.peerCertificateChain.clear();
QTlsBackend::clearPeerCertificates(d);
QList<QSslCertificate> peerCertificateChain;
const CFIndex certCount = SecTrustGetCertificateCount(trust);
for (CFIndex i = 0; i < certCount; ++i) {
SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, i);
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())
configuration.peerCertificate = configuration.peerCertificateChain.at(0);
if (peerCertificateChain.size())
QTlsBackend::storePeerCertificate(d, peerCertificateChain.at(0));
// 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) {
const QSslError error(QSslError::CertificateBlacklisted, cert);
errors << error;
@ -1090,15 +1092,16 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
// Check the peer certificate itself. First try the subject's common name
// (CN) as a wildcard, then try all alternate subject name DNS entries the
// same way.
if (!configuration.peerCertificate.isNull()) {
const auto &peerCertificate = q->peerCertificate();
if (!peerCertificate.isNull()) {
// but only if we're a client connecting to a server
// if we're the server, don't check CN
const QString verificationPeerName = d->verificationName();
if (mode == QSslSocket::SslClientMode) {
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.
const QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
const QSslError error(QSslError::HostNameMismatch, peerCertificate);
errors << error;
emit q->peerVerifyError(error);
if (q->state() != QAbstractSocket::ConnectedState)
@ -1119,7 +1122,8 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
// verify certificate chain
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();
if (QCFType<SecCertificateRef> secRef = SecCertificateCreateWithData(nullptr, certData))
CFArrayAppendValue(certArray, secRef);
@ -1165,7 +1169,7 @@ bool TlsCryptographSecureTransport::verifyPeerTrust()
break;
default:
if (!canIgnoreVerify) {
const QSslError error(QSslError::CertificateUntrusted, configuration.peerCertificate);
const QSslError error(QSslError::CertificateUntrusted, peerCertificate);
errors << error;
emit q->peerVerifyError(error);
}
@ -1199,9 +1203,9 @@ bool TlsCryptographSecureTransport::checkSslErrors()
emit q->sslErrors(sslErrors);
const auto mode = d->tlsMode();
const auto &configuration = d->privateConfiguration();
const bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
const auto &configuration = q->sslConfiguration();
const bool doVerifyPeer = configuration.peerVerifyMode() == QSslSocket::VerifyPeer
|| (configuration.peerVerifyMode() == QSslSocket::AutoVerifyPeer
&& mode == QSslSocket::SslClientMode);
const bool doEmitSslError = !d->verifyErrorsHaveBeenIgnored();
// check whether we need to emit an SSL handshake error

View File

@ -701,6 +701,92 @@ void QTlsBackend::setDefaultCaCertificates(const QList<QSslCertificate> &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)
QT_END_NAMESPACE

View File

@ -405,6 +405,29 @@ public:
static void resetDefaultEllipticCurves();
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)
Q_DISABLE_COPY_MOVE(QTlsBackend)