Index | Thread | Search

From:
Rafael Sadowski <rafael@sizeofvoid.org>
Subject:
CVE-2025-5455 and CVE-2025-6338: qt6-qtbase-6.8.3
To:
ports@openbsd.org
Cc:
tb@openbsd.org
Date:
Sun, 3 Aug 2025 10:00:30 +0200

Download raw body.

Thread
  • Rafael Sadowski:

    CVE-2025-5455 and CVE-2025-6338: qt6-qtbase-6.8.3

Simple diff to fix CVE-2025-5455 and CVE-2025-6338 in
qt6-qtbase-6.8.3. Tested on amd64. OK?

Cheers Rafael

Index: Makefile
===================================================================
RCS file: /cvs/ports/x11/qt6/qtbase/Makefile,v
diff -u -p -u -p -r1.43 Makefile
--- Makefile	6 Jun 2025 05:12:03 -0000	1.43
+++ Makefile	3 Aug 2025 07:57:55 -0000
@@ -4,7 +4,7 @@ COMMENT-main =		C++ general-purpose tool
 COMMENT-global =	global Qt6 documentation internals
 COMMENT-mysql =		MySQL plugin for Qt6
 COMMENT-psql =		PostgresSQL plugin for Qt6
-REVISION-main =		1
+REVISION-main =		2
 
 PKGSPEC-main =		qt6-qtbase-${QT6_PKGSPEC}
 
