From 5df8379b18af0bcfe70a45bdce6e16fe90d42093 Mon Sep 17 00:00:00 2001 From: Vladimir Belyavsky Date: Thu, 21 Nov 2024 15:11:08 +0300 Subject: [PATCH] Schannel: fix endless loop in TlsCryptographSchannel::transmit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We've encountered that under some circumstances DecryptMessage may return undocumented SEC_E_DECRYPT_FAILURE status. It's probably a bug in Schannel on Win 11, as there is no such problem on Win 10. In such cases, since we didn't handle this specifically, we can end up in an infinite loop in TlsCryptographSchannel::transmit() when `intermediateBuffer` is not empty and `bytesRead` is 0. To fix this, we just add SEC_E_DECRYPT_FAILURE status handling and will disconnect from the host and emit the error respectively. Change-Id: I340669a967be420c74cb01296629f94c4720c958 Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit ed0eb386dad22b0984151b92168dcbf9b57c381b) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/tls/schannel/qtls_schannel.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp index a244a90ebc2..6cacb5b7710 100644 --- a/src/plugins/tls/schannel/qtls_schannel.cpp +++ b/src/plugins/tls/schannel/qtls_schannel.cpp @@ -670,6 +670,8 @@ QString schannelErrorToString(qint32 status) return QSslSocket::tr("Unexpected or badly-formatted message received"); case SEC_E_ENCRYPT_FAILURE: return QSslSocket::tr("The data could not be encrypted"); + case SEC_E_DECRYPT_FAILURE: + return QSslSocket::tr("The data could not be decrypted"); case SEC_E_ALGORITHM_MISMATCH: return QSslSocket::tr("No cipher suites in common"); case SEC_E_UNKNOWN_CREDENTIALS: @@ -1945,6 +1947,13 @@ void TlsCryptographSchannel::transmit() setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status)); break; + } else if (status == SEC_E_DECRYPT_FAILURE) { + // It's not documented as a possible return value for DecryptMessage, + // but we see that this may happen - supposed to be a bug in Schannel (with TLS 1.3?) + shutdown = true; // skips sending the shutdown alert + disconnectFromHost(); + setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status)); + break; } else if (status == SEC_I_CONTEXT_EXPIRED) { // 'remote' has initiated a shutdown disconnectFromHost();