diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index 316fbe40..1a3d1432 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -240,7 +240,7 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "They match." - onClicked: { stack.replace(awaitingVerificationConfirmation); flow.acceptDevice(); } + onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); } } } } @@ -379,7 +379,7 @@ ApplicationWindow { Button { Layout.alignment: Qt.AlignRight text: "They match." - onClicked: { stack.replace(awaitingVerificationConfirmation); flow.acceptDevice(); } + onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); } } } } diff --git a/src/ChatPage.h b/src/ChatPage.h index b05a388d..172f74fe 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -175,6 +175,8 @@ signals: void recievedDeviceVerificationKey(const mtx::events::collections::DeviceEvents &message); void recievedDeviceVerificationMac(const mtx::events::collections::DeviceEvents &message); void recievedDeviceVerificationStart(const mtx::events::collections::DeviceEvents &message); + void recievedDeviceVerificationReady(const mtx::events::collections::DeviceEvents &message); + void recievedDeviceVerificationDone(const mtx::events::collections::DeviceEvents &message); private slots: void showUnreadMessageNotification(int count); diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp index 607cc279..0de94c50 100644 --- a/src/DeviceVerificationFlow.cpp +++ b/src/DeviceVerificationFlow.cpp @@ -1,11 +1,10 @@ #include "DeviceVerificationFlow.h" #include "ChatPage.h" #include "Logging.h" +#include "Utils.h" #include -#include // only for debugging #include -#include // only for debugging static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes @@ -28,32 +27,27 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - if (std::find(msg.content.key_agreement_protocols.begin(), - msg.content.key_agreement_protocols.end(), - "curve25519-hkdf-sha256") != - msg.content.key_agreement_protocols.end() && - std::find(msg.content.hashes.begin(), - msg.content.hashes.end(), - "sha256") != msg.content.hashes.end() && + if ((std::find(msg.content.key_agreement_protocols.begin(), + msg.content.key_agreement_protocols.end(), + "curve25519-hkdf-sha256") != + msg.content.key_agreement_protocols.end()) && + (std::find(msg.content.hashes.begin(), + msg.content.hashes.end(), + "sha256") != msg.content.hashes.end()) && (std::find(msg.content.message_authentication_codes.begin(), msg.content.message_authentication_codes.end(), "hmac-sha256") != - msg.content.message_authentication_codes.end() || - std::find(msg.content.message_authentication_codes.begin(), - msg.content.message_authentication_codes.end(), - "hkdf-hmac-sha256") != - msg.content.message_authentication_codes.end()) && - (std::find(msg.content.short_authentication_string.begin(), - msg.content.short_authentication_string.end(), - mtx::events::msg::SASMethods::Decimal) != - msg.content.short_authentication_string.end() || - std::find(msg.content.short_authentication_string.begin(), - msg.content.short_authentication_string.end(), - mtx::events::msg::SASMethods::Emoji) != - msg.content.short_authentication_string.end())) { - this->sendVerificationKey(); // Not sure about this maybe - // those optional methods - this->canonical_json = nlohmann::json(msg); + msg.content.message_authentication_codes.end()) && + ((std::find(msg.content.short_authentication_string.begin(), + msg.content.short_authentication_string.end(), + mtx::events::msg::SASMethods::Decimal) != + msg.content.short_authentication_string.end()) || + (std::find(msg.content.short_authentication_string.begin(), + msg.content.short_authentication_string.end(), + mtx::events::msg::SASMethods::Emoji) != + msg.content.short_authentication_string.end()))) { + this->acceptVerificationRequest(); + this->canonical_json = nlohmann::json(msg.content); } else { this->cancelVerification(); } @@ -67,12 +61,9 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - if ((msg.content.method == - mtx::events::msg::VerificationMethods::SASv1) && - (msg.content.key_agreement_protocol == "curve25519-hkdf-sha256") && + if ((msg.content.key_agreement_protocol == "curve25519-hkdf-sha256") && (msg.content.hash == "sha256") && - ((msg.content.message_authentication_code == "hkdf-hmac-sha256") || - (msg.content.message_authentication_code == "hmac-sha256"))) { + (msg.content.message_authentication_code == "hkdf-hmac-sha256")) { this->commitment = msg.content.commitment; if (std::find(msg.content.short_authentication_string.begin(), msg.content.short_authentication_string.end(), @@ -136,8 +127,7 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) } else { if (this->commitment == mtx::crypto::bin2base64_unpadded(mtx::crypto::sha256( - msg.content.key + - this->canonical_json["content"].dump()))) { + msg.content.key + this->canonical_json.dump()))) { emit this->verificationRequestAccepted(this->method); } else { this->cancelVerification(); @@ -152,7 +142,51 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *) auto msg = std::get>(message); if (msg.content.transaction_id == this->transaction_id) { - std::cout << "Recieved Event Mac" << std::endl; + std::string info = + "MATRIX_KEY_VERIFICATION_MAC" + this->toClient.to_string() + + this->deviceId.toStdString() + + http::client()->user_id().to_string() + + http::client()->device_id() + this->transaction_id; + + std::vector key_list; + std::string key_string; + for (auto mac : msg.content.mac) { + if (mac.second == + this->sas->calculate_mac(this->device_keys[mac.first], + info + mac.first)) { + key_string += mac.first; + } else { + this->cancelVerification(); + return; + } + } + if (msg.content.keys == + this->sas->calculate_mac(key_string, info + "KEY_IDS")) { + this->sendVerificationDone(); + } else { + this->cancelVerification(); + } + } + }); + connect(ChatPage::instance(), + &ChatPage::recievedDeviceVerificationReady, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + if (msg.content.transaction_id == this->transaction_id) { + this->startVerificationRequest(); + } + }); + connect(ChatPage::instance(), + &ChatPage::recievedDeviceVerificationDone, + this, + [this](const mtx::events::collections::DeviceEvents &message) { + auto msg = + std::get>(message); + if (msg.content.transaction_id == this->transaction_id) { + this->startVerificationRequest(); + emit this->deviceVerified(); } }); timeout->start(TIMEOUT); @@ -205,6 +239,34 @@ DeviceVerificationFlow::setUserId(QString userID) { this->userId = userID; this->toClient = mtx::identifiers::parse(userID.toStdString()); + + mtx::responses::QueryKeys res; + mtx::requests::QueryKeys req; + req.device_keys[userID.toStdString()] = {}; + http::client()->query_keys( + req, + [user_id = userID.toStdString(), this](const mtx::responses::QueryKeys &res, + mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("failed to query device keys: {},{}", + err->matrix_error.errcode, + static_cast(err->status_code)); + return; + } + + for (auto x : res.device_keys) { + for (auto y : x.second) { + auto z = y.second; + if (z.user_id == user_id && + z.device_id == this->deviceId.toStdString()) { + for (auto a : z.keys) { + // TODO: Verify Signatures + this->device_keys[a.first] = a.second; + } + } + } + } + }); } void @@ -248,9 +310,6 @@ DeviceVerificationFlow::acceptVerificationRequest() body[this->toClient][this->deviceId.toStdString()] = req; - std::cout << "Accepting the Verification" << std::endl; - std::cout << json(body) << std::endl; - http::client() ->send_to_device( @@ -261,6 +320,50 @@ DeviceVerificationFlow::acceptVerificationRequest() static_cast(err->status_code)); }); } +//! responds verification request +void +DeviceVerificationFlow::sendVerificationReady() +{ + mtx::requests::ToDeviceMessages body; + mtx::events::msg::KeyVerificationReady req; + + req.from_device = http::client()->device_id(); + req.transaction_id = this->transaction_id; + req.methods = {mtx::events::msg::VerificationMethods::SASv1}; + + body[this->toClient][this->deviceId.toStdString()] = req; + + http::client() + ->send_to_device( + this->transaction_id, body, [](mtx::http::RequestErr err) { + if (err) + nhlog::net()->warn("failed to send verification ready: {} {}", + err->matrix_error.error, + static_cast(err->status_code)); + }); +} +//! accepts a verification +void +DeviceVerificationFlow::sendVerificationDone() +{ + mtx::requests::ToDeviceMessages body; + mtx::events::msg::KeyVerificationDone req; + + req.transaction_id = this->transaction_id; + + body[this->toClient][this->deviceId.toStdString()] = req; + + http::client() + ->send_to_device( + this->transaction_id, body, [](mtx::http::RequestErr err) { + if (err) + nhlog::net()->warn("failed to send verification done: {} {}", + err->matrix_error.error, + static_cast(err->status_code)); + }); +} //! starts the verification flow void DeviceVerificationFlow::startVerificationRequest() @@ -373,9 +476,25 @@ DeviceVerificationFlow::sendVerificationMac() mtx::requests::ToDeviceMessages body; mtx::events::msg::KeyVerificationMac req; + std::string info = "MATRIX_KEY_VERIFICATION_MAC" + http::client()->user_id().to_string() + + http::client()->device_id() + this->toClient.to_string() + + this->deviceId.toStdString() + this->transaction_id; + req.transaction_id = this->transaction_id; - // req.mac = ""; - req.keys = ""; + //! this vector stores the type of the key and the key + std::vector> key_list; + key_list.push_back(make_pair("ed25519", olm::client()->identity_keys().ed25519)); + std::sort(key_list.begin(), key_list.end()); + for (auto x : key_list) { + req.mac.insert( + std::make_pair(x.first + ":" + http::client()->device_id(), + this->sas->calculate_mac( + x.second, info + x.first + ":" + http::client()->device_id()))); + req.keys += x.first + ":" + http::client()->device_id() + ","; + } + + req.keys = + this->sas->calculate_mac(req.keys.substr(0, req.keys.size() - 1), info + "KEY_IDS"); body[this->toClient][deviceId.toStdString()] = req; diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h index bddf8edd..81ab9c99 100644 --- a/src/DeviceVerificationFlow.h +++ b/src/DeviceVerificationFlow.h @@ -2,6 +2,7 @@ #include "Olm.h" +#include "mtx/responses/crypto.hpp" #include #include @@ -46,6 +47,10 @@ public: public slots: //! sends a verification request void sendVerificationRequest(); + //! accepts a verification request + void sendVerificationReady(); + //! completes the verification flow(); + void sendVerificationDone(); //! accepts a verification void acceptVerificationRequest(); //! starts the verification flow @@ -78,4 +83,5 @@ private: std::string commitment; mtx::identifiers::User toClient; std::vector sasList; + std::map device_keys; }; diff --git a/src/Olm.cpp b/src/Olm.cpp index 6c1d3fdc..7d7037c9 100644 --- a/src/Olm.cpp +++ b/src/Olm.cpp @@ -9,7 +9,6 @@ #include "MatrixClient.h" #include "Utils.h" #include -#include // only for debugging static const std::string STORAGE_SECRET_KEY("secret"); constexpr auto MEGOLM_ALGO = "m.megolm.v1.aes-sha2"; @@ -79,22 +78,20 @@ handle_to_device_messages(const std::vectorrecievedDeviceVerificationAccept(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationRequest)) { ChatPage::instance()->recievedDeviceVerificationRequest(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationCancel)) { ChatPage::instance()->recievedDeviceVerificationCancel(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationKey)) { ChatPage::instance()->recievedDeviceVerificationKey(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationMac)) { ChatPage::instance()->recievedDeviceVerificationMac(msg); - std::cout << j_msg.dump(2) << std::endl; } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationStart)) { ChatPage::instance()->recievedDeviceVerificationStart(msg); - std::cout << j_msg.dump(2) << std::endl; + } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationReady)) { + ChatPage::instance()->recievedDeviceVerificationReady(msg); + } else if (msg_type == to_string(mtx::events::EventType::KeyVerificationDone)) { + ChatPage::instance()->recievedDeviceVerificationDone(msg); } else { nhlog::crypto()->warn("unhandled event: {}", j_msg.dump(2)); } diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index aaefaed4..7d016cbd 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -183,6 +183,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin msg.content.methods.end(), mtx::events::msg::VerificationMethods::SASv1) != msg.content.methods.end()) { + flow->sendVerificationReady(); emit newDeviceVerificationRequest( std::move(flow), QString::fromStdString(msg.content.transaction_id),