summary refs log tree commit diff
path: root/src/encryption
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-10-30 00:22:47 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2021-10-30 00:23:07 +0200
commit5688b2647ee686559303203a394bad1a92a744b0 (patch)
treeac0a0082e8edc770eaa278dd712278645c70f892 /src/encryption
parentMerge pull request #777 from LorenDB/focusRoomSearch (diff)
downloadnheko-5688b2647ee686559303203a394bad1a92a744b0.tar.xz
Add self verification after login
Diffstat (limited to 'src/encryption')
-rw-r--r--src/encryption/DeviceVerificationFlow.cpp102
-rw-r--r--src/encryption/DeviceVerificationFlow.h15
-rw-r--r--src/encryption/Olm.cpp63
-rw-r--r--src/encryption/SelfVerificationStatus.cpp47
-rw-r--r--src/encryption/SelfVerificationStatus.h5
-rw-r--r--src/encryption/VerificationManager.cpp11
-rw-r--r--src/encryption/VerificationManager.h1
7 files changed, 179 insertions, 65 deletions
diff --git a/src/encryption/DeviceVerificationFlow.cpp b/src/encryption/DeviceVerificationFlow.cpp

index 2481d4f9..f05d5c9f 100644 --- a/src/encryption/DeviceVerificationFlow.cpp +++ b/src/encryption/DeviceVerificationFlow.cpp
@@ -32,12 +32,15 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow::Type flow_type, TimelineModel *model, QString userID, - QString deviceId_) + std::vector<QString> deviceIds_) : sender(false) , type(flow_type) - , deviceId(deviceId_) + , deviceIds(std::move(deviceIds_)) , model_(model) { + if (deviceIds.size() == 1) + deviceId = deviceIds.front(); + timeout = new QTimer(this); timeout->setSingleShot(true); this->sas = olm::client()->sas_init(); @@ -346,33 +349,62 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *, } }); - connect(ChatPage::instance(), - &ChatPage::receivedDeviceVerificationReady, - this, - [this](const mtx::events::msg::KeyVerificationReady &msg) { - nhlog::crypto()->info("verification: received ready"); - if (!sender) { - if (msg.from_device != http::client()->device_id()) { - error_ = User; - emit errorChanged(); - setState(Failed); - } + connect( + ChatPage::instance(), + &ChatPage::receivedDeviceVerificationReady, + this, + [this](const mtx::events::msg::KeyVerificationReady &msg) { + nhlog::crypto()->info("verification: received ready"); + if (!sender) { + if (msg.from_device != http::client()->device_id()) { + error_ = User; + emit errorChanged(); + setState(Failed); + } - return; - } + return; + } - if (msg.transaction_id.has_value()) { - if (msg.transaction_id.value() != this->transaction_id) - return; - } else if (msg.relations.references()) { - if (msg.relations.references() != this->relation.event_id) - return; - else { - this->deviceId = QString::fromStdString(msg.from_device); - } - } - this->startVerificationRequest(); - }); + if (msg.transaction_id.has_value()) { + if (msg.transaction_id.value() != this->transaction_id) + return; + + if (this->deviceId.isEmpty() && this->deviceIds.size() > 1) { + auto from = QString::fromStdString(msg.from_device); + if (std::find(deviceIds.begin(), deviceIds.end(), from) != deviceIds.end()) { + mtx::events::msg::KeyVerificationCancel req{}; + req.code = "m.user"; + req.reason = "accepted by other device"; + req.transaction_id = this->transaction_id; + mtx::requests::ToDeviceMessages<mtx::events::msg::KeyVerificationCancel> body; + + for (const auto &d : this->deviceIds) { + if (d != from) + body[this->toClient][d.toStdString()] = req; + } + + http::client()->send_to_device( + http::client()->generate_txn_id(), body, [](mtx::http::RequestErr err) { + if (err) + nhlog::net()->warn( + "failed to send verification to_device message: {} {}", + err->matrix_error.error, + static_cast<int>(err->status_code)); + }); + + this->deviceId = from; + this->deviceIds = {from}; + } + } + } else if (msg.relations.references()) { + if (msg.relations.references() != this->relation.event_id) + return; + else { + this->deviceId = QString::fromStdString(msg.from_device); + } + } + this->startVerificationRequest(); + }); connect(ChatPage::instance(), &ChatPage::receivedDeviceVerificationDone, @@ -782,7 +814,7 @@ DeviceVerificationFlow::NewInRoomVerification(QObject *parent_, Type::RoomMsg, timelineModel_, other_user_, - QString::fromStdString(msg.from_device))); + {QString::fromStdString(msg.from_device)})); flow->setEventId(event_id_.toStdString()); @@ -801,7 +833,7 @@ DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_, QString txn_id_) { QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow( - parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device))); + parent_, Type::ToDevice, nullptr, other_user_, {QString::fromStdString(msg.from_device)})); flow->transaction_id = txn_id_.toStdString(); if (std::find(msg.methods.begin(), @@ -819,7 +851,7 @@ DeviceVerificationFlow::NewToDeviceVerification(QObject *parent_, QString txn_id_) { QSharedPointer<DeviceVerificationFlow> flow(new DeviceVerificationFlow( - parent_, Type::ToDevice, nullptr, other_user_, QString::fromStdString(msg.from_device))); + parent_, Type::ToDevice, nullptr, other_user_, {QString::fromStdString(msg.from_device)})); flow->transaction_id = txn_id_.toStdString(); flow->handleStartMessage(msg, ""); @@ -832,15 +864,19 @@ DeviceVerificationFlow::InitiateUserVerification(QObject *parent_, QString userid) { QSharedPointer<DeviceVerificationFlow> flow( - new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, userid, "")); + new DeviceVerificationFlow(parent_, Type::RoomMsg, timelineModel_, userid, {})); flow->sender = true; return flow; } QSharedPointer<DeviceVerificationFlow> -DeviceVerificationFlow::InitiateDeviceVerification(QObject *parent_, QString userid, QString device) +DeviceVerificationFlow::InitiateDeviceVerification(QObject *parent_, + QString userid, + std::vector<QString> devices) { + assert(!devices.empty()); + QSharedPointer<DeviceVerificationFlow> flow( - new DeviceVerificationFlow(parent_, Type::ToDevice, nullptr, userid, device)); + new DeviceVerificationFlow(parent_, Type::ToDevice, nullptr, userid, devices)); flow->sender = true; flow->transaction_id = http::client()->generate_txn_id(); diff --git a/src/encryption/DeviceVerificationFlow.h b/src/encryption/DeviceVerificationFlow.h
index f71fa337..55713def 100644 --- a/src/encryption/DeviceVerificationFlow.h +++ b/src/encryption/DeviceVerificationFlow.h
@@ -120,9 +120,8 @@ public: QString txn_id_); static QSharedPointer<DeviceVerificationFlow> InitiateUserVerification(QObject *parent_, TimelineModel *timelineModel_, QString userid); - static QSharedPointer<DeviceVerificationFlow> InitiateDeviceVerification(QObject *parent, - QString userid, - QString device); + static QSharedPointer<DeviceVerificationFlow> + InitiateDeviceVerification(QObject *parent, QString userid, std::vector<QString> devices); // getters QString state(); @@ -161,7 +160,7 @@ private: DeviceVerificationFlow::Type flow_type, TimelineModel *model, QString userID, - QString deviceId_); + std::vector<QString> deviceIds_); void setState(State state) { if (state != state_) { @@ -196,6 +195,7 @@ private: Type type; mtx::identifiers::User toClient; QString deviceId; + std::vector<QString> deviceIds; // public part of our master key, when trusted or empty std::string our_trusted_master_key; @@ -222,11 +222,12 @@ private: { if (this->type == DeviceVerificationFlow::Type::ToDevice) { mtx::requests::ToDeviceMessages<T> body; - msg.transaction_id = this->transaction_id; - body[this->toClient][deviceId.toStdString()] = msg; + msg.transaction_id = this->transaction_id; + for (const auto &d : deviceIds) + body[this->toClient][d.toStdString()] = msg; http::client()->send_to_device<T>( - this->transaction_id, body, [](mtx::http::RequestErr err) { + http::client()->generate_txn_id(), body, [](mtx::http::RequestErr err) { if (err) nhlog::net()->warn("failed to send verification to_device message: {} {}", err->matrix_error.error, diff --git a/src/encryption/Olm.cpp b/src/encryption/Olm.cpp
index 14c97984..01a16ba7 100644 --- a/src/encryption/Olm.cpp +++ b/src/encryption/Olm.cpp
@@ -1540,6 +1540,7 @@ request_cross_signing_keys() }); }; + request(mtx::secret_storage::secrets::cross_signing_master); request(mtx::secret_storage::secrets::cross_signing_self_signing); request(mtx::secret_storage::secrets::cross_signing_user_signing); request(mtx::secret_storage::secrets::megolm_backup_v1); @@ -1574,36 +1575,52 @@ download_cross_signing_keys() backup_key = secret; http::client()->secret_storage_secret( - secrets::cross_signing_self_signing, - [backup_key](Secret secret, mtx::http::RequestErr err) { - std::optional<Secret> self_signing_key; + secrets::cross_signing_master, [backup_key](Secret secret, mtx::http::RequestErr err) { + std::optional<Secret> master_key; if (!err) - self_signing_key = secret; + master_key = secret; http::client()->secret_storage_secret( - secrets::cross_signing_user_signing, - [backup_key, self_signing_key](Secret secret, mtx::http::RequestErr err) { - std::optional<Secret> user_signing_key; + secrets::cross_signing_self_signing, + [backup_key, master_key](Secret secret, mtx::http::RequestErr err) { + std::optional<Secret> self_signing_key; if (!err) - user_signing_key = secret; + self_signing_key = secret; - std::map<std::string, std::map<std::string, AesHmacSha2EncryptedData>> - secrets; + http::client()->secret_storage_secret( + secrets::cross_signing_user_signing, + [backup_key, self_signing_key, master_key](Secret secret, + mtx::http::RequestErr err) { + std::optional<Secret> user_signing_key; + if (!err) + user_signing_key = secret; - if (backup_key && !backup_key->encrypted.empty()) - secrets[backup_key->encrypted.begin()->first][secrets::megolm_backup_v1] = - backup_key->encrypted.begin()->second; - if (self_signing_key && !self_signing_key->encrypted.empty()) - secrets[self_signing_key->encrypted.begin()->first] - [secrets::cross_signing_self_signing] = - self_signing_key->encrypted.begin()->second; - if (user_signing_key && !user_signing_key->encrypted.empty()) - secrets[user_signing_key->encrypted.begin()->first] - [secrets::cross_signing_user_signing] = - user_signing_key->encrypted.begin()->second; + std::map<std::string, std::map<std::string, AesHmacSha2EncryptedData>> + secrets; - for (const auto &[key, secrets] : secrets) - unlock_secrets(key, secrets); + if (backup_key && !backup_key->encrypted.empty()) + secrets[backup_key->encrypted.begin()->first] + [secrets::megolm_backup_v1] = + backup_key->encrypted.begin()->second; + + if (master_key && !master_key->encrypted.empty()) + secrets[master_key->encrypted.begin()->first] + [secrets::cross_signing_master] = + master_key->encrypted.begin()->second; + + if (self_signing_key && !self_signing_key->encrypted.empty()) + secrets[self_signing_key->encrypted.begin()->first] + [secrets::cross_signing_self_signing] = + self_signing_key->encrypted.begin()->second; + + if (user_signing_key && !user_signing_key->encrypted.empty()) + secrets[user_signing_key->encrypted.begin()->first] + [secrets::cross_signing_user_signing] = + user_signing_key->encrypted.begin()->second; + + for (const auto &[key, secrets] : secrets) + unlock_secrets(key, secrets); + }); }); }); }); diff --git a/src/encryption/SelfVerificationStatus.cpp b/src/encryption/SelfVerificationStatus.cpp
index d75a2109..d4be4442 100644 --- a/src/encryption/SelfVerificationStatus.cpp +++ b/src/encryption/SelfVerificationStatus.cpp
@@ -5,10 +5,12 @@ #include "SelfVerificationStatus.h" #include "Cache_p.h" +#include "ChatPage.h" #include "Logging.h" #include "MainWindow.h" #include "MatrixClient.h" #include "Olm.h" +#include "timeline/TimelineViewManager.h" #include "ui/UIA.h" #include <mtx/responses/common.hpp> @@ -196,6 +198,35 @@ void SelfVerificationStatus::verifyMasterKey() { nhlog::db()->info("Clicked verify master key"); + + const auto this_user = http::client()->user_id().to_string(); + + auto keys = cache::client()->userKeys(this_user); + const auto &sigs = keys->master_keys.signatures[this_user]; + + std::vector<QString> devices; + for (const auto &[dev, sig] : sigs) { + (void)sig; + + auto d = QString::fromStdString(dev); + if (d.startsWith("ed25519:")) { + d.remove("ed25519:"); + + if (keys->device_keys.count(d.toStdString())) + devices.push_back(std::move(d)); + } + } + + if (!devices.empty()) + ChatPage::instance()->timelineManager()->verificationManager()->verifyOneOfDevices( + QString::fromStdString(this_user), std::move(devices)); +} + +void +SelfVerificationStatus::verifyMasterKeyWithPassphrase() +{ + nhlog::db()->info("Clicked verify master key with passphrase"); + olm::download_cross_signing_keys(); } void @@ -207,9 +238,15 @@ SelfVerificationStatus::verifyUnverifiedDevices() void SelfVerificationStatus::invalidate() { + using namespace mtx::secret_storage; + nhlog::db()->info("Invalidating self verification status"); + this->hasSSSS_ = false; + emit hasSSSSChanged(); + auto keys = cache::client()->userKeys(http::client()->user_id().to_string()); - if (!keys) { + if (!keys || keys->device_keys.find(http::client()->device_id()) == keys->device_keys.end()) { + cache::client()->markUserKeysOutOfDate({http::client()->user_id().to_string()}); cache::client()->query_keys(http::client()->user_id().to_string(), [](const UserKeyCache &, mtx::http::RequestErr) {}); return; @@ -223,6 +260,14 @@ SelfVerificationStatus::invalidate() return; } + http::client()->secret_storage_secret(secrets::cross_signing_self_signing, + [this](Secret secret, mtx::http::RequestErr err) { + if (!err && !secret.encrypted.empty()) { + this->hasSSSS_ = true; + emit hasSSSSChanged(); + } + }); + auto verifStatus = cache::client()->verificationStatus(http::client()->user_id().to_string()); if (!verifStatus.user_verified) { diff --git a/src/encryption/SelfVerificationStatus.h b/src/encryption/SelfVerificationStatus.h
index 8cb54df6..b1f315f4 100644 --- a/src/encryption/SelfVerificationStatus.h +++ b/src/encryption/SelfVerificationStatus.h
@@ -11,6 +11,7 @@ class SelfVerificationStatus : public QObject Q_OBJECT Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(bool hasSSSS READ hasSSSS NOTIFY hasSSSSChanged) public: SelfVerificationStatus(QObject *o = nullptr); @@ -25,12 +26,15 @@ public: Q_INVOKABLE void setupCrosssigning(bool useSSSS, QString password, bool useOnlineKeyBackup); Q_INVOKABLE void verifyMasterKey(); + Q_INVOKABLE void verifyMasterKeyWithPassphrase(); Q_INVOKABLE void verifyUnverifiedDevices(); Status status() const { return status_; } + bool hasSSSS() const { return hasSSSS_; } signals: void statusChanged(); + void hasSSSSChanged(); void setupCompleted(); void showRecoveryKey(QString key); void setupFailed(QString message); @@ -40,4 +44,5 @@ public slots: private: Status status_ = AllVerified; + bool hasSSSS_ = true; }; diff --git a/src/encryption/VerificationManager.cpp b/src/encryption/VerificationManager.cpp
index b9b51d35..f4c7ddf2 100644 --- a/src/encryption/VerificationManager.cpp +++ b/src/encryption/VerificationManager.cpp
@@ -120,7 +120,16 @@ VerificationManager::removeVerificationFlow(DeviceVerificationFlow *flow) void VerificationManager::verifyDevice(QString userid, QString deviceid) { - auto flow = DeviceVerificationFlow::InitiateDeviceVerification(this, userid, deviceid); + auto flow = DeviceVerificationFlow::InitiateDeviceVerification(this, userid, {deviceid}); + this->dvList[flow->transactionId()] = flow; + emit newDeviceVerificationRequest(flow.data()); +} + +void +VerificationManager::verifyOneOfDevices(QString userid, std::vector<QString> deviceids) +{ + auto flow = + DeviceVerificationFlow::InitiateDeviceVerification(this, userid, std::move(deviceids)); this->dvList[flow->transactionId()] = flow; emit newDeviceVerificationRequest(flow.data()); } diff --git a/src/encryption/VerificationManager.h b/src/encryption/VerificationManager.h
index d6a39ccf..da646c2f 100644 --- a/src/encryption/VerificationManager.h +++ b/src/encryption/VerificationManager.h
@@ -27,6 +27,7 @@ public: Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow); void verifyUser(QString userid); void verifyDevice(QString userid, QString deviceid); + void verifyOneOfDevices(QString userid, std::vector<QString> deviceids); signals: void newDeviceVerificationRequest(DeviceVerificationFlow *flow);