Index: patches/patch-src_corelib_io_qdataurl_cpp
===================================================================
RCS file: patches/patch-src_corelib_io_qdataurl_cpp
diff -N patches/patch-src_corelib_io_qdataurl_cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_corelib_io_qdataurl_cpp	3 Aug 2025 07:57:55 -0000
@@ -0,0 +1,19 @@
+https://download.qt.io/official_releases/qt/6.8/CVE-2025-5455-qtbase-6.8.patch
+Index: src/corelib/io/qdataurl.cpp
+--- src/corelib/io/qdataurl.cpp.orig
++++ src/corelib/io/qdataurl.cpp
+@@ -47,10 +47,10 @@ Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QSt
+         QLatin1StringView textPlain;
+         constexpr auto charset = "charset"_L1;
+         if (QLatin1StringView{data}.startsWith(charset, Qt::CaseInsensitive)) {
+-            qsizetype i = charset.size();
+-            while (data.at(i) == ' ')
+-                ++i;
+-            if (data.at(i) == '=')
++            QByteArrayView copy = data.sliced(charset.size());
++            while (copy.startsWith(' '))
++                copy.slice(1);
++            if (copy.startsWith('='))
+                 textPlain = "text/plain;"_L1;
+         }
+ 
Index: patches/patch-src_plugins_tls_schannel_qtls_schannel_cpp
===================================================================
RCS file: patches/patch-src_plugins_tls_schannel_qtls_schannel_cpp
diff -N patches/patch-src_plugins_tls_schannel_qtls_schannel_cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_plugins_tls_schannel_qtls_schannel_cpp	3 Aug 2025 07:57:55 -0000
@@ -0,0 +1,225 @@
+https://ftp.fau.de/qtproject/archive/qt/6.8/CVE-2025-6338-qtbase-6.8.patch
+
+Index: src/plugins/tls/schannel/qtls_schannel.cpp
+--- src/plugins/tls/schannel/qtls_schannel.cpp.orig
++++ src/plugins/tls/schannel/qtls_schannel.cpp
+@@ -7,6 +7,7 @@
+ #include "qtlskey_schannel_p.h"
+ #include "qx509_schannel_p.h"
+ #include "qtls_schannel_p.h"
++#include "../shared/qasn1element_p.h"
+ 
+ #include <QtNetwork/private/qsslcertificate_p.h>
+ #include <QtNetwork/private/qsslcipher_p.h>
+@@ -126,8 +127,9 @@ using namespace Qt::StringLiterals;
+ Q_LOGGING_CATEGORY(lcTlsBackendSchannel, "qt.tlsbackend.schannel");
+ 
+ // Defined in qsslsocket_qt.cpp.
+-QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
++extern QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
+                          const QString &passPhrase);
++extern QAsn1Element _q_PKCS12_key(const QSslKey &key);
+ 
+ namespace {
+ bool supportsTls13();
+@@ -1003,7 +1005,6 @@ TlsCryptographSchannel::~TlsCryptographSchannel()
+     closeCertificateStores();
+     deallocateContext();
+     freeCredentialsHandle();
+-    CertFreeCertificateContext(localCertContext);
+ }
+ 
+ void TlsCryptographSchannel::init(QSslSocket *qObj, QSslSocketPrivate *dObj)
+@@ -1098,12 +1099,6 @@ bool TlsCryptographSchannel::acquireCredentialsHandle(
+         return false;
+     }
+ 
+-    const CERT_CHAIN_CONTEXT *chainContext = nullptr;
+-    auto freeCertChain = qScopeGuard([&chainContext]() {
+-        if (chainContext)
+-            CertFreeCertificateChain(chainContext);
+-    });
+-
+     DWORD certsCount = 0;
+     // Set up our certificate stores before trying to use one...
+     initializeCertificateStores();
+@@ -1114,36 +1109,11 @@ bool TlsCryptographSchannel::acquireCredentialsHandle(
+     if (!configuration.localCertificateChain().isEmpty() && !localCertificateStore)
+         return true; // 'true' because "tst_QSslSocket::setEmptyKey" expects us to not disconnect
+ 
++    PCCERT_CONTEXT localCertificate = nullptr;
+     if (localCertificateStore != nullptr) {
+-        CERT_CHAIN_FIND_BY_ISSUER_PARA findParam;
+-        ZeroMemory(&findParam, sizeof(findParam));
+-        findParam.cbSize = sizeof(findParam);
+-        findParam.pszUsageIdentifier = isClient ? szOID_PKIX_KP_CLIENT_AUTH : szOID_PKIX_KP_SERVER_AUTH;
+-
+-        // There should only be one chain in our store, so.. we grab that one.
+-        chainContext = CertFindChainInStore(localCertificateStore.get(),
+-                                            X509_ASN_ENCODING,
+-                                            0,
+-                                            CERT_CHAIN_FIND_BY_ISSUER,
+-                                            &findParam,
+-                                            nullptr);
+-        if (!chainContext) {
+-            const QString message = isClient
+-                    ? QSslSocket::tr("The certificate provided cannot be used for a client.")
+-                    : QSslSocket::tr("The certificate provided cannot be used for a server.");
+-            setErrorAndEmit(d, QAbstractSocket::SocketError::SslInvalidUserDataError, message);
+-            return false;
+-        }
+-        Q_ASSERT(chainContext->cChain == 1);
+-        Q_ASSERT(chainContext->rgpChain[0]);
+-        Q_ASSERT(chainContext->rgpChain[0]->cbSize >= 1);
+-        Q_ASSERT(chainContext->rgpChain[0]->rgpElement[0]);
+-        Q_ASSERT(!localCertContext);
+-        localCertContext = CertDuplicateCertificateContext(chainContext->rgpChain[0]
+-                                                                   ->rgpElement[0]
+-                                                                   ->pCertContext);
+         certsCount = 1;
+-        Q_ASSERT(localCertContext);
++        localCertificate = static_cast<PCCERT_CONTEXT>(configuration.localCertificate().handle());
++        Q_ASSERT(localCertificate);
+     }
+ 
+     const QList<QSslCipher> ciphers = configuration.ciphers();
+@@ -1167,7 +1137,7 @@ bool TlsCryptographSchannel::acquireCredentialsHandle(
+         SCH_CREDENTIALS_VERSION,
+         0,
+         certsCount,
+-        &localCertContext,
++        &localCertificate,
+         nullptr,
+         0,
+         nullptr,
+@@ -1724,9 +1694,6 @@ void TlsCryptographSchannel::reset()
+     connectionInfo = {};
+     streamSizes = {};
+ 
+-    CertFreeCertificateContext(localCertContext);
+-    localCertContext = nullptr;
+-
+     contextAttributes = 0;
+     intermediateBuffer.clear();
+     schannelState = SchannelState::InitializeHandshake;
+@@ -2236,6 +2203,70 @@ bool TlsCryptographSchannel::checkSslErrors()
+     return true;
+ }
+ 
++static void attachPrivateKeyToCertificate(const QSslCertificate &certificate,
++                                          const QSslKey &privateKey)
++{
++    QAsn1Element elem = _q_PKCS12_key(privateKey);
++    QByteArray buffer;
++    QDataStream stream(&buffer, QDataStream::WriteOnly);
++    elem.write(stream);
++    NCRYPT_PROV_HANDLE provider = 0;
++    SECURITY_STATUS status = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0);
++    if (status != SEC_E_OK) {
++        qCWarning(lcTlsBackendSchannel())
++                << "Failed to open ncrypt storage provider:" << schannelErrorToString(status);
++        return;
++    }
++    const auto freeProvider = qScopeGuard([provider]() { NCryptFreeObject(provider); });
++
++    const QString certName = certificate.subjectInfo(QSslCertificate::CommonName).front();
++    QSpan<const QChar> nameSpan(certName);
++    NCryptBuffer nbuffer{ ULONG(nameSpan.size_bytes() + sizeof(char16_t)),
++                          NCRYPTBUFFER_PKCS_KEY_NAME,
++                          const_reinterpret_cast<void *>(nameSpan.data()) };
++    NCryptBufferDesc bufferDesc{ NCRYPTBUFFER_VERSION, 1, &nbuffer };
++    NCRYPT_KEY_HANDLE ncryptKey = 0;
++    status = NCryptImportKey(provider, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, &bufferDesc, &ncryptKey,
++                             PBYTE(buffer.data()), buffer.size(), 0);
++    if (status != SEC_E_OK) {
++        qCWarning(lcTlsBackendSchannel())
++                << "Failed to import private key:" << schannelErrorToString(status);
++        return;
++    }
++    const auto freeKey = qScopeGuard([ncryptKey]() { NCryptFreeObject(ncryptKey); });
++
++    CERT_CONTEXT *context = PCERT_CONTEXT(certificate.handle());
++    Q_ASSERT(context);
++
++    CRYPT_DATA_BLOB keyBlob = { sizeof(ncryptKey), PBYTE(&ncryptKey) };
++    BOOL ok =
++            CertSetCertificateContextProperty(context, CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, &keyBlob);
++    if (!ok) {
++        auto error = GetLastError();
++        if (lcTlsBackendSchannel().isWarningEnabled())
++            qErrnoWarning(int(error), "Failed to set ncrypt handle property.");
++        return;
++    }
++
++    CRYPT_KEY_PROV_INFO provInfo{
++        const_reinterpret_cast<LPWSTR>(certName.constData()),
++        const_cast<LPWSTR>(MS_KEY_STORAGE_PROVIDER),
++        0,
++        CERT_SET_KEY_PROV_HANDLE_PROP_ID | CERT_SET_KEY_CONTEXT_PROP_ID,
++        0,
++        nullptr,
++        0,
++    };
++    ok = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
++                                           CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG, &provInfo);
++    if (!ok) {
++        auto error = GetLastError();
++        if (lcTlsBackendSchannel().isWarningEnabled())
++            qErrnoWarning(int(error), "Failed to set key provider info property.");
++        return;
++    }
++}
++
+ void TlsCryptographSchannel::initializeCertificateStores()
+ {
+     //// helper function which turns a chain into a certificate store
+@@ -2252,7 +2283,10 @@ void TlsCryptographSchannel::initializeCertificateStor
+         CRYPT_DATA_BLOB pfxBlob;
+         pfxBlob.cbData = DWORD(pkcs12.length());
+         pfxBlob.pbData = reinterpret_cast<unsigned char *>(pkcs12.data());
+-        return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, 0));
++        // ALWAYS_CNG to import using "Cryptography API: Next Generation (CNG)"
++        // NO_PERSIST_KEY to request not persisting anything imported to disk
++        constexpr DWORD flags = PKCS12_ALWAYS_CNG_KSP | PKCS12_NO_PERSIST_KEY;
++        return QHCertStorePointer(PFXImportCertStore(&pfxBlob, passphrase, flags));
+     };
+ 
+     if (!configuration.localCertificateChain().isEmpty()) {
+@@ -2262,10 +2296,34 @@ void TlsCryptographSchannel::initializeCertificateStor
+             return;
+         }
+         if (localCertificateStore == nullptr) {
+-            localCertificateStore = createStoreFromCertificateChain(configuration.localCertificateChain(),
+-                                                                    configuration.privateKey());
+-            if (localCertificateStore == nullptr)
++            localCertificateStore =
++                    createStoreFromCertificateChain(configuration.localCertificateChain(), {});
++            if (localCertificateStore) {
++                const CERT_CONTEXT *certificateContext = CertFindCertificateInStore(
++                        localCertificateStore.get(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
++                        CERT_FIND_ANY, nullptr, nullptr);
++                if (certificateContext) {
++                    auto *backend = QTlsBackend::backend<X509CertificateSchannel>(
++                            configuration.localCertificate());
++                    backend->certificateContext.reset(
++                            CertDuplicateCertificateContext(certificateContext));
++
++                    DWORD keySpec = 0;
++                    BOOL mustFree = FALSE;
++                    NCRYPT_KEY_HANDLE testKey = 0;
++                    BOOL ok = CryptAcquireCertificatePrivateKey(
++                            certificateContext, CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, nullptr,
++                            &testKey, &keySpec, &mustFree);
++                    if (mustFree)
++                        NCryptFreeObject(testKey);
++                    if (!ok) {
++                        attachPrivateKeyToCertificate(configuration.localCertificate(),
++                                                      configuration.privateKey());
++                    }
++                }
++            } else {
+                 qCWarning(lcTlsBackendSchannel, "Failed to load certificate chain!");
++            }
+         }
+     }
+ 
Index: patches/patch-src_plugins_tls_schannel_qtls_schannel_p_h
===================================================================
RCS file: patches/patch-src_plugins_tls_schannel_qtls_schannel_p_h
diff -N patches/patch-src_plugins_tls_schannel_qtls_schannel_p_h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_plugins_tls_schannel_qtls_schannel_p_h	3 Aug 2025 07:57:55 -0000
@@ -0,0 +1,14 @@
+https://ftp.fau.de/qtproject/archive/qt/6.8/CVE-2025-6338-qtbase-6.8.patch
+
+Index: src/plugins/tls/schannel/qtls_schannel_p.h
+--- src/plugins/tls/schannel/qtls_schannel_p.h.orig
++++ src/plugins/tls/schannel/qtls_schannel_p.h
+@@ -106,8 +106,6 @@ class TlsCryptographSchannel final : public TlsCryptog
+     QHCertStorePointer peerCertificateStore = nullptr;
+     QHCertStorePointer caCertificateStore = nullptr;
+ 
+-    const CERT_CONTEXT *localCertContext = nullptr;
+-
+     ULONG contextAttributes = 0;
+     qint64 missingData = 0;
+ 
Index: patches/patch-src_plugins_tls_shared_qsslsocket_qt_cpp
===================================================================
RCS file: patches/patch-src_plugins_tls_shared_qsslsocket_qt_cpp
diff -N patches/patch-src_plugins_tls_shared_qsslsocket_qt_cpp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_plugins_tls_shared_qsslsocket_qt_cpp	3 Aug 2025 07:57:55 -0000
@@ -0,0 +1,14 @@
+https://ftp.fau.de/qtproject/archive/qt/6.8/CVE-2025-6338-qtbase-6.8.patch
+
+Index: src/plugins/tls/shared/qsslsocket_qt.cpp
+--- src/plugins/tls/shared/qsslsocket_qt.cpp.orig
++++ src/plugins/tls/shared/qsslsocket_qt.cpp
+@@ -134,7 +134,7 @@ static QByteArray _q_PKCS12_certBag(const QSslCertific
+     return ba;
+ }
+ 
+-static QAsn1Element _q_PKCS12_key(const QSslKey &key)
++QAsn1Element _q_PKCS12_key(const QSslKey &key)
+ {
+     Q_ASSERT(key.algorithm() == QSsl::Rsa || key.algorithm() == QSsl::Dsa);
+