QSslSocket (OpenSSL, Windows) - make sure we ignore stale fetch results
The CA fetcher on Windows works on a separate thread, it can take quite some time to finish its job and if a connection was meanwhile closed (via 'abort', 'close' or 'disconnectFromHost') but the socket is still alive/re-used - we don't want to be fooled by the previous fetch 'finished' signal, only if it's fetching for the same certificate. Change-Id: Ibd0a70000ad10cff10207d37d7b47c38e615d0f1 Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
964f5757ea
commit
c9a702a04d
@ -898,6 +898,10 @@ void QSslSocket::close()
|
||||
qCDebug(lcSsl) << "QSslSocket::close()";
|
||||
#endif
|
||||
Q_D(QSslSocket);
|
||||
|
||||
// We don't want any CA roots fetched anymore.
|
||||
d->caToFetch = QSslCertificate{};
|
||||
|
||||
if (encryptedBytesToWrite() || !d->writeBuffer.isEmpty())
|
||||
flush();
|
||||
if (d->plainSocket)
|
||||
@ -947,6 +951,11 @@ void QSslSocket::abort()
|
||||
#ifdef QSSLSOCKET_DEBUG
|
||||
qCDebug(lcSsl) << "QSslSocket::abort()";
|
||||
#endif
|
||||
// On Windows, CertGetCertificateChain is probably still doing its
|
||||
// job, if the socket is re-used, we want to ignore its reported
|
||||
// root CA.
|
||||
d->caToFetch = QSslCertificate{};
|
||||
|
||||
if (d->plainSocket)
|
||||
d->plainSocket->abort();
|
||||
close();
|
||||
@ -1768,6 +1777,9 @@ void QSslSocket::disconnectFromHost()
|
||||
d->pendingClose = true;
|
||||
return;
|
||||
}
|
||||
// Make sure we don't process any signal from the CA fetcher
|
||||
// (Windows):
|
||||
d->caToFetch = QSslCertificate{};
|
||||
|
||||
// Perhaps emit closing()
|
||||
if (d->state != ClosingState) {
|
||||
@ -1884,6 +1896,7 @@ void QSslSocketPrivate::init()
|
||||
configuration.peerCertificate.clear();
|
||||
configuration.peerCertificateChain.clear();
|
||||
fetchAuthorityInformation = false;
|
||||
caToFetch = QSslCertificate{};
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1736,8 +1736,13 @@ void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert)
|
||||
if (fetchAuthorityInformation)
|
||||
customRoots = configuration.caCertificates;
|
||||
|
||||
//Remember we are fetching and what we are fetching:
|
||||
caToFetch = cert;
|
||||
|
||||
QWindowsCaRootFetcher *fetcher = new QWindowsCaRootFetcher(cert, mode, customRoots, q->peerVerifyName());
|
||||
QObject::connect(fetcher, SIGNAL(finished(QSslCertificate,QSslCertificate)), q, SLOT(_q_caRootLoaded(QSslCertificate,QSslCertificate)), Qt::QueuedConnection);
|
||||
QObjectPrivate::connect(fetcher, &QWindowsCaRootFetcher::finished,
|
||||
this, &QSslSocketBackendPrivate::_q_caRootLoaded,
|
||||
Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(fetcher, "start", Qt::QueuedConnection);
|
||||
pauseSocketNotifiers(q);
|
||||
paused = true;
|
||||
@ -1746,6 +1751,14 @@ void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert)
|
||||
//This is the callback from QWindowsCaRootFetcher, trustedRoot will be invalid (default constructed) if it failed.
|
||||
void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertificate trustedRoot)
|
||||
{
|
||||
if (caToFetch != cert) {
|
||||
//Ooops, something from the previous connection attempt, ignore!
|
||||
return;
|
||||
}
|
||||
|
||||
//Done, fetched already:
|
||||
caToFetch = QSslCertificate{};
|
||||
|
||||
if (fetchAuthorityInformation) {
|
||||
if (!configuration.caCertificates.contains(trustedRoot))
|
||||
trustedRoot = QSslCertificate{};
|
||||
|
@ -222,6 +222,7 @@ protected:
|
||||
QList<QOcspResponse> ocspResponses;
|
||||
bool handshakeInterrupted = false;
|
||||
bool fetchAuthorityInformation = false;
|
||||
QSslCertificate caToFetch;
|
||||
};
|
||||
|
||||
#if QT_CONFIG(securetransport) || QT_CONFIG(schannel)
|
||||
|
Loading…
Reference in New Issue
Block a user