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 <mate.barany@qt.io>
This commit is contained in:
Mårten Nordheim 2025-06-10 18:10:23 +02:00
parent 33dc247b6a
commit 9ed754e754

View File

@ -806,7 +806,7 @@ QT_WARNING_POP
\internal \internal
Used by verifyCertContext to check if a client cert is used by a server or vice versa. Used by verifyCertContext to check if a client cert is used by a server or vice versa.
*/ */
bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bool isClient) bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bool isClient, bool isLeaf)
{ {
const auto netscapeIt = std::find_if( const auto netscapeIt = std::find_if(
extensions.cbegin(), extensions.cend(), extensions.cbegin(), extensions.cend(),
@ -820,8 +820,13 @@ bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bo
dataStream >> netscapeCertType; dataStream >> netscapeCertType;
if (dataStream.status() != QDataStream::Status::Ok) if (dataStream.status() != QDataStream::Status::Ok)
return true; return true;
const int expectedPeerCertType = isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE const int expectedPeerCertType = [&]() {
if (isLeaf) {
return isClient ? NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE
: NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE; : NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE;
}
return NETSCAPE_SSL_CA_CERT_TYPE;
}();
if ((netscapeCertType & expectedPeerCertType) == 0) if ((netscapeCertType & expectedPeerCertType) == 0)
return true; 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 // 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. // still in use. Schannel does not check this automatically, so we do it here.
// It is used to differentiate between client and server certificates. // 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; element->TrustStatus.dwErrorStatus |= CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) { if (element->TrustStatus.dwErrorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) {