mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 11:00:48 +03:00
Add TOFU (Trust On First Use) mode to encryption
This commit is contained in:
parent
0d0709ccd3
commit
2df4c532ed
2 changed files with 74 additions and 21 deletions
|
@ -3334,23 +3334,27 @@ Cache::statusMessage(const std::string &user_id)
|
||||||
void
|
void
|
||||||
to_json(json &j, const UserKeyCache &info)
|
to_json(json &j, const UserKeyCache &info)
|
||||||
{
|
{
|
||||||
j["device_keys"] = info.device_keys;
|
j["device_keys"] = info.device_keys;
|
||||||
j["master_keys"] = info.master_keys;
|
j["seen_device_keys"] = info.seen_device_keys;
|
||||||
j["user_signing_keys"] = info.user_signing_keys;
|
j["master_keys"] = info.master_keys;
|
||||||
j["self_signing_keys"] = info.self_signing_keys;
|
j["master_key_changed"] = info.master_key_changed;
|
||||||
j["updated_at"] = info.updated_at;
|
j["user_signing_keys"] = info.user_signing_keys;
|
||||||
j["last_changed"] = info.last_changed;
|
j["self_signing_keys"] = info.self_signing_keys;
|
||||||
|
j["updated_at"] = info.updated_at;
|
||||||
|
j["last_changed"] = info.last_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
from_json(const json &j, UserKeyCache &info)
|
from_json(const json &j, UserKeyCache &info)
|
||||||
{
|
{
|
||||||
info.device_keys = j.value("device_keys", std::map<std::string, mtx::crypto::DeviceKeys>{});
|
info.device_keys = j.value("device_keys", std::map<std::string, mtx::crypto::DeviceKeys>{});
|
||||||
info.master_keys = j.value("master_keys", mtx::crypto::CrossSigningKeys{});
|
info.seen_device_keys = j.value("seen_device_keys", std::set<std::string>{});
|
||||||
info.user_signing_keys = j.value("user_signing_keys", mtx::crypto::CrossSigningKeys{});
|
info.master_keys = j.value("master_keys", mtx::crypto::CrossSigningKeys{});
|
||||||
info.self_signing_keys = j.value("self_signing_keys", mtx::crypto::CrossSigningKeys{});
|
info.master_key_changed = j.value("master_key_changed", false);
|
||||||
info.updated_at = j.value("updated_at", "");
|
info.user_signing_keys = j.value("user_signing_keys", mtx::crypto::CrossSigningKeys{});
|
||||||
info.last_changed = j.value("last_changed", "");
|
info.self_signing_keys = j.value("self_signing_keys", mtx::crypto::CrossSigningKeys{});
|
||||||
|
info.updated_at = j.value("updated_at", "");
|
||||||
|
info.last_changed = j.value("last_changed", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<UserKeyCache>
|
std::optional<UserKeyCache>
|
||||||
|
@ -3393,17 +3397,57 @@ Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::Query
|
||||||
for (auto &[user, update] : updates) {
|
for (auto &[user, update] : updates) {
|
||||||
nhlog::db()->debug("Updated user keys: {}", user);
|
nhlog::db()->debug("Updated user keys: {}", user);
|
||||||
|
|
||||||
|
auto updateToWrite = update;
|
||||||
|
|
||||||
std::string_view oldKeys;
|
std::string_view oldKeys;
|
||||||
auto res = db.get(txn, user, oldKeys);
|
auto res = db.get(txn, user, oldKeys);
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
auto last_changed = json::parse(oldKeys).get<UserKeyCache>().last_changed;
|
updateToWrite = json::parse(oldKeys).get<UserKeyCache>();
|
||||||
|
auto last_changed = updateToWrite.last_changed;
|
||||||
// skip if we are tracking this and expect it to be up to date with the last
|
// skip if we are tracking this and expect it to be up to date with the last
|
||||||
// sync token
|
// sync token
|
||||||
if (!last_changed.empty() && last_changed != sync_token)
|
if (!last_changed.empty() && last_changed != sync_token)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!updateToWrite.master_keys.keys.empty() &&
|
||||||
|
update.master_keys.keys != updateToWrite.master_keys.keys) {
|
||||||
|
updateToWrite.master_key_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateToWrite.master_keys = update.master_keys;
|
||||||
|
updateToWrite.self_signing_keys = update.self_signing_keys;
|
||||||
|
updateToWrite.user_signing_keys = update.user_signing_keys;
|
||||||
|
|
||||||
|
// If we have keys for the device already, only update the signatures.
|
||||||
|
for (const auto &[device_id, device_keys] : update.device_keys) {
|
||||||
|
if (updateToWrite.device_keys.count(device_id) &&
|
||||||
|
updateToWrite.device_keys.at(device_id).keys ==
|
||||||
|
device_keys.keys) {
|
||||||
|
updateToWrite.device_keys.at(device_id).signatures =
|
||||||
|
device_keys.signatures;
|
||||||
|
} else {
|
||||||
|
bool keyReused = false;
|
||||||
|
for (const auto &[key_id, key] : device_keys.keys) {
|
||||||
|
(void)key_id;
|
||||||
|
if (updateToWrite.seen_device_keys.count(key)) {
|
||||||
|
keyReused = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!updateToWrite.device_keys.count(device_id) &&
|
||||||
|
!keyReused)
|
||||||
|
updateToWrite.device_keys[device_id] = device_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[key_id, key] : device_keys.keys) {
|
||||||
|
(void)key_id;
|
||||||
|
updateToWrite.seen_device_keys.insert(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
db.put(txn, user, json(update).dump());
|
db.put(txn, user, json(updateToWrite).dump());
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
@ -3715,19 +3759,23 @@ Cache::verificationStatus(const std::string &user_id)
|
||||||
auto master_keys = ourKeys->master_keys.keys;
|
auto master_keys = ourKeys->master_keys.keys;
|
||||||
|
|
||||||
if (user_id != local_user) {
|
if (user_id != local_user) {
|
||||||
if (!verifyAtLeastOneSig(
|
bool theirMasterKeyVerified =
|
||||||
ourKeys->user_signing_keys, master_keys, local_user))
|
verifyAtLeastOneSig(
|
||||||
return status;
|
ourKeys->user_signing_keys, master_keys, local_user) &&
|
||||||
|
verifyAtLeastOneSig(
|
||||||
|
theirKeys->master_keys, ourKeys->user_signing_keys.keys, local_user);
|
||||||
|
|
||||||
if (!verifyAtLeastOneSig(
|
if (theirMasterKeyVerified)
|
||||||
theirKeys->master_keys, ourKeys->user_signing_keys.keys, local_user))
|
trustlevel = crypto::Trust::Verified;
|
||||||
|
else if (!theirKeys->master_key_changed)
|
||||||
|
trustlevel = crypto::Trust::TOFU;
|
||||||
|
else
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
master_keys = theirKeys->master_keys.keys;
|
master_keys = theirKeys->master_keys.keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
trustlevel = crypto::Trust::Verified;
|
status.user_verified = trustlevel;
|
||||||
status.user_verified = crypto::Trust::Verified;
|
|
||||||
|
|
||||||
if (!verifyAtLeastOneSig(theirKeys->self_signing_keys, master_keys, user_id))
|
if (!verifyAtLeastOneSig(theirKeys->self_signing_keys, master_keys, user_id))
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <mtx/events/encrypted.hpp>
|
#include <mtx/events/encrypted.hpp>
|
||||||
#include <mtx/responses/crypto.hpp>
|
#include <mtx/responses/crypto.hpp>
|
||||||
|
@ -123,12 +124,16 @@ struct UserKeyCache
|
||||||
{
|
{
|
||||||
//! Device id to device keys
|
//! Device id to device keys
|
||||||
std::map<std::string, mtx::crypto::DeviceKeys> device_keys;
|
std::map<std::string, mtx::crypto::DeviceKeys> device_keys;
|
||||||
//! corss signing keys
|
//! cross signing keys
|
||||||
mtx::crypto::CrossSigningKeys master_keys, user_signing_keys, self_signing_keys;
|
mtx::crypto::CrossSigningKeys master_keys, user_signing_keys, self_signing_keys;
|
||||||
//! Sync token when nheko last fetched the keys
|
//! Sync token when nheko last fetched the keys
|
||||||
std::string updated_at;
|
std::string updated_at;
|
||||||
//! Sync token when the keys last changed. updated != last_changed means they are outdated.
|
//! Sync token when the keys last changed. updated != last_changed means they are outdated.
|
||||||
std::string last_changed;
|
std::string last_changed;
|
||||||
|
//! if the master key has ever changed
|
||||||
|
bool master_key_changed = false;
|
||||||
|
//! Device keys that were already used at least once
|
||||||
|
std::set<std::string> seen_device_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in a new issue