Protect against replay attacks

This commit is contained in:
Nicolas Werner 2021-08-07 23:54:35 +02:00
parent 72bbad7485
commit b73bd2859c
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
4 changed files with 29 additions and 3 deletions

View File

@ -158,7 +158,7 @@ Cache::isHiddenEvent(lmdb::txn &txn,
index.session_id = encryptedEvent->content.session_id;
index.sender_key = encryptedEvent->content.sender_key;
auto result = olm::decryptEvent(index, *encryptedEvent);
auto result = olm::decryptEvent(index, *encryptedEvent, true);
if (!result.error)
e = result.event.value();
}
@ -4294,6 +4294,8 @@ to_json(nlohmann::json &obj, const GroupSessionData &msg)
obj["forwarding_curve25519_key_chain"] = msg.forwarding_curve25519_key_chain;
obj["currently"] = msg.currently;
obj["indices"] = msg.indices;
}
void
@ -4307,6 +4309,8 @@ from_json(const nlohmann::json &obj, GroupSessionData &msg)
obj.value("forwarding_curve25519_key_chain", std::vector<std::string>{});
msg.currently = obj.value("currently", SharedWithUsers{});
msg.indices = obj.value("indices", std::map<uint32_t, std::string>());
}
void

View File

@ -50,6 +50,9 @@ struct GroupSessionData
std::string sender_claimed_ed25519_key;
std::vector<std::string> forwarding_curve25519_key_chain;
//! map from index to event_id to check for replay attacks
std::map<uint32_t, std::string> indices;
// who has access to this session.
// Rotate, when a user leaves the room and share, when a user gets added.
SharedWithUsers currently;

View File

@ -1028,7 +1028,8 @@ send_megolm_key_to_device(const std::string &user_id,
DecryptionResult
decryptEvent(const MegolmSessionIndex &index,
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event)
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event,
bool dont_write_db)
{
try {
if (!cache::client()->inboundMegolmSessionExists(index)) {
@ -1043,10 +1044,26 @@ decryptEvent(const MegolmSessionIndex &index,
std::string msg_str;
try {
auto session = cache::client()->getInboundMegolmSession(index);
auto sessionData =
cache::client()->getMegolmSessionData(index).value_or(GroupSessionData{});
auto res =
olm::client()->decrypt_group_message(session.get(), event.content.ciphertext);
msg_str = std::string((char *)res.data.data(), res.data.size());
if (!event.event_id.empty() && event.event_id[0] == '$') {
auto oldIdx = sessionData.indices.find(res.message_index);
if (oldIdx != sessionData.indices.end()) {
if (oldIdx->second != event.event_id)
return {DecryptionErrorCode::ReplayAttack,
std::nullopt,
std::nullopt};
} else if (!dont_write_db) {
sessionData.indices[res.message_index] = event.event_id;
cache::client()->saveInboundMegolmSession(
index, std::move(session), sessionData);
}
}
} catch (const lmdb::error &e) {
return {DecryptionErrorCode::DbError, e.what(), std::nullopt};
} catch (const mtx::crypto::olm_exception &e) {

View File

@ -81,9 +81,11 @@ encrypt_group_message(const std::string &room_id,
const std::string &device_id,
nlohmann::json body);
//! Decrypt an event. Use dont_write_db to prevent db writes when already in a write transaction.
DecryptionResult
decryptEvent(const MegolmSessionIndex &index,
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event);
const mtx::events::EncryptedEvent<mtx::events::msg::Encrypted> &event,
bool dont_write_db = false);
crypto::Trust
calculate_trust(const std::string &user_id, const std::string &curve25519);