From 154e1884548dd4fba9f6f7b359fb81a101d0feb2 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 16 May 2023 18:58:45 +0300 Subject: Jabber: more OMEMO fixes --- protocols/JabberG/src/jabber_omemo.cpp | 204 +++++++++++------------------- protocols/JabberG/src/jabber_omemo.h | 3 - protocols/JabberG/src/jabber_userinfo.cpp | 5 +- 3 files changed, 74 insertions(+), 138 deletions(-) (limited to 'protocols/JabberG/src') diff --git a/protocols/JabberG/src/jabber_omemo.cpp b/protocols/JabberG/src/jabber_omemo.cpp index b0bef8b94d..bcc336d582 100644 --- a/protocols/JabberG/src/jabber_omemo.cpp +++ b/protocols/JabberG/src/jabber_omemo.cpp @@ -370,12 +370,29 @@ complete: if (proto->m_bUseOMEMO) init(); } - + + int db_enum_settings_trash_cb(const char *szSetting, void *lParam) + { + if (strstr(szSetting, "OmemoPreKey") == szSetting) + ((CJabberProto *)lParam)->delSetting(szSetting); + return 0; + } + void omemo_impl::init() { if (provider) return; + // some db cleanup + if (!proto->getMStringA("OmemoFingerprintOwn").IsEmpty()) { + db_enum_settings(0, &db_enum_settings_trash_cb, proto->m_szModuleName, proto); + + proto->delSetting(CMStringA(FORMAT, "OmemoSignalPreKey_%d512", GetOwnDeviceId())); + proto->delSetting("OmemoSignedPreKeyPublic"); + proto->delSetting("OmemoSignedPreKeySignature"); + proto->delSetting("OmemoFingerprintOwn"); + } + if (!global_context) signal_context_create(&global_context, this); @@ -419,28 +436,6 @@ complete: } } - struct omemo_device - { - uint32_t id; - ratchet_identity_key_pair *device_key; - }; - - omemo_device* omemo_impl::create_device() - { - omemo_device *dev = (omemo_device*)mir_alloc(sizeof(omemo_device)); - for (dev->id = 0; dev->id == 0;) - Utils_GetRandom((void*)&(dev->id), 4); - - dev->id &= ~0x80000000; - - if (signal_protocol_key_helper_generate_identity_key_pair(&(dev->device_key), global_context)) { - proto->debugLogA("Jabber OMEMO: signal_protocol_key_helper_generate_identity_key_pair failed"); - //TODO: handle error - } - - return dev; - } - bool omemo_impl::IsFirstRun() { // TODO: more sanity checks @@ -470,47 +465,42 @@ complete: void omemo_impl::RefreshDevice() { + int32_t dev_id = 0; + ratchet_identity_key_pair *device_key; + // generate and save device id - omemo_device *new_dev = create_device(); - proto->setDword("OmemoDeviceId", new_dev->id); + do { + Utils_GetRandom((void *)&(dev_id), 4); + dev_id &= ~0x80000000; + } while (!dev_id); + proto->setDword("OmemoDeviceId", dev_id); // generate and save device key - ec_public_key *public_key = ratchet_identity_key_pair_get_public(new_dev->device_key); - { - SignalBuffer buf(public_key); - ptrA key(mir_base64_encode(buf.data(), buf.len())); - ptrA fingerprint((char*)mir_alloc((buf.len() * 2) + 1)); - bin2hex(buf.data(), buf.len(), fingerprint); - proto->setString("OmemoFingerprintOwn", fingerprint); - proto->setString("OmemoDevicePublicKey", key); + if (signal_protocol_key_helper_generate_identity_key_pair(&device_key, global_context)) { + proto->debugLogA("Jabber OMEMO: signal_protocol_key_helper_generate_identity_key_pair failed"); + //TODO: handle error } - - proto->setString("OmemoDevicePrivateKey", - SignalBuffer(ratchet_identity_key_pair_get_private(new_dev->device_key)).toBase64()); + proto->setString("OmemoDevicePublicKey", + SignalBuffer(ratchet_identity_key_pair_get_public(device_key)).toBase64()); + proto->setString("OmemoDevicePrivateKey", + SignalBuffer(ratchet_identity_key_pair_get_private(device_key)).toBase64()); // generate and save signed pre key session_signed_pre_key *signed_pre_key; { const unsigned int signed_pre_key_id = 1; - signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, new_dev->device_key, signed_pre_key_id, time(0), global_context); - SIGNAL_UNREF(new_dev->device_key); + signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, device_key, signed_pre_key_id, time(0), global_context); + SIGNAL_UNREF(device_key); SignalBuffer buf(signed_pre_key); - CMStringA szSetting(FORMAT, "%s%u%d", "OmemoSignalSignedPreKey_", proto->m_omemo.GetOwnDeviceId(), signed_pre_key_id); + CMStringA szSetting(FORMAT, "%s%u%d", "OmemoSignalSignedPreKey_", dev_id, signed_pre_key_id); db_set_blob(0, proto->m_szModuleName, szSetting, buf.data(), buf.len()); + SIGNAL_UNREF(signed_pre_key); } - // TODO: store signed_pre_key for libsignal data backend too - // TODO: dynamic signed pre_key id and setting name ? - ec_key_pair *signed_pre_key_pair = session_signed_pre_key_get_key_pair(signed_pre_key); - proto->setString("OmemoSignedPreKeyPublic", SignalBuffer(ec_key_pair_get_public(signed_pre_key_pair)).toBase64()); - - ptrA signature(mir_base64_encode(session_signed_pre_key_get_signature(signed_pre_key), session_signed_pre_key_get_signature_len(signed_pre_key))); - proto->setString("OmemoSignedPreKeySignature", signature); - // generate and save pre keys set signal_protocol_key_helper_pre_key_list_node *keys_root; - signal_protocol_key_helper_generate_pre_keys(&keys_root, 0, 100, global_context); + signal_protocol_key_helper_generate_pre_keys(&keys_root, 1, 100, global_context); CMStringA szSetting; for (auto *it = keys_root; it; it = signal_protocol_key_helper_key_list_next(it)) { session_pre_key *pre_key = signal_protocol_key_helper_key_list_element(it); @@ -519,10 +509,6 @@ complete: SignalBuffer buf(pre_key); szSetting.Format("%s%u%d", "OmemoSignalPreKey_", GetOwnDeviceId(), pre_key_id); db_set_blob(0, proto->m_szModuleName, szSetting, buf.data(), buf.len()); - - ec_key_pair *pre_key_pair = session_pre_key_get_key_pair(pre_key); - szSetting.Format("OmemoPreKey%uPublic", pre_key_id); - proto->setString(szSetting, SignalBuffer(ec_key_pair_get_public(pre_key_pair)).toBase64()); } signal_protocol_key_helper_key_list_free(keys_root); } @@ -786,15 +772,6 @@ complete: CMStringA szSetting(FORMAT, "%s%u%d", "OmemoSignalPreKey_", proto->m_omemo.GetOwnDeviceId(), pre_key_id); db_set_blob(0, proto->m_szModuleName, szSetting, record, (unsigned int)record_len); //TODO: check return value - { //store base64 encoded keys for bundle (private key does not required ?) - session_pre_key *prekey = nullptr; - session_pre_key_deserialize(&prekey, record, record_len, global_context); //TODO: handle error - if (prekey) { - ec_key_pair *pre_key_pair = session_pre_key_get_key_pair(prekey); - szSetting.Format("OmemoPreKey%uPublic", pre_key_id); - proto->setString(szSetting, SignalBuffer(ec_key_pair_get_public(pre_key_pair)).toBase64()); - } - } //TODO: resend bundle ? return 0; @@ -838,12 +815,6 @@ complete: CMStringA szSetting(FORMAT, "%s%u%d", "OmemoSignalPreKey_", proto->m_omemo.GetOwnDeviceId(), pre_key_id); db_unset(0, proto->m_szModuleName, szSetting); - - szSetting.Format("OmemoPreKey%uPublic", pre_key_id); - db_unset(0, proto->m_szModuleName, szSetting); - - szSetting.Format("OmemoPreKey%uPrivate", pre_key_id); - db_unset(0, proto->m_szModuleName, szSetting); return 0; } @@ -1204,19 +1175,10 @@ complete: signal_protocol_key_helper_pre_key_list_node *keys_root; signal_protocol_key_helper_generate_pre_keys(&keys_root, id, 1, global_context); - CMStringA szSetting; - for (auto *it = keys_root; it; it = signal_protocol_key_helper_key_list_next(it)) { - session_pre_key *pre_key = signal_protocol_key_helper_key_list_element(it); - uint32_t pre_key_id = session_pre_key_get_id(pre_key); + SignalBuffer buf(signal_protocol_key_helper_key_list_element(keys_root)); + CMStringA szSetting(FORMAT, "%s%u%d", "OmemoSignalPreKey_", proto->m_omemo.GetOwnDeviceId(), id); + db_set_blob(0, proto->m_szModuleName, szSetting, buf.data(), buf.len()); - SignalBuffer buf(pre_key); - szSetting.Format("%s%u%d", "OmemoSignalPreKey_", proto->m_omemo.GetOwnDeviceId(), pre_key_id); - db_set_blob(0, proto->m_szModuleName, szSetting, buf.data(), buf.len()); - - ec_key_pair *pre_key_pair = session_pre_key_get_key_pair(pre_key); - szSetting.Format("OmemoPreKey%uPublic", pre_key_id); - proto->setString(szSetting, SignalBuffer(ec_key_pair_get_public(pre_key_pair)).toBase64()); - } signal_protocol_key_helper_key_list_free(keys_root); // proto->OmemoAnnounceDevice(); @@ -1589,20 +1551,6 @@ void CJabberProto::OmemoAnnounceDevice(bool include_cache) m_ThreadInfo->send(iq); } -struct db_enum_settings_prekeys_cb_data -{ - std::list settings; //TODO: check this -}; - -int db_enum_settings_prekeys_cb(const char *szSetting, void *lParam) -{ - db_enum_settings_prekeys_cb_data *data = (db_enum_settings_prekeys_cb_data*)lParam; - if (strstr(szSetting, "OmemoPreKey") && strstr(szSetting, "Public")) //TODO: suboptimal code, use different names for simple searching - data->settings.push_back(mir_strdup(szSetting)); - - return 0; -} - void CJabberProto::OmemoSendBundle() { // get own device id @@ -1613,19 +1561,22 @@ void CJabberProto::OmemoSendBundle() XmlNodeIq iq("set", SerialNext()); iq << XATTR("from", JabberStripJid(m_ThreadInfo->fullJID, szBareJid, _countof(szBareJid))); - TiXmlElement *publish_node = iq << XCHILDNS("pubsub", "http://jabber.org/protocol/pubsub") << XCHILD("publish"); - { - char attr_val[128]; - mir_snprintf(attr_val, "%s.bundles:%u", JABBER_FEAT_OMEMO, own_id); - publish_node << XATTR("node", attr_val); - } + TiXmlElement *publish_node = iq << XCHILDNS("pubsub", "http://jabber.org/protocol/pubsub") + << XCHILD("publish") << XATTR("node", CMStringA(FORMAT, "%s.bundles:%u", JABBER_FEAT_OMEMO, own_id)); + TiXmlElement *bundle_node = publish_node << XCHILD("item") << XATTR("id", "current") << XCHILDNS("bundle", JABBER_FEAT_OMEMO); + session_signed_pre_key *sspk; + signal_protocol_signed_pre_key_load_key(m_omemo.store_context, &sspk, 1); + // add signed pre key public - bundle_node << XCHILD("signedPreKeyPublic", ptrA(getUStringA("OmemoSignedPreKeyPublic"))) << XATTRI("signedPreKeyId", 1); + CMStringA spkey_pub(SignalBuffer(ec_key_pair_get_public(session_signed_pre_key_get_key_pair(sspk))).toBase64()); + bundle_node << XCHILD("signedPreKeyPublic", spkey_pub) << XATTRI("signedPreKeyId", 1); // add pre key signature - bundle_node << XCHILD("signedPreKeySignature", ptrA(getUStringA("OmemoSignedPreKeySignature"))); + ptrA signature(mir_base64_encode(session_signed_pre_key_get_signature(sspk), session_signed_pre_key_get_signature_len(sspk))); + bundle_node << XCHILD("signedPreKeySignature", signature); + SIGNAL_UNREF(sspk); // add identity key // it is must be a public key right ?, standart is a bit confusing... @@ -1634,35 +1585,17 @@ void CJabberProto::OmemoSendBundle() // add prekeys TiXmlElement *prekeys_node = XmlAddChild(bundle_node, "prekeys"); - db_enum_settings_prekeys_cb_data *ud = new db_enum_settings_prekeys_cb_data; - db_enum_settings(0, &db_enum_settings_prekeys_cb, m_szModuleName, ud); - for (std::list::iterator i = ud->settings.begin(), end = ud->settings.end(); i != end; i++) { - ptrA val(getUStringA(*i)); - if (val) { - unsigned int key_id = 0; - char *p = *i, buf[5] = { 0 }; - p += strlen("OmemoPreKey"); - int i2 = 0; - for (char c = 0; c != 'P'; i2++, c = p[i2]) - ; - memcpy(buf, p, i2); - buf[i2 + 1] = 0; - key_id = atoi(buf); - prekeys_node << XCHILD("preKeyPublic", val) << XATTRI("preKeyId", key_id); - } - mir_free(*i); - } - ud->settings.clear(); - delete ud; - CMStringA szSetting; - for (int i = 0;; i++) { - szSetting.Format("OmemoPreKey%dPublic", i); - ptrA val(getUStringA(szSetting)); - if (val == nullptr) + for (int i = 1;; i++) { + session_pre_key *pre_key; + signal_protocol_pre_key_load_key(m_omemo.store_context, &pre_key, i); + if (!pre_key) break; - prekeys_node << XCHILD("preKeyPublic", val) << XATTRI("preKeyId", i + 1); + CMStringA val(SignalBuffer(ec_key_pair_get_public(session_pre_key_get_key_pair(pre_key))).toBase64()); + SIGNAL_UNREF(pre_key); + + prekeys_node << XCHILD("preKeyPublic", val) << XATTRI("preKeyId", i); } // send bundle @@ -1794,19 +1727,24 @@ void CJabberProto::OmemoOnIqResultGetBundle(const TiXmlElement *iqNode, CJabberI return; } - auto *prekey_node = XmlFirstChild(prekeys, "preKeyPublic"); - if (!prekey_node) { - debugLogA("Jabber OMEMO: error: device bundle does not contain preKeyPublic node"); + int PKs = XmlGetChildCount(prekeys); + if (PKs < 1) return; - } + uint8_t nPK; + Utils_GetRandom(&nPK, 1); + nPK %= PKs; + + auto prekey_node = TiXmlEnum(prekeys).begin(); + for (int i = 0; i < nPK; i++) + ++prekey_node; - const char *preKeyPublic = prekey_node->GetText(); + const char *preKeyPublic = (*prekey_node)->GetText(); if (!preKeyPublic) { debugLogA("Jabber OMEMO: error: failed to get preKeyPublic data"); return; } - const char *preKeyId = XmlGetAttr(prekey_node, "preKeyId"); + const char *preKeyId = XmlGetAttr(*prekey_node, "preKeyId"); if (!preKeyId) { debugLogA("Jabber OMEMO: error: failed to get preKeyId data"); return; diff --git a/protocols/JabberG/src/jabber_omemo.h b/protocols/JabberG/src/jabber_omemo.h index 34881d3217..747a90ed7e 100644 --- a/protocols/JabberG/src/jabber_omemo.h +++ b/protocols/JabberG/src/jabber_omemo.h @@ -44,8 +44,6 @@ namespace omemo CMStringW FormatFingerprint(const char* pszHexString); CMStringA hex_string(const uint8_t* pData, const size_t length); - struct omemo_device; - struct omemo_impl { omemo_impl(CJabberProto *p); @@ -56,7 +54,6 @@ namespace omemo bool IsFirstRun(); int GetOwnDeviceId(); void RefreshDevice(); - omemo_device* create_device(); bool create_session_store(); bool build_session(MCONTACT hContact, const char *jid, const char *dev_id, const char *key_id, const char *pre_key_public, const char *signed_pre_key_id, const char *signed_pre_key_public, const char *signed_pre_key_signature, const char *identity_key); diff --git a/protocols/JabberG/src/jabber_userinfo.cpp b/protocols/JabberG/src/jabber_userinfo.cpp index 9be0712683..2a334701a4 100644 --- a/protocols/JabberG/src/jabber_userinfo.cpp +++ b/protocols/JabberG/src/jabber_userinfo.cpp @@ -814,8 +814,9 @@ public: if (m_hContact == 0) { // GetOwnDeviceId() creates own keys if they don't exist CMStringA str1(FORMAT, "%d", ppro->m_omemo.GetOwnDeviceId()); - CMStringA str2(ppro->getMStringA("OmemoFingerprintOwn")); - AddListItem(str1, TranslateT("This device"), str2); + size_t fplen; + mir_ptr fp(mir_base64_decode(ptrA(ppro->getStringA("OmemoDevicePublicKey")), &fplen)); + AddListItem(str1, TranslateT("This device"), omemo::hex_string((uint8_t *)fp.get(), fplen)); } for (int i = 0;; i++) { -- cgit v1.2.3