diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2021-03-12 12:12:59 +0100 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2021-03-16 13:41:08 +0100 |
commit | 31cc0df7607a4d5887812c304aac0001c2cd7705 (patch) | |
tree | a961a6b76273a040e62259ac3c7c743c83f87318 /src/network | |
parent | 9391ba55149336c395b866b24dc9b844334d50da (diff) |
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>
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/ssl/qdtls_base.cpp | 29 | ||||
-rw-r--r-- | src/network/ssl/qdtls_base_p.h | 4 | ||||
-rw-r--r-- | src/network/ssl/qdtls_openssl.cpp | 55 | ||||
-rw-r--r-- | src/network/ssl/qsslconfiguration.h | 8 | ||||
-rw-r--r-- | src/network/ssl/qsslconfiguration_p.h | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 8 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_p.h | 1 | ||||
-rw-r--r-- | src/network/ssl/qtls_openssl.cpp | 137 | ||||
-rw-r--r-- | src/network/ssl/qtls_schannel.cpp | 110 | ||||
-rw-r--r-- | src/network/ssl/qtls_st.cpp | 118 | ||||
-rw-r--r-- | src/network/ssl/qtlsbackend.cpp | 86 | ||||
-rw-r--r-- | src/network/ssl/qtlsbackend_p.h | 23 |
12 files changed, 334 insertions, 249 deletions
diff --git a/src/network/ssl/qdtls_base.cpp b/src/network/ssl/qdtls_base.cpp index be10aac7db..6a5979eb9e 100644 --- a/src/network/ssl/qdtls_base.cpp +++ b/src/network/ssl/qdtls_base.cpp @@ -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(); } diff --git a/src/network/ssl/qdtls_base_p.h b/src/network/ssl/qdtls_base_p.h index bbca4ab57d..df35f514a2 100644 --- a/src/network/ssl/qdtls_base_p.h +++ b/src/network/ssl/qdtls_base_p.h @@ -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; diff --git a/src/network/ssl/qdtls_openssl.cpp b/src/network/ssl/qdtls_openssl.cpp index 374839458c..80b5179f69 100644 --- a/src/network/ssl/qdtls_openssl.cpp +++ b/src/network/ssl/qdtls_openssl.cpp @@ -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 = {}; diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 716ea8ed7f..43566bc0cd 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -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; }; diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h index 9a70fda653..43c736e012 100644 --- a/src/network/ssl/qsslconfiguration_p.h +++ b/src/network/ssl/qsslconfiguration_p.h @@ -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; diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 264815d3ac..1463fbdc53 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -3123,14 +3123,6 @@ QSslSocket::SslMode QSslSocketPrivate::tlsMode() const /*! \internal */ -QSslConfigurationPrivate &QSslSocketPrivate::privateConfiguration() -{ - return configuration; -} - -/*! - \internal -*/ bool QSslSocketPrivate::isRootsOnDemandAllowed() const { return allowRootCertOnDemandLoading; diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 6a03a23dc6..c90dfc8883 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -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; diff --git a/src/network/ssl/qtls_openssl.cpp b/src/network/ssl/qtls_openssl.cpp index d4a6c1a99b..010794c499 100644 --- a/src/network/ssl/qtls_openssl.cpp +++ b/src/network/ssl/qtls_openssl.cpp @@ -560,7 +560,6 @@ bool TlsCryptographOpenSSL::startHandshake() return false; const auto mode = d->tlsMode(); - auto &configuration = d->privateConfiguration(); pendingFatalAlert = false; errorsReportedFromCallback = false; @@ -581,10 +580,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 ¤tError : 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; } @@ -627,8 +630,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; @@ -638,14 +644,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()) { { @@ -669,16 +675,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) @@ -700,7 +706,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; @@ -762,7 +768,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 @@ -770,7 +775,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)) { @@ -803,26 +808,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; @@ -830,7 +838,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 ... @@ -838,16 +846,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); @@ -1175,12 +1183,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) { @@ -1204,7 +1211,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. @@ -1244,9 +1253,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; @@ -1344,17 +1352,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()); @@ -1369,7 +1371,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; @@ -1379,7 +1381,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('.')) @@ -1433,7 +1435,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")); @@ -1447,8 +1449,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. @@ -1491,18 +1494,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); } } @@ -1513,9 +1520,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(); @@ -1605,10 +1612,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); @@ -1635,7 +1642,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: @@ -1663,7 +1670,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) { @@ -1674,11 +1681,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(); @@ -1722,7 +1729,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); @@ -1747,7 +1754,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; @@ -1771,12 +1778,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; } @@ -1789,8 +1795,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) { diff --git a/src/network/ssl/qtls_schannel.cpp b/src/network/ssl/qtls_schannel.cpp index 5cc4195d4e..a68af953ec 100644 --- a/src/network/ssl/qtls_schannel.cpp +++ b/src/network/ssl/qtls_schannel.cpp @@ -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) diff --git a/src/network/ssl/qtls_st.cpp b/src/network/ssl/qtls_st.cpp index 602f1ef409..e4f5c71c02 100644 --- a/src/network/ssl/qtls_st.cpp +++ b/src/network/ssl/qtls_st.cpp @@ -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 diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp index 1d4cf2844f..079cbccbc0 100644 --- a/src/network/ssl/qtlsbackend.cpp +++ b/src/network/ssl/qtlsbackend.cpp @@ -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 diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h index 9015be7a8e..4d2bc25300 100644 --- a/src/network/ssl/qtlsbackend_p.h +++ b/src/network/ssl/qtlsbackend_p.h @@ -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) |