From 9ed754e754a8769c6d3a7291dbfe45f38a7dd20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 10 Jun 2025 18:10:23 +0200 Subject: [PATCH] Schannel: fix verifying intermediate certificates with netscape ext We were always checking 'client' or 'server' usage depending on our own type, which breaks for any intermediate certificate with the 'ca' usage set. We assume that any non-leaf certificate should be a CA (if anything), and leaf certificates must be for client or server usage. Pick-to: 6.10 6.9 6.8 6.5 Fixes: QTBUG-137041 Change-Id: I268f3bad669df77351fc458f56e318db75ecac7b Reviewed-by: Mate Barany --- src/plugins/tls/schannel/qtls_schannel.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp index d152dff6efb..617e070025e 100644 --- a/src/plugins/tls/schannel/qtls_schannel.cpp +++ b/src/plugins/tls/schannel/qtls_schannel.cpp @@ -806,7 +806,7 @@ QT_WARNING_POP \internal Used by verifyCertContext to check if a client cert is used by a server or vice versa. */ -bool netscapeWrongCertType(const QList &extensions, bool isClient) +bool netscapeWrongCertType(const QList &extensions, bool isClient, bool isLeaf) { const auto netscapeIt = std::find_if( extensions.cbegin(), extensions.cend(), @@ -820,8 +820,13 @@ bool netscapeWrongCertType(const QList &extensions, bo dataStream >> netscapeCertType; if (dataStream.status() != QDataStream::Status::Ok) return true; - const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE - : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE; + const int expectedPeerCertType = [&]() { + if (isLeaf) { + return isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE + : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE; + } + return NETSCAPE_SSL_CA_CERT_TYPE; + }(); if ((netscapeCertType & expectedPeerCertType) == 0) return true; } @@ -2549,7 +2554,7 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext) // While netscape shouldn't be relevant now it defined an extension which is // still in use. Schannel does not check this automatically, so we do it here. // It is used to differentiate between client and server certificates. - if (netscapeWrongCertType(extensions, isClient)) + if (netscapeWrongCertType(extensions, isClient, i == 0)) element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE; if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {