aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-04-16 22:23:53 +0200
committerGitHub <noreply@github.com>2022-04-16 22:23:53 +0200
commit87e8d6d6ef325f176a7d3b5da441569f9b24c847 (patch)
tree671133c8974569b182a27d82d627929addeb5ad6
parentfc3ad90a054e3c674127a0cdd385ddbb98cf2010 (diff)
parentc0c4cd014718fdb54ee691ccbdab46981e15d25f (diff)
downloadlibquotient-87e8d6d6ef325f176a7d3b5da441569f9b24c847.tar.gz
libquotient-87e8d6d6ef325f176a7d3b5da441569f9b24c847.zip
Merge pull request #544 from TobiasFella/checkedkey
Check edKey when receiving an olm message and prepare for MSC 3700
-rw-r--r--lib/connection.cpp120
-rw-r--r--lib/connection.h6
-rw-r--r--lib/database.cpp33
-rw-r--r--lib/database.h7
-rw-r--r--lib/e2ee/qolminboundsession.cpp18
-rw-r--r--lib/e2ee/qolminboundsession.h11
-rw-r--r--lib/room.cpp46
-rw-r--r--lib/room.h2
8 files changed, 175 insertions, 68 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 45888bcb..d99ab64d 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -118,6 +118,8 @@ public:
PicklingMode picklingMode = Unencrypted {};
Database *database = nullptr;
QHash<QString, int> oneTimeKeysCount;
+ std::vector<std::unique_ptr<EncryptedEvent>> pendingEncryptedEvents;
+ void handleEncryptedToDeviceEvent(const EncryptedEvent& event);
// A map from SenderKey to vector of InboundSession
UnorderedMap<QString, std::vector<QOlmSessionPtr>> olmSessions;
@@ -218,7 +220,7 @@ public:
}
q->database()->saveOlmSession(senderKey, session->sessionId(), std::get<QByteArray>(pickleResult), QDateTime::currentDateTime());
}
- QString sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr<QOlmAccount>& olmAccount)
+ std::pair<QString, QString> sessionDecryptPrekey(const QOlmMessage& message, const QString &senderKey, std::unique_ptr<QOlmAccount>& olmAccount)
{
Q_ASSERT(message.type() == QOlmMessage::PreKey);
for(auto& session : olmSessions[senderKey]) {
@@ -228,7 +230,7 @@ public:
const auto result = session->decrypt(message);
if(std::holds_alternative<QString>(result)) {
q->database()->setOlmSessionLastReceived(QString(session->sessionId()), QDateTime::currentDateTime());
- return std::get<QString>(result);
+ return { std::get<QString>(result), session->sessionId() };
} else {
qCDebug(E2EE) << "Failed to decrypt prekey message";
return {};
@@ -247,47 +249,53 @@ public:
qWarning(E2EE) << "Failed to remove one time key for session" << newSession->sessionId();
}
const auto result = newSession->decrypt(message);
+ QString sessionId = newSession->sessionId();
saveSession(newSession, senderKey);
olmSessions[senderKey].push_back(std::move(newSession));
if(std::holds_alternative<QString>(result)) {
- return std::get<QString>(result);
+ return { std::get<QString>(result), sessionId };
} else {
qCDebug(E2EE) << "Failed to decrypt prekey message with new session";
return {};
}
}
- QString sessionDecryptGeneral(const QOlmMessage& message, const QString &senderKey)
+ std::pair<QString, QString> sessionDecryptGeneral(const QOlmMessage& message, const QString &senderKey)
{
Q_ASSERT(message.type() == QOlmMessage::General);
for(auto& session : olmSessions[senderKey]) {
const auto result = session->decrypt(message);
if(std::holds_alternative<QString>(result)) {
q->database()->setOlmSessionLastReceived(QString(session->sessionId()), QDateTime::currentDateTime());
- return std::get<QString>(result);
+ return { std::get<QString>(result), session->sessionId() };
}
}
qCWarning(E2EE) << "Failed to decrypt message";
return {};
}
- QString sessionDecryptMessage(
+ std::pair<QString, QString> sessionDecryptMessage(
const QJsonObject& personalCipherObject, const QByteArray& senderKey, std::unique_ptr<QOlmAccount>& account)
{
QString decrypted;
+ QString olmSessionId;
int type = personalCipherObject.value(TypeKeyL).toInt(-1);
QByteArray body = personalCipherObject.value(BodyKeyL).toString().toLatin1();
if (type == QOlmMessage::PreKey) {
QOlmMessage preKeyMessage(body, QOlmMessage::PreKey);
- decrypted = sessionDecryptPrekey(preKeyMessage, senderKey, account);
+ auto result = sessionDecryptPrekey(preKeyMessage, senderKey, account);
+ decrypted = result.first;
+ olmSessionId = result.second;
} else if (type == QOlmMessage::General) {
QOlmMessage message(body, QOlmMessage::General);
- decrypted = sessionDecryptGeneral(message, senderKey);
+ auto result = sessionDecryptGeneral(message, senderKey);
+ decrypted = result.first;
+ olmSessionId = result.second;
}
- return decrypted;
+ return { decrypted, olmSessionId };
}
#endif
- EventPtr sessionDecryptMessage(const EncryptedEvent& encryptedEvent)
+ std::pair<EventPtr, QString> sessionDecryptMessage(const EncryptedEvent& encryptedEvent)
{
#ifndef Quotient_E2EE_ENABLED
qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off.";
@@ -303,7 +311,7 @@ public:
qCDebug(E2EE) << "Encrypted event is not for the current device";
return {};
}
- const auto decrypted = sessionDecryptMessage(
+ const auto [decrypted, olmSessionId] = sessionDecryptMessage(
personalCipherObject, encryptedEvent.senderKey().toLatin1(), olmAccount);
if (decrypted.isEmpty()) {
qCDebug(E2EE) << "Problem with new session from senderKey:"
@@ -322,9 +330,17 @@ public:
<< "in Olm plaintext";
return {};
}
- //TODO make this do the check mentioned in the E2EE Implementation guide instead
- if (decryptedEvent->fullJson()["keys"]["ed25519"].toString().isEmpty()) {
- qCDebug(E2EE) << "Event does not contain an ed25519 key";
+
+ auto query = database->prepareQuery(QStringLiteral("SELECT edKey FROM tracked_devices WHERE curveKey=:curveKey;"));
+ query.bindValue(":curveKey", encryptedEvent.contentJson()["sender_key"].toString());
+ database->execute(query);
+ if (!query.next()) {
+ qCWarning(E2EE) << "Received olm message from unknown device" << encryptedEvent.contentJson()["sender_key"].toString();
+ return {};
+ }
+ auto edKey = decryptedEvent->fullJson()["keys"]["ed25519"].toString();
+ if (edKey.isEmpty() || query.value(QStringLiteral("edKey")).toString() != edKey) {
+ qCDebug(E2EE) << "Received olm message with invalid ed key";
return {};
}
@@ -346,7 +362,7 @@ public:
return {};
}
- return std::move(decryptedEvent);
+ return { std::move(decryptedEvent), olmSessionId };
#endif // Quotient_E2EE_ENABLED
}
#ifdef Quotient_E2EE_ENABLED
@@ -929,30 +945,46 @@ void Connection::Private::consumeToDeviceEvents(Events&& toDeviceEvents)
qCDebug(E2EE) << "Unsupported algorithm" << event.id() << "for event" << event.algorithm();
return;
}
- const auto decryptedEvent = sessionDecryptMessage(event);
- if(!decryptedEvent) {
- qCWarning(E2EE) << "Failed to decrypt event" << event.id();
+ if (q->isKnownCurveKey(event.senderId(), event.senderKey())) {
+ handleEncryptedToDeviceEvent(event);
return;
}
-
- switchOnType(*decryptedEvent,
- [this, senderKey = event.senderKey()](const RoomKeyEvent& roomKeyEvent) {
- if (auto* detectedRoom = q->room(roomKeyEvent.roomId())) {
- detectedRoom->handleRoomKeyEvent(roomKeyEvent, senderKey);
- } else {
- qCDebug(E2EE) << "Encrypted event room id" << roomKeyEvent.roomId()
- << "is not found at the connection" << q->objectName();
- }
- },
- [](const Event& evt) {
- qCDebug(E2EE) << "Skipping encrypted to_device event, type"
- << evt.matrixType();
- });
+ trackedUsers += event.senderId();
+ outdatedUsers += event.senderId();
+ encryptionUpdateRequired = true;
+ pendingEncryptedEvents.push_back(std::make_unique<EncryptedEvent>(event.fullJson()));
+ }, [](const Event& e){
+ // Unhandled
});
}
#endif
}
+#ifdef Quotient_E2EE_ENABLED
+void Connection::Private::handleEncryptedToDeviceEvent(const EncryptedEvent& event)
+{
+ const auto [decryptedEvent, olmSessionId] = sessionDecryptMessage(event);
+ if(!decryptedEvent) {
+ qCWarning(E2EE) << "Failed to decrypt event" << event.id();
+ return;
+ }
+
+ switchOnType(*decryptedEvent,
+ [this, senderKey = event.senderKey(), &event, olmSessionId = olmSessionId](const RoomKeyEvent& roomKeyEvent) {
+ if (auto* detectedRoom = q->room(roomKeyEvent.roomId())) {
+ detectedRoom->handleRoomKeyEvent(roomKeyEvent, event.senderId(), olmSessionId);
+ } else {
+ qCDebug(E2EE) << "Encrypted event room id" << roomKeyEvent.roomId()
+ << "is not found at the connection" << q->objectName();
+ }
+ },
+ [](const Event& evt) {
+ qCDebug(E2EE) << "Skipping encrypted to_device event, type"
+ << evt.matrixType();
+ });
+}
+#endif
+
void Connection::Private::consumeDevicesList(DevicesList&& devicesList)
{
#ifdef Quotient_E2EE_ENABLED
@@ -2038,6 +2070,15 @@ void Connection::Private::loadOutdatedUserDevices()
outdatedUsers -= user;
}
saveDevicesList();
+
+ for(size_t i = 0; i < pendingEncryptedEvents.size();) {
+ if (q->isKnownCurveKey(pendingEncryptedEvents[i]->fullJson()[SenderKeyL].toString(), pendingEncryptedEvents[i]->contentJson()["sender_key"].toString())) {
+ handleEncryptedToDeviceEvent(*(pendingEncryptedEvents[i].get()));
+ pendingEncryptedEvents.erase(pendingEncryptedEvents.begin() + i);
+ } else {
+ i++;
+ }
+ }
});
}
@@ -2159,14 +2200,14 @@ Database* Connection::database()
return d->database;
}
-UnorderedMap<std::pair<QString, QString>, QOlmInboundGroupSessionPtr> Connection::loadRoomMegolmSessions(Room* room)
+UnorderedMap<QString, QOlmInboundGroupSessionPtr> Connection::loadRoomMegolmSessions(Room* room)
{
return database()->loadMegolmSessions(room->id(), picklingMode());
}
-void Connection::saveMegolmSession(Room* room, const QString& senderKey, QOlmInboundGroupSession* session, const QString& ed25519Key)
+void Connection::saveMegolmSession(Room* room, QOlmInboundGroupSession* session)
{
- database()->saveMegolmSession(room->id(), senderKey, session->sessionId(), ed25519Key, session->pickle(picklingMode()));
+ database()->saveMegolmSession(room->id(), session->sessionId(), session->pickle(picklingMode()), session->senderId(), session->olmSessionId());
}
QStringList Connection::devicesForUser(User* user) const
@@ -2184,4 +2225,13 @@ QString Connection::edKeyForUserDevice(const QString& user, const QString& devic
return d->deviceKeys[user][device].keys["ed25519:" % device];
}
+bool Connection::isKnownCurveKey(const QString& user, const QString& curveKey)
+{
+ auto query = database()->prepareQuery(QStringLiteral("SELECT * FROM tracked_devices WHERE matrixId=:matrixId AND curveKey=:curveKey"));
+ query.bindValue(":matrixId", user);
+ query.bindValue(":curveKey", curveKey);
+ database()->execute(query);
+ return query.next();
+}
+
#endif
diff --git a/lib/connection.h b/lib/connection.h
index a4986b06..29731593 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -317,8 +317,8 @@ public:
#ifdef Quotient_E2EE_ENABLED
QOlmAccount* olmAccount() const;
Database* database();
- UnorderedMap<std::pair<QString, QString>, QOlmInboundGroupSessionPtr> loadRoomMegolmSessions(Room* room);
- void saveMegolmSession(Room* room, const QString& senderKey, QOlmInboundGroupSession* session, const QString& ed25519Key);
+ UnorderedMap<QString, QOlmInboundGroupSessionPtr> loadRoomMegolmSessions(Room* room);
+ void saveMegolmSession(Room* room, QOlmInboundGroupSession* session);
#endif // Quotient_E2EE_ENABLED
Q_INVOKABLE Quotient::SyncJob* syncJob() const;
Q_INVOKABLE int millisToReconnect() const;
@@ -684,6 +684,7 @@ public Q_SLOTS:
QStringList devicesForUser(User* user) const;
QString curveKeyForUserDevice(const QString &user, const QString& device) const;
QString edKeyForUserDevice(const QString& user, const QString& device) const;
+ bool isKnownCurveKey(const QString& user, const QString& curveKey);
#endif
Q_SIGNALS:
/// \brief Initial server resolution has failed
@@ -841,6 +842,7 @@ Q_SIGNALS:
void cacheStateChanged();
void lazyLoadingChanged();
void turnServersChanged(const QJsonObject& servers);
+ void devicesListLoaded();
protected:
/**
diff --git a/lib/database.cpp b/lib/database.cpp
index 70dc1b9b..3189b3f1 100644
--- a/lib/database.cpp
+++ b/lib/database.cpp
@@ -29,6 +29,7 @@ Database::Database(const QString& matrixId, const QString& deviceId, QObject* pa
switch(version()) {
case 0: migrateTo1();
case 1: migrateTo2();
+ case 2: migrateTo3();
}
}
@@ -99,6 +100,7 @@ void Database::migrateTo2()
{
qCDebug(DATABASE) << "Migrating database to version 2";
transaction();
+ //TODO remove this column again - we don't need it after all
execute(QStringLiteral("ALTER TABLE inbound_megolm_sessions ADD ed25519Key TEXT"));
execute(QStringLiteral("ALTER TABLE olm_sessions ADD lastReceived TEXT"));
@@ -111,6 +113,20 @@ void Database::migrateTo2()
commit();
}
+void Database::migrateTo3()
+{
+ qCDebug(DATABASE) << "Migrating database to version 3";
+ transaction();
+
+ execute(QStringLiteral("CREATE TABLE inbound_megolm_sessions_temp AS SELECT roomId, sessionId, pickle FROM inbound_megolm_sessions;"));
+ execute(QStringLiteral("DROP TABLE inbound_megolm_sessions;"));
+ execute(QStringLiteral("ALTER TABLE inbound_megolm_sessions_temp RENAME TO inbound_megolm_sessions;"));
+ execute(QStringLiteral("ALTER TABLE inbound_megolm_sessions ADD olmSessionId TEXT;"));
+ execute(QStringLiteral("ALTER TABLE inbound_megolm_sessions ADD senderId TEXT;"));
+ execute(QStringLiteral("PRAGMA user_version = 3;"));
+ commit();
+}
+
QByteArray Database::accountPickle()
{
auto query = prepareQuery(QStringLiteral("SELECT pickle FROM accounts;"));
@@ -178,33 +194,36 @@ UnorderedMap<QString, std::vector<QOlmSessionPtr>> Database::loadOlmSessions(con
return sessions;
}
-UnorderedMap<std::pair<QString, QString>, QOlmInboundGroupSessionPtr> Database::loadMegolmSessions(const QString& roomId, const PicklingMode& picklingMode)
+UnorderedMap<QString, QOlmInboundGroupSessionPtr> Database::loadMegolmSessions(const QString& roomId, const PicklingMode& picklingMode)
{
auto query = prepareQuery(QStringLiteral("SELECT * FROM inbound_megolm_sessions WHERE roomId=:roomId;"));
query.bindValue(":roomId", roomId);
transaction();
execute(query);
commit();
- UnorderedMap<std::pair<QString, QString>, QOlmInboundGroupSessionPtr> sessions;
+ UnorderedMap<QString, QOlmInboundGroupSessionPtr> sessions;
while (query.next()) {
auto session = QOlmInboundGroupSession::unpickle(query.value("pickle").toByteArray(), picklingMode);
if (std::holds_alternative<QOlmError>(session)) {
qCWarning(E2EE) << "Failed to unpickle megolm session";
continue;
}
- sessions[{query.value("senderKey").toString(), query.value("sessionId").toString()}] = std::move(std::get<QOlmInboundGroupSessionPtr>(session));
+
+ sessions[query.value("sessionId").toString()] = std::move(std::get<QOlmInboundGroupSessionPtr>(session));
+ sessions[query.value("sessionId").toString()]->setOlmSessionId(query.value("olmSessionId").toString());
+ sessions[query.value("sessionId").toString()]->setSenderId(query.value("senderId").toString());
}
return sessions;
}
-void Database::saveMegolmSession(const QString& roomId, const QString& senderKey, const QString& sessionId, const QString& ed25519Key, const QByteArray& pickle)
+void Database::saveMegolmSession(const QString& roomId, const QString& sessionId, const QByteArray& pickle, const QString& senderId, const QString& olmSessionId)
{
- auto query = prepareQuery(QStringLiteral("INSERT INTO inbound_megolm_sessions(roomId, senderKey, sessionId, ed25519Key, pickle) VALUES(:roomId, :senderKey, :sessionId, :ed25519Key, :pickle);"));
+ auto query = prepareQuery(QStringLiteral("INSERT INTO inbound_megolm_sessions(roomId, sessionId, pickle, senderId, olmSessionId) VALUES(:roomId, :sessionId, :pickle, :senderId, :olmSessionId);"));
query.bindValue(":roomId", roomId);
- query.bindValue(":senderKey", senderKey);
query.bindValue(":sessionId", sessionId);
- query.bindValue(":ed25519Key", ed25519Key);
query.bindValue(":pickle", pickle);
+ query.bindValue(":senderId", senderId);
+ query.bindValue(":olmSessionId", olmSessionId);
transaction();
execute(query);
commit();
diff --git a/lib/database.h b/lib/database.h
index cf241dbc..08fe49f3 100644
--- a/lib/database.h
+++ b/lib/database.h
@@ -8,7 +8,6 @@
#include <QtCore/QVector>
#include "e2ee/e2ee.h"
-
namespace Quotient {
class QUOTIENT_API Database : public QObject
{
@@ -29,8 +28,8 @@ public:
void clear();
void saveOlmSession(const QString& senderKey, const QString& sessionId, const QByteArray &pickle, const QDateTime& timestamp);
UnorderedMap<QString, std::vector<QOlmSessionPtr>> loadOlmSessions(const PicklingMode& picklingMode);
- UnorderedMap<std::pair<QString, QString>, QOlmInboundGroupSessionPtr> loadMegolmSessions(const QString& roomId, const PicklingMode& picklingMode);
- void saveMegolmSession(const QString& roomId, const QString& senderKey, const QString& sessionKey, const QString& ed25519Key, const QByteArray& pickle);
+ UnorderedMap<QString, QOlmInboundGroupSessionPtr> loadMegolmSessions(const QString& roomId, const PicklingMode& picklingMode);
+ void saveMegolmSession(const QString& roomId, const QString& sessionId, const QByteArray& pickle, const QString& senderId, const QString& olmSessionId);
void addGroupSessionIndexRecord(const QString& roomId, const QString& sessionId, uint32_t index, const QString& eventId, qint64 ts);
std::pair<QString, qint64> groupSessionIndexRecord(const QString& roomId, const QString& sessionId, qint64 index);
void clearRoomData(const QString& roomId);
@@ -39,6 +38,8 @@ public:
private:
void migrateTo1();
void migrateTo2();
+ void migrateTo3();
+
QString m_matrixId;
};
}
diff --git a/lib/e2ee/qolminboundsession.cpp b/lib/e2ee/qolminboundsession.cpp
index 2e9cc716..60d871ef 100644
--- a/lib/e2ee/qolminboundsession.cpp
+++ b/lib/e2ee/qolminboundsession.cpp
@@ -149,3 +149,21 @@ bool QOlmInboundGroupSession::isVerified() const
{
return olm_inbound_group_session_is_verified(m_groupSession) != 0;
}
+
+QString QOlmInboundGroupSession::olmSessionId() const
+{
+ return m_olmSessionId;
+}
+void QOlmInboundGroupSession::setOlmSessionId(const QString& olmSessionId)
+{
+ m_olmSessionId = olmSessionId;
+}
+
+QString QOlmInboundGroupSession::senderId() const
+{
+ return m_senderId;
+}
+void QOlmInboundGroupSession::setSenderId(const QString& senderId)
+{
+ m_senderId = senderId;
+}
diff --git a/lib/e2ee/qolminboundsession.h b/lib/e2ee/qolminboundsession.h
index 437f753d..32112b97 100644
--- a/lib/e2ee/qolminboundsession.h
+++ b/lib/e2ee/qolminboundsession.h
@@ -41,9 +41,20 @@ public:
QByteArray sessionId() const;
bool isVerified() const;
+ //! The olm session that this session was received from.
+ //! Required to get the device this session is from.
+ QString olmSessionId() const;
+ void setOlmSessionId(const QString& setOlmSessionId);
+
+ //! The sender of this session.
+ QString senderId() const;
+ void setSenderId(const QString& senderId);
+
QOlmInboundGroupSession(OlmInboundGroupSession* session);
private:
OlmInboundGroupSession* m_groupSession;
+ QString m_olmSessionId;
+ QString m_senderId;
};
using QOlmInboundGroupSessionPtr = std::unique_ptr<QOlmInboundGroupSession>;
diff --git a/lib/room.cpp b/lib/room.cpp
index 88aa1d07..183e242a 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -337,27 +337,25 @@ public:
bool isLocalUser(const User* u) const { return u == q->localUser(); }
#ifdef Quotient_E2EE_ENABLED
- // A map from (senderKey, sessionId) to InboundGroupSession
- UnorderedMap<std::pair<QString, QString>, QOlmInboundGroupSessionPtr> groupSessions;
+ UnorderedMap<QString, QOlmInboundGroupSessionPtr> groupSessions;
- bool addInboundGroupSession(QString senderKey, QString sessionId,
- QString sessionKey, QString ed25519Key)
+ bool addInboundGroupSession(QString sessionId, QString sessionKey, const QString& senderId, const QString& olmSessionId)
{
- if (groupSessions.find({senderKey, sessionId}) != groupSessions.end()) {
- qCWarning(E2EE) << "Inbound Megolm session" << sessionId
- << "with senderKey" << senderKey << "already exists";
+ if (groupSessions.find(sessionId) != groupSessions.end()) {
+ qCWarning(E2EE) << "Inbound Megolm session" << sessionId << "already exists";
return false;
}
auto megolmSession = QOlmInboundGroupSession::create(sessionKey.toLatin1());
if (megolmSession->sessionId() != sessionId) {
- qCWarning(E2EE) << "Session ID mismatch in m.room_key event sent "
- "from sender with key" << senderKey;
+ qCWarning(E2EE) << "Session ID mismatch in m.room_key event";
return false;
}
+ megolmSession->setSenderId(senderId);
+ megolmSession->setOlmSessionId(olmSessionId);
qCWarning(E2EE) << "Adding inbound session";
- connection->saveMegolmSession(q, senderKey, megolmSession.get(), ed25519Key);
- groupSessions[{senderKey, sessionId}] = std::move(megolmSession);
+ connection->saveMegolmSession(q, megolmSession.get());
+ groupSessions[sessionId] = std::move(megolmSession);
return true;
}
@@ -365,9 +363,10 @@ public:
const QString& senderKey,
const QString& sessionId,
const QString& eventId,
- QDateTime timestamp)
+ QDateTime timestamp,
+ const QString& senderId)
{
- auto groupSessionIt = groupSessions.find({ senderKey, sessionId });
+ auto groupSessionIt = groupSessions.find(sessionId);
if (groupSessionIt == groupSessions.end()) {
// qCWarning(E2EE) << "Unable to decrypt event" << eventId
// << "The sender's device has not sent us the keys for "
@@ -375,6 +374,10 @@ public:
return QString();
}
auto& senderSession = groupSessionIt->second;
+ if (senderSession->senderId() != senderId) {
+ qCWarning(E2EE) << "Sender from event does not match sender from session";
+ return {};
+ }
auto decryptResult = senderSession->decrypt(cipher);
if(std::holds_alternative<QOlmError>(decryptResult)) {
qCWarning(E2EE) << "Unable to decrypt event" << eventId
@@ -1482,7 +1485,7 @@ RoomEventPtr Room::decryptMessage(const EncryptedEvent& encryptedEvent)
QString decrypted = d->groupSessionDecryptMessage(
encryptedEvent.ciphertext(), encryptedEvent.senderKey(),
encryptedEvent.sessionId(), encryptedEvent.id(),
- encryptedEvent.originTimestamp());
+ encryptedEvent.originTimestamp(), encryptedEvent.senderId());
if (decrypted.isEmpty()) {
// qCWarning(E2EE) << "Encrypted message is empty";
return {};
@@ -1497,22 +1500,25 @@ RoomEventPtr Room::decryptMessage(const EncryptedEvent& encryptedEvent)
}
void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent,
- const QString& senderKey)
+ const QString& senderId,
+ const QString& olmSessionId)
{
#ifndef Quotient_E2EE_ENABLED
Q_UNUSED(roomKeyEvent)
- Q_UNUSED(senderKey)
+ Q_UNUSED(senderId)
+ Q_UNUSED(olmSessionId)
qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off.";
#else // Quotient_E2EE_ENABLED
if (roomKeyEvent.algorithm() != MegolmV1AesSha2AlgoKey) {
qCWarning(E2EE) << "Ignoring unsupported algorithm"
<< roomKeyEvent.algorithm() << "in m.room_key event";
}
- if (d->addInboundGroupSession(senderKey, roomKeyEvent.sessionId(),
- roomKeyEvent.sessionKey(), roomKeyEvent.fullJson()["keys"]["ed25519"].toString())) {
+ if (d->addInboundGroupSession(roomKeyEvent.sessionId(),
+ roomKeyEvent.sessionKey(), senderId, olmSessionId)) {
qCWarning(E2EE) << "added new inboundGroupSession:"
<< d->groupSessions.size();
- for (const auto& eventId : d->undecryptedEvents[roomKeyEvent.sessionId()]) {
+ auto undecryptedEvents = d->undecryptedEvents[roomKeyEvent.sessionId()];
+ for (const auto& eventId : undecryptedEvents) {
const auto pIdx = d->eventsIndex.constFind(eventId);
if (pIdx == d->eventsIndex.cend())
continue;
@@ -1524,7 +1530,7 @@ void Room::handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent,
auto& decryptedEvent = *decrypted;
auto oldEvent = ti.replaceEvent(std::move(decrypted));
decryptedEvent.setOriginalEvent(std::move(oldEvent));
- emit replacedEvent(ti.event(), decrypted->originalEvent());
+ emit replacedEvent(ti.event(), decryptedEvent.originalEvent());
d->undecryptedEvents[roomKeyEvent.sessionId()] -= eventId;
}
}
diff --git a/lib/room.h b/lib/room.h
index 9f70d77a..6ba7feac 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -277,7 +277,7 @@ public:
int timelineSize() const;
bool usesEncryption() const;
RoomEventPtr decryptMessage(const EncryptedEvent& encryptedEvent);
- void handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, const QString& senderKey);
+ void handleRoomKeyEvent(const RoomKeyEvent& roomKeyEvent, const QString& senderId, const QString& olmSessionId);
int joinedCount() const;
int invitedCount() const;
int totalMemberCount() const;