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:
Timur Pocheptsov 2021-03-12 12:12:59 +01:00
parent 9391ba5514
commit 31cc0df760
12 changed files with 334 additions and 249 deletions

View File

@ -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();
} }

View File

@ -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;

View File

@ -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 = {};

View File

@ -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;
}; };

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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 &currentError : qAsConst(lastErrors)) { for (const auto &currentError : 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) {

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)