Support "fixed" mac method in verification

pull/1662/head
Nicolas Werner 10 months ago
parent c130e4cf06
commit 1254ac41ce
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
  1. 2
      CMakeLists.txt
  2. 2
      im.nheko.Nheko.yaml
  3. 109
      src/encryption/DeviceVerificationFlow.cpp

@ -603,7 +603,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare( FetchContent_Declare(
MatrixClient MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG 72f9a20c048c3482386b0916ef76fb9f4d890be8 GIT_TAG 03bb6fbd665260faec0148b5bb0bfe484e88581a
) )
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "") set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "") set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")

@ -223,7 +223,7 @@ modules:
buildsystem: cmake-ninja buildsystem: cmake-ninja
name: mtxclient name: mtxclient
sources: sources:
- commit: 72f9a20c048c3482386b0916ef76fb9f4d890be8 - commit: 03bb6fbd665260faec0148b5bb0bfe484e88581a
#tag: v0.9.2 #tag: v0.9.2
type: git type: git
url: https://github.com/Nheko-Reborn/mtxclient.git url: https://github.com/Nheko-Reborn/mtxclient.git

@ -21,15 +21,7 @@
static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes
static constexpr std::string_view mac_method_alg_v1 = "hkdf-hmac-sha256"; static constexpr std::string_view mac_method_alg_v1 = "hkdf-hmac-sha256";
static constexpr std::string_view mac_method_alg_v2 = "hkdf-hmac-sha256.v2";
static mtx::events::msg::KeyVerificationMac
key_verification_mac(mtx::crypto::SAS *sas,
mtx::identifiers::User sender,
const std::string &senderDevice,
mtx::identifiers::User receiver,
const std::string &receiverDevice,
const std::string &transactionId,
std::map<std::string, std::string> keys);
DeviceVerificationFlow::DeviceVerificationFlow(QObject *, DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
DeviceVerificationFlow::Type flow_type, DeviceVerificationFlow::Type flow_type,
@ -113,7 +105,8 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
&ChatPage::receivedDeviceVerificationAccept, &ChatPage::receivedDeviceVerificationAccept,
this, this,
[this](const mtx::events::msg::KeyVerificationAccept &msg) { [this](const mtx::events::msg::KeyVerificationAccept &msg) {
nhlog::crypto()->info("verification: received accept"); nhlog::crypto()->info("verification: received accept with mac methods {}",
fmt::join(msg.message_authentication_code, ", "));
if (msg.transaction_id.has_value()) { if (msg.transaction_id.has_value()) {
if (msg.transaction_id.value() != this->transaction_id) if (msg.transaction_id.value() != this->transaction_id)
return; return;
@ -121,9 +114,10 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
if (msg.relations.references() != this->relation.event_id) if (msg.relations.references() != this->relation.event_id)
return; return;
} }
if ((msg.key_agreement_protocol == "curve25519-hkdf-sha256") && if (msg.key_agreement_protocol == "curve25519-hkdf-sha256" &&
(msg.hash == "sha256") && msg.hash == "sha256" &&
(msg.message_authentication_code == mac_method_alg_v1)) { (msg.message_authentication_code == mac_method_alg_v1 ||
msg.message_authentication_code == mac_method_alg_v2)) {
this->commitment = msg.commitment; this->commitment = msg.commitment;
if (std::find(msg.short_authentication_string.begin(), if (std::find(msg.short_authentication_string.begin(),
msg.short_authentication_string.end(), msg.short_authentication_string.end(),
@ -250,13 +244,13 @@ DeviceVerificationFlow::DeviceVerificationFlow(QObject *,
if (their_keys.self_signing_keys.keys.count(mac.first)) if (their_keys.self_signing_keys.keys.count(mac.first))
key_list[mac.first] = their_keys.self_signing_keys.keys[mac.first]; key_list[mac.first] = their_keys.self_signing_keys.keys[mac.first];
} }
auto macs = key_verification_mac(sas.get(), auto macs = sas->calculate_mac(mac_method,
toClient, toClient,
this->deviceId.toStdString(), this->deviceId.toStdString(),
http::client()->user_id(), http::client()->user_id(),
http::client()->device_id(), http::client()->device_id(),
this->transaction_id, this->transaction_id,
key_list); key_list);
for (const auto &[key, mac] : macs.mac) { for (const auto &[key, mac] : macs.mac) {
if (mac != msg.mac.at(key)) { if (mac != msg.mac.at(key)) {
@ -574,10 +568,21 @@ DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificati
return; return;
} }
nhlog::crypto()->info("verification: received start with mac methods {}",
fmt::join(msg.message_authentication_codes, ", "));
// TODO(Nico): Replace with contains once we use C++23 // TODO(Nico): Replace with contains once we use C++23
if (std::ranges::count(msg.key_agreement_protocols, "curve25519-hkdf-sha256") && if (std::ranges::count(msg.key_agreement_protocols, "curve25519-hkdf-sha256") &&
std::ranges::count(msg.hashes, "sha256") && std::ranges::count(msg.hashes, "sha256")) {
std::ranges::count(msg.message_authentication_codes, mac_method_alg_v1)) { if (std::ranges::count(msg.message_authentication_codes, mac_method_alg_v2)) {
this->mac_method = mac_method_alg_v2;
} else if (std::ranges::count(msg.message_authentication_codes, mac_method_alg_v1)) {
this->mac_method = mac_method_alg_v1;
} else {
this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
return;
}
if (std::ranges::count(msg.short_authentication_string, if (std::ranges::count(msg.short_authentication_string,
mtx::events::msg::SASMethods::Emoji)) { mtx::events::msg::SASMethods::Emoji)) {
this->method = mtx::events::msg::SASMethods::Emoji; this->method = mtx::events::msg::SASMethods::Emoji;
@ -588,6 +593,7 @@ DeviceVerificationFlow::handleStartMessage(const mtx::events::msg::KeyVerificati
this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod); this->cancelVerification(DeviceVerificationFlow::Error::UnknownMethod);
return; return;
} }
if (!sender) if (!sender)
this->canonical_json = nlohmann::json(msg).dump(); this->canonical_json = nlohmann::json(msg).dump();
else { else {
@ -621,6 +627,14 @@ DeviceVerificationFlow::acceptVerificationRequest()
{ {
if (acceptSent) if (acceptSent)
return; return;
if (mac_method.empty()) {
nhlog::crypto()->critical("Ignoring start without mac method set!");
return;
} else {
nhlog::crypto()->debug("Accepted verification using mac_method {}", mac_method);
}
acceptSent = true; acceptSent = true;
mtx::events::msg::KeyVerificationAccept req; mtx::events::msg::KeyVerificationAccept req;
@ -628,7 +642,7 @@ DeviceVerificationFlow::acceptVerificationRequest()
req.method = mtx::events::msg::VerificationMethods::SASv1; req.method = mtx::events::msg::VerificationMethods::SASv1;
req.key_agreement_protocol = "curve25519-hkdf-sha256"; req.key_agreement_protocol = "curve25519-hkdf-sha256";
req.hash = "sha256"; req.hash = "sha256";
req.message_authentication_code = mac_method_alg_v1; req.message_authentication_code = this->mac_method;
if (this->method == mtx::events::msg::SASMethods::Emoji) if (this->method == mtx::events::msg::SASMethods::Emoji)
req.short_authentication_string = {mtx::events::msg::SASMethods::Emoji}; req.short_authentication_string = {mtx::events::msg::SASMethods::Emoji};
else if (this->method == mtx::events::msg::SASMethods::Decimal) else if (this->method == mtx::events::msg::SASMethods::Decimal)
@ -673,7 +687,8 @@ DeviceVerificationFlow::startVerificationRequest()
req.method = mtx::events::msg::VerificationMethods::SASv1; req.method = mtx::events::msg::VerificationMethods::SASv1;
req.key_agreement_protocols = {"curve25519-hkdf-sha256"}; req.key_agreement_protocols = {"curve25519-hkdf-sha256"};
req.hashes = {"sha256"}; req.hashes = {"sha256"};
req.message_authentication_codes = {std::string(mac_method_alg_v1)}; req.message_authentication_codes = {std::string(mac_method_alg_v1),
std::string(mac_method_alg_v2)};
req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal, req.short_authentication_string = {mtx::events::msg::SASMethods::Decimal,
mtx::events::msg::SASMethods::Emoji}; mtx::events::msg::SASMethods::Emoji};
@ -771,36 +786,6 @@ DeviceVerificationFlow::sendVerificationKey()
send(req); send(req);
} }
mtx::events::msg::KeyVerificationMac
key_verification_mac(mtx::crypto::SAS *sas,
mtx::identifiers::User sender,
const std::string &senderDevice,
mtx::identifiers::User receiver,
const std::string &receiverDevice,
const std::string &transactionId,
std::map<std::string, std::string> keys)
{
mtx::events::msg::KeyVerificationMac req;
std::string info = "MATRIX_KEY_VERIFICATION_MAC" + sender.to_string() + senderDevice +
receiver.to_string() + receiverDevice + transactionId;
std::string key_list;
bool first = true;
for (const auto &[key_id, key] : keys) {
req.mac[key_id] = sas->calculate_mac(key, info + key_id);
if (!first)
key_list += ",";
key_list += key_id;
first = false;
}
req.keys = sas->calculate_mac(key_list, info + "KEY_IDS");
return req;
}
//! sends the mac of the keys //! sends the mac of the keys
void void
DeviceVerificationFlow::sendVerificationMac() DeviceVerificationFlow::sendVerificationMac()
@ -809,6 +794,8 @@ DeviceVerificationFlow::sendVerificationMac()
return; return;
macSent = true; macSent = true;
nhlog::crypto()->debug("Sending mac using mac_method {}", mac_method);
std::map<std::string, std::string> key_list; std::map<std::string, std::string> key_list;
key_list["ed25519:" + http::client()->device_id()] = olm::client()->identity_keys().ed25519; key_list["ed25519:" + http::client()->device_id()] = olm::client()->identity_keys().ed25519;
@ -816,13 +803,13 @@ DeviceVerificationFlow::sendVerificationMac()
if (!this->our_trusted_master_key.empty()) if (!this->our_trusted_master_key.empty())
key_list["ed25519:" + our_trusted_master_key] = our_trusted_master_key; key_list["ed25519:" + our_trusted_master_key] = our_trusted_master_key;
mtx::events::msg::KeyVerificationMac req = key_verification_mac(sas.get(), mtx::events::msg::KeyVerificationMac req = sas->calculate_mac(mac_method,
http::client()->user_id(), http::client()->user_id(),
http::client()->device_id(), http::client()->device_id(),
this->toClient, this->toClient,
this->deviceId.toStdString(), this->deviceId.toStdString(),
this->transaction_id, this->transaction_id,
key_list); key_list);
send(req); send(req);

Loading…
Cancel
Save