From 6c9f1ab964776bf4f26a5fd9761f08a3faa06701 Mon Sep 17 00:00:00 2001 From: vae Date: Thu, 22 Jul 2021 23:01:30 +0300 Subject: [PATCH] feat: wip omemo + key publish --- qomemo/qxmpp_omemo_manager.cpp | 40 +++++++++++-- qomemo/qxmpp_omemo_manager.h | 5 +- qomemo/signal/context.cpp | 10 +++- qomemo/signal/context.h | 1 + qomemo/signal/stores/sender_key_store.cpp | 34 +++++------ qomemo/signal/stores/sender_key_store.h | 4 +- qomemo/signal/stores/session_store.cpp | 58 +++++++++---------- qomemo/signal/stores/session_store.h | 4 +- qomemo/signal/stores/signed_pre_key_store.cpp | 48 +++++++-------- qomemo/signal/stores/signed_pre_key_store.h | 3 +- qomemo/signal/stores/store_context.cpp | 14 ++++- qomemo/signal/stores/store_context.h | 18 ++++++ qomemo/variant/conversations.cpp | 4 +- 13 files changed, 147 insertions(+), 96 deletions(-) diff --git a/qomemo/qxmpp_omemo_manager.cpp b/qomemo/qxmpp_omemo_manager.cpp index 788fc96..e70754c 100644 --- a/qomemo/qxmpp_omemo_manager.cpp +++ b/qomemo/qxmpp_omemo_manager.cpp @@ -22,7 +22,8 @@ using namespace QXmpp::Omemo; Manager::Manager() : deviceService{new DeviceService(this)}, - omemoVariant(new Variant::Conversations) { + omemoVariant(new Variant::Conversations), + signalContext(new Signal::Context) { connect(this, &Manager::deviceListReceived, deviceService.get(), &DeviceService::onDeviceListReceived); connect(this, &Manager::deviceListNotFound, deviceService.get(), &DeviceService::onDeviceListNotFound); connect(this, &Manager::deviceListNotFound, this, [this](const QString &jid) { @@ -42,7 +43,7 @@ bool QXmpp::Omemo::Manager::handleStanza(const QDomElement &stanza) { std::cout << str.toStdString(); - if (handleDeviceList(stanza) || handleMissingDeviceList(stanza)) + if (handleDeviceList(stanza) || handleMissingDeviceList(stanza) || handleEncryptedMessage(stanza)) return true; return false; @@ -98,6 +99,19 @@ bool Manager::handleMissingDeviceList(const QDomElement &stanza) { return true; } +bool Manager::handleEncryptedMessage(const QDomElement &stanza) { + if (stanza.tagName() != "message") + return false; + + auto encrypted = stanza.firstChildElement("encrypted"); + if (encrypted.isNull()) + return false; + + qDebug() << "!!!! Got encrypted message!!"; + + return true; +} + void QXmpp::Omemo::Manager::setClient(QXmppClient *client) { QXmppClientExtension::setClient(client); @@ -178,7 +192,7 @@ void Manager::generateDeviceForSelfIfNeeded(const DeviceList ¤tList) { qInfo() << "Generating device"; - auto deviceId = QRandomGenerator64{}.bounded(INT32_MAX); + auto deviceId = QRandomGenerator64::system()->bounded(INT32_MAX); db->saveActiveDeviceId(deviceId); Device device{}; @@ -186,11 +200,11 @@ void Manager::generateDeviceForSelfIfNeeded(const DeviceList ¤tList) { auto updatedList = currentList; - auto bundle = Bundle(); updatedList.devices.push_back(device); - publishDeviceList(updatedList); + + auto bundle = generateAndSaveBundle(deviceId); publishBundle(deviceId, bundle); } @@ -213,6 +227,8 @@ Bundle Manager::generateAndSaveBundle(int deviceId) { database->saveIdentityKey(deviceId, identityKey); database->saveIdentityKeySecret(deviceId, identityKeySecret); + result.ik = identityKey; + // Generate SPK ec_key_pair *ecSpk; curve_generate_key_pair(signalContext->temporaryGetContextUnsafeForRawAccessThatNeedsToBeWrapped(), &ecSpk); @@ -227,11 +243,15 @@ Bundle Manager::generateAndSaveBundle(int deviceId) { signal_buffer_len(spkPublic)); SignedPreKey spk{}; - spk.id = 0; + spk.id = 1; spk.key.publicKey = QByteArray((const char *) signal_buffer_const_data(spkPublic), (int) signal_buffer_len(spkPublic)); spk.key.secretKey = QByteArray((const char *) signal_buffer_const_data(spkSecret), (int) signal_buffer_len(spkSecret)); spk.signature = QByteArray((const char *) signal_buffer_const_data(signature), (int) signal_buffer_len(signature)); + result.spk = spk.key.publicKey; + result.spks = spk.signature; + result.spkId = 1; + // Generate 100 PK for (auto i = 1; i <= 100; ++i) { ec_key_pair *currentPreKey; @@ -247,6 +267,12 @@ Bundle Manager::generateAndSaveBundle(int deviceId) { database->savePreKey(deviceId, i, preKey); + PreKey pk{}; + pk.data = preKey.publicKey; + pk.id = i; + + result.prekeys.append(pk); + signal_buffer_free(pkPublic); signal_buffer_free(pkSecret); SIGNAL_UNREF(currentPreKey); @@ -261,4 +287,6 @@ Bundle Manager::generateAndSaveBundle(int deviceId) { signal_buffer_free(spkPublic); signal_buffer_free(spkSecret); SIGNAL_UNREF(ecSpk); + + return result; } diff --git a/qomemo/qxmpp_omemo_manager.h b/qomemo/qxmpp_omemo_manager.h index 7f04026..03c2aa2 100644 --- a/qomemo/qxmpp_omemo_manager.h +++ b/qomemo/qxmpp_omemo_manager.h @@ -8,6 +8,7 @@ #include "qomemo.h" #include "variant/omemo_base.h" +#include #include namespace Signal { @@ -29,6 +30,8 @@ namespace QXmpp::Omemo { bool handleMissingDeviceList(const QDomElement& stanza); + bool handleEncryptedMessage(const QDomElement& stanza); + QSharedPointer getDeviceService(); Bundle generateAndSaveBundle(int deviceId); @@ -55,7 +58,7 @@ namespace QXmpp::Omemo { private: QSharedPointer deviceService; QScopedPointer omemoVariant; - QScopedPointer signalContext; + std::shared_ptr signalContext; }; } // namespace QXmpp::Omemo diff --git a/qomemo/signal/context.cpp b/qomemo/signal/context.cpp index 6253faa..75d3557 100644 --- a/qomemo/signal/context.cpp +++ b/qomemo/signal/context.cpp @@ -3,12 +3,18 @@ */ #include "context.h" +#include "crypto/crypto.h" using namespace Signal; -Context::Context() {} +Context::Context() : cryptoProvider{ Signal::Crypto::createProvider() } { + signal_context_create(&ctx, nullptr); + signal_context_set_crypto_provider(ctx, &cryptoProvider); +} -Context::~Context() {} +Context::~Context() { + signal_context_destroy(ctx); +} std::unique_ptr Context::generateCurveKeyPair() { auto result = std::unique_ptr(); diff --git a/qomemo/signal/context.h b/qomemo/signal/context.h index b829aca..30941d9 100644 --- a/qomemo/signal/context.h +++ b/qomemo/signal/context.h @@ -25,6 +25,7 @@ namespace Signal { signal_context *temporaryGetContextUnsafeForRawAccessThatNeedsToBeWrapped(); private: + signal_crypto_provider cryptoProvider{}; signal_context *ctx{nullptr}; }; diff --git a/qomemo/signal/stores/sender_key_store.cpp b/qomemo/signal/stores/sender_key_store.cpp index a1cb687..2db5231 100644 --- a/qomemo/signal/stores/sender_key_store.cpp +++ b/qomemo/signal/stores/sender_key_store.cpp @@ -4,26 +4,6 @@ #include "sender_key_store.h" -void Signal::Store::SenderKeyStore::boundToContext( - signal_protocol_store_context *ctx) { - signal_protocol_sender_key_store store{}; - - store.user_data = nullptr; - store.destroy_func = nullptr; - - store.load_sender_key = [](signal_buffer **record, signal_buffer **user_record, - const signal_protocol_sender_key_name *sender_key_name, void *ptr) { - return static_cast(ptr)->loadSenderKey(record, user_record, sender_key_name); - }; - store.store_sender_key = [](const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, - size_t record_len, uint8_t *user_record, size_t user_record_len, void *ptr) { - return static_cast(ptr)->storeSenderKey(sender_key_name, record, record_len, user_record, - user_record_len); - }; - - signal_protocol_store_context_set_sender_key_store(ctx, &store); -} - int Signal::Store::SenderKeyStore::loadSenderKey(signal_buffer **record, signal_buffer **user_record, const signal_protocol_sender_key_name *sender_key_name) { return 0; @@ -34,3 +14,17 @@ int Signal::Store::SenderKeyStore::storeSenderKey(const signal_protocol_sender_k size_t user_record_len) { return 0; } + +void Signal::Store::SenderKeyStore::fillCallbacks(signal_protocol_sender_key_store &store) { + store.user_data = nullptr; + store.destroy_func = nullptr; + store.load_sender_key = [](signal_buffer **record, signal_buffer **user_record, + const signal_protocol_sender_key_name *sender_key_name, void *ptr) { + return static_cast(ptr)->loadSenderKey(record, user_record, sender_key_name); + }; + store.store_sender_key = [](const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, + size_t record_len, uint8_t *user_record, size_t user_record_len, void *ptr) { + return static_cast(ptr)->storeSenderKey(sender_key_name, record, record_len, user_record, + user_record_len); + }; +} diff --git a/qomemo/signal/stores/sender_key_store.h b/qomemo/signal/stores/sender_key_store.h index 904377e..a5abcc6 100644 --- a/qomemo/signal/stores/sender_key_store.h +++ b/qomemo/signal/stores/sender_key_store.h @@ -10,12 +10,12 @@ namespace Signal::Store { class SenderKeyStore { public: - static void boundToContext(signal_protocol_store_context *ctx); - int storeSenderKey(const signal_protocol_sender_key_name *sender_key_name, uint8_t *record, size_t record_len, uint8_t *user_record, size_t user_record_len); int loadSenderKey(signal_buffer **record, signal_buffer **user_record, const signal_protocol_sender_key_name *sender_key_name); + + void fillCallbacks(signal_protocol_sender_key_store &store); }; } // namespace Signal::Store diff --git a/qomemo/signal/stores/session_store.cpp b/qomemo/signal/stores/session_store.cpp index 311b3e6..4b9a5f9 100644 --- a/qomemo/signal/stores/session_store.cpp +++ b/qomemo/signal/stores/session_store.cpp @@ -4,38 +4,6 @@ #include "session_store.h" -void Signal::Store::SessionStore::boundToContext( - signal_protocol_store_context *ctx) { - signal_protocol_session_store store{}; - - store.user_data = nullptr; - store.destroy_func = nullptr; - - store.load_session_func = [](signal_buffer **record, signal_buffer **user_record, - const signal_protocol_address *address, void *ptr) { - return static_cast(ptr)->loadSession(record, user_record, address); - }; - store.get_sub_device_sessions_func = [](signal_int_list **sessions, const char *name, size_t name_len, void *ptr) { - return static_cast(ptr)->getSubDeviceSessions(sessions, name, name_len); - }; - store.store_session_func = [](const signal_protocol_address *address, uint8_t *record, size_t record_len, - uint8_t *user_record, size_t user_record_len, void *ptr) { - return static_cast(ptr)->storeSession(address, record, record_len, user_record, - user_record_len); - }; - store.contains_session_func = [](const signal_protocol_address *address, void *ptr) { - return static_cast(ptr)->containsSession(address); - }; - store.delete_session_func = [](const signal_protocol_address *address, void *ptr) { - return static_cast(ptr)->deleteSession(address); - }; - store.delete_all_sessions_func = [](const char *name, size_t name_len, void *ptr) { - return static_cast(ptr)->deleteAllSessions(name, name_len); - }; - - signal_protocol_store_context_set_session_store(ctx, &store); -} - int Signal::Store::SessionStore::loadSession(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address) { return 0; @@ -61,3 +29,29 @@ int Signal::Store::SessionStore::deleteSession(const signal_protocol_address *ad int Signal::Store::SessionStore::deleteAllSessions(const char *name, size_t name_len) { return 0; } + +void Signal::Store::SessionStore::fillCallbacks(signal_protocol_session_store &store) { + store.user_data = nullptr; + store.destroy_func = nullptr; + store.load_session_func = [](signal_buffer **record, signal_buffer **user_record, + const signal_protocol_address *address, void *ptr) { + return static_cast(ptr)->loadSession(record, user_record, address); + }; + store.get_sub_device_sessions_func = [](signal_int_list **sessions, const char *name, size_t name_len, void *ptr) { + return static_cast(ptr)->getSubDeviceSessions(sessions, name, name_len); + }; + store.store_session_func = [](const signal_protocol_address *address, uint8_t *record, size_t record_len, + uint8_t *user_record, size_t user_record_len, void *ptr) { + return static_cast(ptr)->storeSession(address, record, record_len, user_record, + user_record_len); + }; + store.contains_session_func = [](const signal_protocol_address *address, void *ptr) { + return static_cast(ptr)->containsSession(address); + }; + store.delete_session_func = [](const signal_protocol_address *address, void *ptr) { + return static_cast(ptr)->deleteSession(address); + }; + store.delete_all_sessions_func = [](const char *name, size_t name_len, void *ptr) { + return static_cast(ptr)->deleteAllSessions(name, name_len); + }; +} diff --git a/qomemo/signal/stores/session_store.h b/qomemo/signal/stores/session_store.h index 848e5b8..c773c83 100644 --- a/qomemo/signal/stores/session_store.h +++ b/qomemo/signal/stores/session_store.h @@ -10,8 +10,6 @@ namespace Signal::Store { class SessionStore { public: - static void boundToContext(signal_protocol_store_context *ctx); - int loadSession(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address); int getSubDeviceSessions(signal_int_list **sessions, const char *name, size_t name_len); int storeSession(const signal_protocol_address *address, uint8_t *record, size_t record_len, @@ -19,6 +17,8 @@ namespace Signal::Store { int containsSession(const signal_protocol_address *address); int deleteSession(const signal_protocol_address *address); int deleteAllSessions(const char *name, size_t name_len); + + void fillCallbacks(signal_protocol_session_store &store); }; } // namespace Signal::Store diff --git a/qomemo/signal/stores/signed_pre_key_store.cpp b/qomemo/signal/stores/signed_pre_key_store.cpp index 43bae1e..483465d 100644 --- a/qomemo/signal/stores/signed_pre_key_store.cpp +++ b/qomemo/signal/stores/signed_pre_key_store.cpp @@ -4,33 +4,6 @@ #include "signed_pre_key_store.h" -void Signal::Store::SignedPreKeyStore::boundToContext( - signal_protocol_store_context *ctx) { - signal_protocol_signed_pre_key_store store{}; - - store.user_data = nullptr; - store.destroy_func = nullptr; - - store.load_signed_pre_key = [](signal_buffer **record, uint32_t signed_pre_key_id, void *ptr) { - return static_cast(ptr)->loadSignedPreKey( - record, signed_pre_key_id); - }; - store.store_signed_pre_key = [](uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *ptr) { - return static_cast(ptr)->storeSignedPreKey( - signed_pre_key_id, record, record_len); - }; - store.contains_signed_pre_key = [](uint32_t signed_pre_key_id, void *ptr) { - return static_cast(ptr)->containsSignedPreKey( - signed_pre_key_id); - }; - store.remove_signed_pre_key = [](uint32_t signed_pre_key_id, void *ptr) { - return static_cast(ptr)->removeSignedPreKey( - signed_pre_key_id); - }; - - signal_protocol_store_context_set_signed_pre_key_store(ctx, &store); -} - int Signal::Store::SignedPreKeyStore::loadSignedPreKey(signal_buffer **record, uint32_t signed_pre_key_id) { return 0; } @@ -47,3 +20,24 @@ int Signal::Store::SignedPreKeyStore::containsSignedPreKey(uint32_t signed_pre_k int Signal::Store::SignedPreKeyStore::removeSignedPreKey(uint32_t signed_pre_key_id) { return 0; } + +void Signal::Store::SignedPreKeyStore::fillCallbacks(signal_protocol_signed_pre_key_store &store) { + store.user_data = nullptr; + store.destroy_func = nullptr; + store.load_signed_pre_key = [](signal_buffer **record, uint32_t signed_pre_key_id, void *ptr) { + return static_cast(ptr)->loadSignedPreKey( + record, signed_pre_key_id); + }; + store.store_signed_pre_key = [](uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *ptr) { + return static_cast(ptr)->storeSignedPreKey( + signed_pre_key_id, record, record_len); + }; + store.contains_signed_pre_key = [](uint32_t signed_pre_key_id, void *ptr) { + return static_cast(ptr)->containsSignedPreKey( + signed_pre_key_id); + }; + store.remove_signed_pre_key = [](uint32_t signed_pre_key_id, void *ptr) { + return static_cast(ptr)->removeSignedPreKey( + signed_pre_key_id); + }; +} diff --git a/qomemo/signal/stores/signed_pre_key_store.h b/qomemo/signal/stores/signed_pre_key_store.h index 3f58851..2544741 100644 --- a/qomemo/signal/stores/signed_pre_key_store.h +++ b/qomemo/signal/stores/signed_pre_key_store.h @@ -10,11 +10,12 @@ namespace Signal::Store { class SignedPreKeyStore { public: - static void boundToContext(signal_protocol_store_context *ctx); int loadSignedPreKey(signal_buffer **record, uint32_t signed_pre_key_id); int storeSignedPreKey(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len); int containsSignedPreKey(uint32_t signed_pre_key_id); int removeSignedPreKey(uint32_t signed_pre_key_id); + + void fillCallbacks(signal_protocol_signed_pre_key_store &store); }; } // namespace Signal::Store diff --git a/qomemo/signal/stores/store_context.cpp b/qomemo/signal/stores/store_context.cpp index dd5bb5e..e4dd58a 100644 --- a/qomemo/signal/stores/store_context.cpp +++ b/qomemo/signal/stores/store_context.cpp @@ -4,8 +4,20 @@ #include "store_context.h" -Signal::Store::Context::Context(signal_context *global) { +Signal::Store::Context::Context(signal_context *global) : identityKeyStore(), preKeyStore(), senderKeyStore(), sessionStore(), signedPreKeyStore() { signal_protocol_store_context_create(&ctx, global); + + identityKeyStore->fillCallbacks(iks); + preKeyStore->fillCallbacks(pks); + senderKeyStore->fillCallbacks(sks); + sessionStore->fillCallbacks(ss); + signedPreKeyStore->fillCallbacks(spks); + + signal_protocol_store_context_set_identity_key_store(ctx, &iks); + signal_protocol_store_context_set_pre_key_store(ctx, &pks); + signal_protocol_store_context_set_sender_key_store(ctx, &sks); + signal_protocol_store_context_set_session_store(ctx, &ss); + signal_protocol_store_context_set_signed_pre_key_store(ctx, &spks); } Signal::Store::Context::~Context() { diff --git a/qomemo/signal/stores/store_context.h b/qomemo/signal/stores/store_context.h index 204d9b9..7c1ea55 100644 --- a/qomemo/signal/stores/store_context.h +++ b/qomemo/signal/stores/store_context.h @@ -6,6 +6,12 @@ #include +#include "identity_key_store.h" +#include "pre_key_store.h" +#include "sender_key_store.h" +#include "session_store.h" +#include "signed_pre_key_store.h" + namespace Signal::Store { class Context { @@ -19,6 +25,18 @@ namespace Signal::Store { private: signal_protocol_store_context *ctx{nullptr}; + + signal_protocol_identity_key_store iks{}; + signal_protocol_pre_key_store pks{}; + signal_protocol_sender_key_store sks{}; + signal_protocol_session_store ss{}; + signal_protocol_signed_pre_key_store spks{}; + + std::unique_ptr identityKeyStore; + std::unique_ptr preKeyStore; + std::unique_ptr senderKeyStore; + std::unique_ptr sessionStore; + std::unique_ptr signedPreKeyStore; }; } // namespace Signal::Store diff --git a/qomemo/variant/conversations.cpp b/qomemo/variant/conversations.cpp index 84926cb..1658c37 100644 --- a/qomemo/variant/conversations.cpp +++ b/qomemo/variant/conversations.cpp @@ -103,14 +103,14 @@ QXmppIq Variant::Conversations::bundleSetIq(int deviceId, const Bundle &bundle) auto publish = createElement("publish"); publish.setAttribute( "node", - QString("eu.siacs.conversations.axolotl.bundles:%s").arg(deviceId)); + QString("eu.siacs.conversations.axolotl.bundles:%1").arg(deviceId)); publish.appendChild(item); auto pubSub = createElement("pubsub", "http://jabber.org/protocol/pubsub"); pubSub.appendChild(publish); pubSub.appendChild(createOpenPublishOptions()); - iq.extensions().push_back(pubSub); + iq.setExtensions({ pubSub }); return iq; }