aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autotests/CMakeLists.txt1
-rw-r--r--autotests/testolmaccount.cpp10
-rw-r--r--autotests/testolmutility.cpp131
-rw-r--r--autotests/testolmutility.h15
-rw-r--r--lib/crypto/qolmaccount.cpp36
-rw-r--r--lib/crypto/qolmaccount.h8
-rw-r--r--lib/crypto/qolmutility.cpp23
-rw-r--r--lib/crypto/qolmutility.h2
8 files changed, 196 insertions, 30 deletions
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
index 6afdf8cc..0354172b 100644
--- a/autotests/CMakeLists.txt
+++ b/autotests/CMakeLists.txt
@@ -16,4 +16,5 @@ if(${PROJECT_NAME}_ENABLE_E2EE)
quotient_add_test(NAME testolmaccount)
quotient_add_test(NAME testgroupsession)
quotient_add_test(NAME testolmsession)
+ quotient_add_test(NAME testolmutility)
endif()
diff --git a/autotests/testolmaccount.cpp b/autotests/testolmaccount.cpp
index 5cb88a99..8d979e0b 100644
--- a/autotests/testolmaccount.cpp
+++ b/autotests/testolmaccount.cpp
@@ -309,11 +309,10 @@ void TestOlmAccount::claimKeys()
deviceKeys[bob->userId()] = QStringList();
auto job = alice->callApi<QueryKeysJob>(deviceKeys);
connect(job, &BaseJob::result, this, [bob, alice, aliceOlm, job, this] {
+ qDebug() << job->jsonData();
auto bobDevices = job->deviceKeys()[bob->userId()];
QVERIFY(bobDevices.size() > 0);
- auto devices = {bob->deviceId()};
-
// Retrieve the identity key for the current device.
auto bobEd25519 =
bobDevices[bob->deviceId()].keys["ed25519:" + bob->deviceId()];
@@ -324,10 +323,9 @@ void TestOlmAccount::claimKeys()
QVERIFY(verifyIdentitySignature(currentDevice, bob->deviceId(), bob->userId()));
QHash<QString, QHash<QString, QString>> oneTimeKeys;
- for (const auto &d : devices) {
- oneTimeKeys[bob->userId()] = QHash<QString, QString>();
- oneTimeKeys[bob->userId()][d] = SignedCurve25519Key;
- }
+ oneTimeKeys[bob->userId()] = QHash<QString, QString>();
+ oneTimeKeys[bob->userId()][bob->deviceId()] = SignedCurve25519Key;
+
auto job = alice->callApi<ClaimKeysJob>(oneTimeKeys);
connect(job, &BaseJob::result, this, [aliceOlm, bob, bobEd25519, job] {
const auto userId = bob->userId();
diff --git a/autotests/testolmutility.cpp b/autotests/testolmutility.cpp
new file mode 100644
index 00000000..cb92a0df
--- /dev/null
+++ b/autotests/testolmutility.cpp
@@ -0,0 +1,131 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "testolmutility.h"
+#include "crypto/qolmaccount.h"
+#include "crypto/qolmutility.h"
+
+using namespace Quotient;
+
+void TestOlmUtility::canonicalJSON()
+{
+ // Examples taken from
+ // https://matrix.org/docs/spec/appendices.html#canonical-json
+ auto data = QJsonDocument::fromJson(QByteArrayLiteral(R"({
+ "auth": {
+ "success": true,
+ "mxid": "@john.doe:example.com",
+ "profile": {
+ "display_name": "John Doe",
+ "three_pids": [{
+ "medium": "email",
+ "address": "john.doe@example.org"
+ }, {
+ "medium": "msisdn",
+ "address": "123456789"
+ }]
+ }}})"));
+
+ QCOMPARE(data.toJson(QJsonDocument::Compact),
+ "{\"auth\":{\"mxid\":\"@john.doe:example.com\",\"profile\":{\"display_name\":\"John "
+ "Doe\",\"three_pids\":[{\"address\":\"john.doe@example.org\",\"medium\":\"email\"},{"
+ "\"address\":\"123456789\",\"medium\":\"msisdn\"}]},\"success\":true}}");
+
+ auto data0 = QJsonDocument::fromJson(QByteArrayLiteral(R"({"b":"2","a":"1"})"));
+ QCOMPARE(data0.toJson(QJsonDocument::Compact), "{\"a\":\"1\",\"b\":\"2\"}");
+
+ auto data1 = QJsonDocument::fromJson(QByteArrayLiteral(R"({ "本": 2, "日": 1 })"));
+ QCOMPARE(data1.toJson(QJsonDocument::Compact), "{\"日\":1,\"本\":2}");
+
+ auto data2 = QJsonDocument::fromJson(QByteArrayLiteral(R"({"a": "\u65E5"})"));
+ QCOMPARE(data2.toJson(QJsonDocument::Compact), "{\"a\":\"日\"}");
+
+ auto data3 = QJsonDocument::fromJson(QByteArrayLiteral(R"({ "a": null })"));
+ QCOMPARE(data3.toJson(QJsonDocument::Compact), "{\"a\":null}");
+}
+
+void TestOlmUtility::verifySignedOneTimeKey()
+{
+ auto aliceOlm = std::make_shared<QOlmAccount>("alice:matrix.org", "aliceDevice");
+ aliceOlm->createNewAccount();
+ aliceOlm->generateOneTimeKeys(1);
+ auto keys = aliceOlm->oneTimeKeys();
+
+ auto firstKey = keys.curve25519().keyValueBegin()->second;
+ auto msgObj = QJsonObject({{"key", firstKey}});
+ auto sig = aliceOlm->sign(msgObj);
+
+ auto msg = QJsonDocument(msgObj).toJson(QJsonDocument::Compact);
+
+ auto utilityBuf = new uint8_t[olm_utility_size()];
+ auto utility = olm_utility(utilityBuf);
+
+ qDebug() << "1" << aliceOlm->identityKeys().ed25519 << msg << QString::fromUtf8(sig);
+
+ QByteArray signatureBuf1(sig.length(), '0');
+ std::copy(sig.begin(), sig.end(), signatureBuf1.begin());
+
+ auto res = olm_ed25519_verify(utility,
+ aliceOlm->identityKeys().ed25519.data(),
+ aliceOlm->identityKeys().ed25519.size(),
+ msg.data(),
+ msg.size(),
+ (void *)sig.data(),
+ sig.size());
+ qDebug() << "2" << aliceOlm->identityKeys().ed25519 << msg << QString::fromUtf8(signatureBuf1);
+
+ QCOMPARE(std::string(olm_utility_last_error(utility)), "SUCCESS");
+ QCOMPARE(res, 0);
+
+ delete[](reinterpret_cast<uint8_t *>(utility));
+
+ QOlmUtility utility2;
+ auto res2 = std::get<bool>(utility2.ed25519Verify(aliceOlm->identityKeys().ed25519, msg, signatureBuf1));
+
+ //QCOMPARE(std::string(olm_utility_last_error(utility)), "SUCCESS");
+ QCOMPARE(res2, true);
+}
+
+void TestOlmUtility::validUploadKeysRequest()
+{
+ const auto userId = QStringLiteral("@alice:matrix.org");
+ const auto deviceId = QStringLiteral("FKALSOCCC");
+
+ auto alice = std::make_shared<QOlmAccount>(userId, deviceId);
+ alice->createNewAccount();
+ alice->generateOneTimeKeys(1);
+
+ auto idSig = alice->signIdentityKeys();
+
+ QJsonObject body
+ {
+ {"algorithms", QJsonArray{"m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"}},
+ {"user_id", userId},
+ {"device_id", deviceId},
+ {"keys",
+ QJsonObject{
+ {QStringLiteral("curve25519:") + deviceId, QString::fromUtf8(alice->identityKeys().curve25519)},
+ {QStringLiteral("ed25519:") + deviceId, QString::fromUtf8(alice->identityKeys().ed25519)}
+ }
+ },
+ {"signatures",
+ QJsonObject{
+ {userId,
+ QJsonObject{
+ {"ed25519:" + deviceId, QString::fromUtf8(idSig)}
+ }
+ }
+ }
+ }
+ };
+
+ DeviceKeys deviceKeys = alice->getDeviceKeys();
+ QCOMPARE(QJsonDocument(toJson(deviceKeys)).toJson(QJsonDocument::Compact),
+ QJsonDocument(body).toJson(QJsonDocument::Compact));
+
+ QVERIFY(verifyIdentitySignature(fromJson<DeviceKeys>(body), deviceId, userId));
+ QVERIFY(verifyIdentitySignature(deviceKeys, deviceId, userId));
+}
+
+QTEST_MAIN(TestOlmUtility)
diff --git a/autotests/testolmutility.h b/autotests/testolmutility.h
new file mode 100644
index 00000000..b30249c8
--- /dev/null
+++ b/autotests/testolmutility.h
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
+//
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include <QtTest/QtTest>
+
+class TestOlmUtility : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void canonicalJSON();
+ void verifySignedOneTimeKey();
+ void validUploadKeysRequest();
+};
diff --git a/lib/crypto/qolmaccount.cpp b/lib/crypto/qolmaccount.cpp
index 750d7318..e27bbee1 100644
--- a/lib/crypto/qolmaccount.cpp
+++ b/lib/crypto/qolmaccount.cpp
@@ -110,10 +110,10 @@ IdentityKeys QOlmAccount::identityKeys() const
QByteArray QOlmAccount::sign(const QByteArray &message) const
{
- const size_t signatureLength = olm_account_signature_length(m_account);
- QByteArray signatureBuffer(signatureLength, '0');
+ QByteArray signatureBuffer(olm_account_signature_length(m_account), '0');
+
const auto error = olm_account_sign(m_account, message.data(), message.length(),
- signatureBuffer.data(), signatureLength);
+ signatureBuffer.data(), signatureBuffer.length());
if (error == olm_error()) {
throw lastError(m_account);
@@ -216,9 +216,8 @@ OlmAccount *Quotient::QOlmAccount::data()
return m_account;
}
-UploadKeysJob *QOlmAccount::createUploadKeyRequest(const OneTimeKeys &oneTimeKeys)
+DeviceKeys QOlmAccount::getDeviceKeys() const
{
-
DeviceKeys deviceKeys;
deviceKeys.userId = m_userId;
deviceKeys.deviceId = m_deviceId;
@@ -231,6 +230,13 @@ UploadKeysJob *QOlmAccount::createUploadKeyRequest(const OneTimeKeys &oneTimeKey
const auto sign = signIdentityKeys();
deviceKeys.signatures[m_userId]["ed25519:" + m_deviceId] = sign;
+ return deviceKeys;
+}
+
+UploadKeysJob *QOlmAccount::createUploadKeyRequest(const OneTimeKeys &oneTimeKeys)
+{
+ auto deviceKeys = getDeviceKeys();
+
if (oneTimeKeys.curve25519().isEmpty()) {
return new UploadKeysJob(deviceKeys);
}
@@ -272,36 +278,34 @@ bool Quotient::verifyIdentitySignature(const DeviceKeys &deviceKeys,
const auto signingKey = deviceKeys.keys[signKeyId];
const auto signature = deviceKeys.signatures[userId][signKeyId];
-
if (signature.isEmpty()) {
+ qDebug() << "signature empty";
return false;
}
return ed25519VerifySignature(signingKey, toJson(deviceKeys), signature);
}
-bool Quotient::ed25519VerifySignature(QString signingKey,
- QJsonObject obj,
- QString signature)
+bool Quotient::ed25519VerifySignature(const QString &signingKey,
+ const QJsonObject &obj,
+ const QString &signature)
{
if (signature.isEmpty()) {
return false;
}
+ QJsonObject obj1 = obj;
- obj.remove("unsigned");
- obj.remove("signatures");
-
- QJsonDocument doc;
- doc.setObject(obj);
- auto canonicalJson = doc.toJson(QJsonDocument::Compact);
+ obj1.remove("unsigned");
+ obj1.remove("signatures");
- qDebug() << canonicalJson;
+ auto canonicalJson = QJsonDocument(obj1).toJson(QJsonDocument::Compact);
QByteArray signingKeyBuf = signingKey.toUtf8();
QOlmUtility utility;
auto signatureBuf = signature.toUtf8();
auto result = utility.ed25519Verify(signingKeyBuf, canonicalJson, signatureBuf);
if (std::holds_alternative<QOlmError>(result)) {
+ qDebug() << "error:" << std::get<QOlmError>(result);
return false;
}
diff --git a/lib/crypto/qolmaccount.h b/lib/crypto/qolmaccount.h
index 09ef623a..de78a8af 100644
--- a/lib/crypto/qolmaccount.h
+++ b/lib/crypto/qolmaccount.h
@@ -72,6 +72,8 @@ public:
UploadKeysJob *createUploadKeyRequest(const OneTimeKeys &oneTimeKeys);
+ DeviceKeys getDeviceKeys() const;
+
//! Remove the one time key used to create the supplied session.
[[nodiscard]] std::optional<QOlmError> removeOneTimeKeys(const std::unique_ptr<QOlmSession> &session) const;
@@ -104,9 +106,9 @@ bool verifyIdentitySignature(const DeviceKeys &deviceKeys,
const QString &userId);
//! checks if the signature is signed by the signing_key
-bool ed25519VerifySignature(QString signingKey,
- QJsonObject obj,
- QString signature);
+bool ed25519VerifySignature(const QString &signingKey,
+ const QJsonObject &obj,
+ const QString &signature);
} // namespace Quotient
diff --git a/lib/crypto/qolmutility.cpp b/lib/crypto/qolmutility.cpp
index 3c6a14c7..ad78a226 100644
--- a/lib/crypto/qolmutility.cpp
+++ b/lib/crypto/qolmutility.cpp
@@ -5,6 +5,7 @@
#ifdef Quotient_E2EE_ENABLED
#include "crypto/qolmutility.h"
#include "olm/olm.h"
+#include <QDebug>
using namespace Quotient;
@@ -19,10 +20,12 @@ QOlmUtility::QOlmUtility()
{
auto utility = new uint8_t[olm_utility_size()];
m_utility = olm_utility(utility);
+ qDebug() << "created";
}
QOlmUtility::~QOlmUtility()
{
+ qDebug() << "deleted";
olm_clear_utility(m_utility);
delete[](reinterpret_cast<uint8_t *>(m_utility));
}
@@ -43,15 +46,27 @@ QString QOlmUtility::sha256Utf8Msg(const QString &message) const
}
std::variant<bool, QOlmError> QOlmUtility::ed25519Verify(const QByteArray &key,
- const QByteArray &message, QByteArray &signature)
+ const QByteArray &message, const QByteArray &signature)
{
- const auto error = olm_ed25519_verify(m_utility, key.data(), key.length(),
- message.data(), message.length(), signature.data(), signature.length());
+ QByteArray signatureBuf(signature.length(), '0');
+ std::copy(signature.begin(), signature.end(), signatureBuf.begin());
+ qDebug() << "3" << key << message << signature;
+
+ const auto ret = olm_ed25519_verify(m_utility, key.data(), key.size(),
+ message.data(), message.size(), (void *)signatureBuf.data(), signatureBuf.size());
+
+ const auto error = ret;
if (error == olm_error()) {
+ qDebug() << QString(olm_utility_last_error(m_utility));
return lastError(m_utility);
}
- return error == 0;
+
+ if (ret != 0) {
+ qDebug() << "ed25519Verify" << ret;
+ return false;
+ }
+ return true;
}
diff --git a/lib/crypto/qolmutility.h b/lib/crypto/qolmutility.h
index 16c330eb..3de09ab4 100644
--- a/lib/crypto/qolmutility.h
+++ b/lib/crypto/qolmutility.h
@@ -36,7 +36,7 @@ public:
//! \param message QByteArray The message that was signed.
//! \param signature QByteArray The signature of the message.
std::variant<bool, QOlmError> ed25519Verify(const QByteArray &key,
- const QByteArray &message, QByteArray &signature);
+ const QByteArray &message, const QByteArray &signature);
private: