[libraries/qca] /: qca-ossl: do not dereference a DH key that failed to generate
Nekto Oleg <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit f2032d5dd5e7470d02ceeca581044b8b99322755 by Nekto Oleg.
Committed on 02/08/2026 at 19:04.
Pushed by aacid into branch 'master'.
qca-ossl: do not dereference a DH key that failed to generate
DHKeyMaker::run() leaves its result null when DH_generate_key() fails.
km_finished() then skips key setup but still reports completion, so
deriveKey() receives a context whose EVP_PKEY is null and hands it to
DH_size(). Check both keys and return an empty SymmetricKey instead,
matching what the function already does when DH_compute_key() fails.
testDH() could not have caught this: its guard required DH to appear in
supportedIOTypes(), which never happens because DH keys are not
serialisable, so the test skipped on every run. Drop that condition - the
test only generates keys - and add coverage for deriveKey() itself, which
was not exercised anywhere.
CCBUG: 482819
M +10 -2 plugins/qca-ossl/qca-ossl.cpp
M +31 -2 unittest/keygenunittest/keygenunittest.cpp
https://invent.kde.org/libraries/qca/-/commit/f2032d5dd5e7470d02ceeca581044b8b99322755
diff --git a/plugins/qca-ossl/qca-ossl.cpp b/plugins/qca-ossl/qca-ossl.cpp
index becfcc31..b20854c4 100644
--- a/plugins/qca-ossl/qca-ossl.cpp
+++ b/plugins/qca-ossl/qca-ossl.cpp
@@ -2721,8 +2721,16 @@ public:
SymmetricKey deriveKey(const PKeyBase &theirs) override
{
- const DH *dh = EVP_PKEY_get0_DH(evp.pkey);
- const DH *them = EVP_PKEY_get0_DH(static_cast<const DHKey *>(&theirs)->evp.pkey);
+ // Not const: OpenSSL 1.1 takes a non-const EVP_PKEY * here.
+ EVP_PKEY *theirPkey = static_cast<const DHKey *>(&theirs)->evp.pkey;
+ if (!evp.pkey || !theirPkey)
+ return SymmetricKey();
+
+ const DH *dh = EVP_PKEY_get0_DH(evp.pkey);
+ const DH *them = EVP_PKEY_get0_DH(theirPkey);
+ if (!dh || !them)
+ return SymmetricKey();
+
const BIGNUM *bnpub_key;
DH_get0_key(them, &bnpub_key, nullptr);
diff --git a/unittest/keygenunittest/keygenunittest.cpp b/unittest/keygenunittest/keygenunittest.cpp
index 385e0e06..8bf2c067 100644
--- a/unittest/keygenunittest/keygenunittest.cpp
+++ b/unittest/keygenunittest/keygenunittest.cpp
@@ -40,6 +40,7 @@ private Q_SLOTS:
void testRSA();
void testDSA();
void testDH();
+ void testDHDeriveKey();
private:
QCA::Initializer *m_init;
@@ -129,8 +130,10 @@ void KeyGenUnitTest::testDH()
QCOMPARE(keygen.isBusy(), false);
QCOMPARE(keygen.blockingEnabled(), true);
- if (!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::DH) ||
- !QCA::PKey::supportedIOTypes().contains(QCA::PKey::DH))
+ // Only key generation is exercised here, so do not require DH to appear in
+ // supportedIOTypes() - DH keys are not serialisable, which made this test
+ // skip unconditionally.
+ if (!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::DH))
QSKIP("DH not supported!");
QCA::DLGroup group = keygen.createDLGroup(QCA::IETF_1024);
@@ -146,6 +149,32 @@ void KeyGenUnitTest::testDH()
QCOMPARE(dh1.bitSize(), 2048);
}
+void KeyGenUnitTest::testDHDeriveKey()
+{
+ QCA::KeyGenerator keygen;
+
+ if (!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::DH))
+ QSKIP("DH not supported!");
+
+ const QCA::DLGroup group = keygen.createDLGroup(QCA::IETF_1024);
+ QCOMPARE(group.isNull(), false);
+
+ QCA::PrivateKey ours = keygen.createDH(group);
+ QCA::PrivateKey theirs = keygen.createDH(group);
+ QCOMPARE(ours.isNull(), false);
+ QCOMPARE(theirs.isNull(), false);
+
+ // Key agreement is what consumers such as the Secret Service DH-AES session
+ // actually use. A key that failed to generate reaches this call looking
+ // valid, so exercise it rather than only inspecting the generated keys.
+ const QCA::SymmetricKey shared = ours.deriveKey(theirs.toPublicKey());
+ QCOMPARE(shared.isEmpty(), false);
+
+ // Both sides must arrive at the same secret.
+ const QCA::SymmetricKey otherSide = theirs.deriveKey(ours.toPublicKey());
+ QCOMPARE(shared, otherSide);
+}
+
QTEST_MAIN(KeyGenUnitTest)
#include "keygenunittest.moc"