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