From ec348cf21e3cecfda0e1d7db6f2ecf423509f55a Mon Sep 17 00:00:00 2001
From: Marek Vasut <marex@denx.de>
Date: Tue, 10 Oct 2023 16:09:29 +0200
Subject: [PATCH] qtbase: Pick CVE-2023-34410 fix

CVE: CVE-2023-34410
Upstream-Status: Backport [https://download.qt.io/official_releases/qt/5.15/CVE-2023-34410-qtbase-5.15.diff]
---
 src/network/ssl/qsslsocket.cpp          |  5 +++++
 src/network/ssl/qsslsocket_schannel.cpp | 22 ++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 5bb6e7ee4a..2a0b3a4f1d 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -2221,6 +2221,10 @@ QSslSocketPrivate::QSslSocketPrivate()
     , flushTriggered(false)
 {
     QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
+    // If the global configuration doesn't allow root certificates to be loaded
+    // on demand then we have to disable it for this socket as well.
+    if (!configuration.allowRootCertOnDemandLoading)
+        allowRootCertOnDemandLoading = false;
 }
 
 /*!
@@ -2470,6 +2474,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
     ptr->sessionProtocol = global->sessionProtocol;
     ptr->ciphers = global->ciphers;
     ptr->caCertificates = global->caCertificates;
+    ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
     ptr->protocol = global->protocol;
     ptr->peerVerifyMode = global->peerVerifyMode;
     ptr->peerVerifyDepth = global->peerVerifyDepth;
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
index c956ce3c2b..d1b23af29b 100644
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ b/src/network/ssl/qsslsocket_schannel.cpp
@@ -1880,6 +1880,28 @@ bool QSslSocketBackendPrivate::verifyCertContext(CERT_CONTEXT *certContext)
     if (configuration.peerVerifyDepth > 0 && DWORD(configuration.peerVerifyDepth) < verifyDepth)
         verifyDepth = DWORD(configuration.peerVerifyDepth);
 
+    const auto &caCertificates = q->sslConfiguration().caCertificates();
+
+    if (!rootCertOnDemandLoadingAllowed()
+            && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
+            && (q->peerVerifyMode() == QSslSocket::VerifyPeer
+                    || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
+        // When verifying a peer Windows "helpfully" builds a chain that
+        // may include roots from the system store. But we don't want that if
+        // the user has set their own CA certificates.
+        // Since Windows claims this is not a partial chain the root is included
+        // and we have to check that it is one of our configured CAs.
+        CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
+        QSslCertificate certificate = getCertificateFromChainElement(element);
+        if (!caCertificates.contains(certificate)) {
+            auto error = QSslError(QSslError::CertificateUntrusted, certificate);
+            sslErrors += error;
+            emit q->peerVerifyError(error);
+            if (q->state() != QAbstractSocket::ConnectedState)
+                return false;
+        }
+    }
+
     for (DWORD i = 0; i < verifyDepth; i++) {
         CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
         QSslCertificate certificate = getCertificateFromChainElement(element);
