QAuthenticator: Filter out algorithms we don't support

Which is anything other than MD5

Pick-to: 6.2 5.15
Fixes: QTBUG-98280
Change-Id: Ifbf143f233ee5602fed1594e3316e6b2adec1461
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Mårten Nordheim 2021-11-22 15:20:32 +01:00
parent 8a883dea1c
commit a92619d950
2 changed files with 50 additions and 0 deletions

View File

@ -443,6 +443,21 @@ bool QAuthenticatorPrivate::isMethodSupported(QByteArrayView method)
return std::any_of(methods, methods + std::size(methods), isSupported);
}
static bool verifyDigestMD5(QByteArrayView value)
{
auto opts = QAuthenticatorPrivate::parseDigestAuthenticationChallenge(value.toByteArray());
if (auto it = opts.constFind("algorithm"); it != opts.cend()) {
QByteArray alg = it.value();
if (alg.size() < 3)
return false;
// Just compare the first 3 characters, that way we match other subvariants as well, such as
// "MD5-sess"
auto view = QByteArrayView(alg).first(3);
return view.compare("MD5", Qt::CaseInsensitive) == 0;
}
return true; // assume it's ok if algorithm is not specified
}
void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy, const QString &host)
{
#if !QT_CONFIG(gssapi)
@ -474,6 +489,10 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
method = Ntlm;
headerVal = current.second.mid(5);
} else if (method < DigestMd5 && str.startsWith("digest")) {
// Make sure the algorithm is actually MD5 before committing to it:
if (!verifyDigestMD5(QByteArrayView(current.second).sliced(7)))
continue;
method = DigestMd5;
headerVal = current.second.mid(7);
} else if (method < Negotiate && str.startsWith("negotiate")) {

View File

@ -48,6 +48,8 @@ private Q_SLOTS:
void ntlmAuth_data();
void ntlmAuth();
void sha256AndMd5Digest();
void equalityOperators();
void isMethodSupported();
@ -151,6 +153,35 @@ void tst_QAuthenticator::ntlmAuth()
QVERIFY(priv->calculateResponse("GET", "/", "").startsWith("NTLM "));
}
// We don't (currently) support SHA256. So, when presented with the option of MD5 or SHA256,
// we should always pick MD5.
void tst_QAuthenticator::sha256AndMd5Digest()
{
QByteArray md5 = "Digest realm=\"\", nonce=\"\", algorithm=MD5, qop=\"auth\"";
QByteArray sha256 = "Digest realm=\"\", nonce=\"\", algorithm=SHA-256, qop=\"auth\"";
QAuthenticator auth;
auth.setUser("unimportant");
auth.setPassword("unimportant");
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth);
QVERIFY(priv->isMethodSupported("digest")); // sanity check
QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
QList<QPair<QByteArray, QByteArray>> headers;
// Put sha256 first, so that its parsed first...
headers.emplace_back("WWW-Authenticate", sha256);
headers.emplace_back("WWW-Authenticate", md5);
priv->parseHttpResponse(headers, false, QString());
QByteArray response = priv->calculateResponse("GET", "/index", {});
QCOMPARE(priv->phase, QAuthenticatorPrivate::Done);
QVERIFY(!response.isEmpty());
QVERIFY(!response.contains("algorithm=SHA-256"));
QVERIFY(response.contains("algorithm=MD5"));
}
void tst_QAuthenticator::equalityOperators()
{
QAuthenticator s1, s2;