diff options
author | George Hazan <ghazan@miranda.im> | 2022-06-03 13:31:18 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2022-06-03 13:31:18 +0300 |
commit | a8f17cd96a4d9d802f7f425ba4cb9283e262b9cd (patch) | |
tree | 9658d8d011f3521aed544b77635b9f7363ec2402 /protocols | |
parent | 61473c4e162244e1127a4a2639e4e08f0bb7b800 (diff) |
Jabber: better behaviour of OMEMO keys pudlishing
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/JabberG/src/jabber_iqid.cpp | 94 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_omemo.cpp | 113 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_proto.h | 5 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_userinfo.cpp | 89 |
4 files changed, 142 insertions, 159 deletions
diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp index 4056dca118..9060fb3823 100644 --- a/protocols/JabberG/src/jabber_iqid.cpp +++ b/protocols/JabberG/src/jabber_iqid.cpp @@ -51,8 +51,14 @@ void CJabberProto::OnIqResultServerDiscoInfo(const TiXmlElement *iqNode, CJabber if (!mir_strcmp(tmp.category, "pubsub") && !mir_strcmp(tmp.type, "pep")) {
m_bPepSupported = true;
- if (m_bUseOMEMO) // publish ndes, precreation is not required
- OmemoPublishNodes();
+ if (m_bUseOMEMO) {
+ XmlNodeIq iq(AddIQ(&CJabberProto::OnIqResultGetOmemodevicelist, JABBER_IQ_TYPE_GET));
+ iq << XATTR("from", m_ThreadInfo->fullJID);
+ iq << XCHILDNS("pubsub", "http://jabber.org/protocol/pubsub")
+ << XCHILD("items") << XATTR("node", JABBER_FEAT_OMEMO ".devicelist");
+
+ m_ThreadInfo->send(iq);
+ }
EnableMenuItems(true);
RebuildInfoFrame();
@@ -1072,51 +1078,63 @@ void CJabberProto::OnIqResultSetVcard(const TiXmlElement *iqNode, CJabberIqInfo* void CJabberProto::OnIqResultGetOmemodevicelist(const TiXmlElement* iqNode, CJabberIqInfo*)
{
- if (const char *from = XmlGetAttr(iqNode, "from"))
- if (auto *pubsubNode = XmlGetChildByTag(iqNode, "pubsub", "xmlns", JABBER_FEAT_PUBSUB))
- if (auto *itemsNode = XmlGetChildByTag(pubsubNode, "items", "node", JABBER_FEAT_OMEMO ".devicelist"))
- OmemoHandleDeviceList(from, itemsNode);
+ const char *from = XmlGetAttr(iqNode, "from"); //replies for our jid don't contain "from"
+ bool res = false;
+ if (auto *pubsubNode = XmlGetChildByTag(iqNode, "pubsub", "xmlns", JABBER_FEAT_PUBSUB))
+ if (auto *itemsNode = XmlGetChildByTag(pubsubNode, "items", "node", JABBER_FEAT_OMEMO ".devicelist"))
+ res = OmemoHandleDeviceList(from, itemsNode);
+
+ if (!from && !res) {
+ for (int i = 0;; i++) {
+ CMStringA szSetting(FORMAT, "%s%d", omemo::DevicePrefix, i);
+ if (!getDword(szSetting, 0))
+ break;
+
+ delSetting(szSetting);
+ }
+
+ OmemoAnnounceDevice(false); //Publish own device if we can't retrieve up to date list
+ OmemoSendBundle();
+ }
}
void CJabberProto::OnIqResultSetSearch(const TiXmlElement *iqNode, CJabberIqInfo*)
{
- const TiXmlElement *queryNode;
- const char *type;
- int id;
-
debugLogA("<iq/> iqIdGetSearch");
- if ((type = XmlGetAttr(iqNode, "type")) == nullptr) return;
- if ((id = JabberGetPacketID(iqNode)) == -1) return;
- if (!mir_strcmp(type, "result")) {
- if ((queryNode = XmlFirstChild(iqNode, "query")) == nullptr)
- return;
-
- PROTOSEARCHRESULT psr = {};
- psr.cbSize = sizeof(psr);
- for (auto *itemNode : TiXmlFilter(queryNode, "item")) {
- if (auto *jid = XmlGetAttr(itemNode, "jid")) {
- psr.id.w = mir_utf8decodeW(jid);
- debugLogA("Result jid = %s", jid);
- if (auto *p = XmlGetChildText(itemNode, "nick"))
- psr.nick.w = mir_utf8decodeW(p);
- if (auto *p = XmlGetChildText(itemNode, "first"))
- psr.firstName.w = mir_utf8decodeW(p);
- if (auto *p = XmlGetChildText(itemNode, "last"))
- psr.lastName.w = mir_utf8decodeW(p);
- if (auto *p = XmlGetChildText(itemNode, "email"))
- psr.email.w = mir_utf8decodeW(p);
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)id, (LPARAM)&psr);
+ const char *type = XmlGetAttr(iqNode, "type");
+ int id = JabberGetPacketID(iqNode);
+ if (type == nullptr || id == -1)
+ return;
- replaceStrW(psr.id.w, 0);
- replaceStrW(psr.nick.w, 0);
- replaceStrW(psr.firstName.w, 0);
- replaceStrW(psr.lastName.w, 0);
- replaceStrW(psr.email.w, 0);
+ if (!mir_strcmp(type, "result")) {
+ if (auto *queryNode = XmlFirstChild(iqNode, "query")) {
+ PROTOSEARCHRESULT psr = {};
+ psr.cbSize = sizeof(psr);
+ for (auto *itemNode : TiXmlFilter(queryNode, "item")) {
+ if (auto *jid = XmlGetAttr(itemNode, "jid")) {
+ psr.id.w = mir_utf8decodeW(jid);
+ debugLogA("Result jid = %s", jid);
+ if (auto *p = XmlGetChildText(itemNode, "nick"))
+ psr.nick.w = mir_utf8decodeW(p);
+ if (auto *p = XmlGetChildText(itemNode, "first"))
+ psr.firstName.w = mir_utf8decodeW(p);
+ if (auto *p = XmlGetChildText(itemNode, "last"))
+ psr.lastName.w = mir_utf8decodeW(p);
+ if (auto *p = XmlGetChildText(itemNode, "email"))
+ psr.email.w = mir_utf8decodeW(p);
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)id, (LPARAM)&psr);
+
+ replaceStrW(psr.id.w, 0);
+ replaceStrW(psr.nick.w, 0);
+ replaceStrW(psr.firstName.w, 0);
+ replaceStrW(psr.lastName.w, 0);
+ replaceStrW(psr.email.w, 0);
+ }
}
- }
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
+ }
}
else if (!mir_strcmp(type, "error"))
ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
diff --git a/protocols/JabberG/src/jabber_omemo.cpp b/protocols/JabberG/src/jabber_omemo.cpp index 490d370ce0..9a31f43009 100644 --- a/protocols/JabberG/src/jabber_omemo.cpp +++ b/protocols/JabberG/src/jabber_omemo.cpp @@ -36,22 +36,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "..\..\libs\libsignal\src\session_cipher.h"
#include "..\..\libs\libsignal\src\protocol.h"
-namespace utils {
- // code from http://stackoverflow.com/questions/3368883/how-does-this-size-of-array-template-function-work
- template <std::size_t N>
- struct type_of_size
- {
- typedef char type[N];
- };
-
- template <typename T, std::size_t Size>
- typename type_of_size<Size>::type& sizeof_array_helper(T(&)[Size]);
-
- #define _countof_portable(pArray) sizeof(sizeof_array_helper(pArray))
-}
-
-using namespace utils;
-
namespace omemo
{
int random_func(uint8_t *data, size_t len, void * /*user_data*/)
@@ -1650,39 +1634,36 @@ bool CJabberProto::OmemoHandleMessage(const TiXmlElement *node, const char *jid, return true;
}
-void CJabberProto::OmemoHandleDeviceList(const char *from, const TiXmlElement *node)
+bool CJabberProto::OmemoHandleDeviceList(const char *from, const TiXmlElement *node)
{
if (!node)
- return;
-
- MCONTACT hContact = HContactFromJID(from);
+ return false;
+
node = XmlFirstChild(node, "item"); //get <item> node
if (!node) {
debugLogA("Jabber OMEMO: error: omemo devicelist does not have <item> node");
- return;
+ return false;
}
node = XmlGetChildByTag(node, "list", "xmlns", JABBER_FEAT_OMEMO); //<list xmlns = 'urn:xmpp:omemo:0'>
if (!node) {
debugLogA("Jabber OMEMO: error: omemo devicelist does not have <list> node");
- return;
+ return false;
}
CMStringA szSetting;
- bool own_jid = false;
- if (strstr(m_ThreadInfo->fullJID, from))
- own_jid = true;
-
- if (own_jid) {
+ if (from == nullptr) {
//check if our device exist
bool own_device_listed = false;
uint32_t own_id = m_omemo.GetOwnDeviceId();
int i = 0;
for (auto *list_item : TiXmlFilter(node, "device")) {
uint32_t current_id = list_item->IntAttribute("id");
- if (current_id == own_id)
+ if (current_id == own_id) {
own_device_listed = true;
- szSetting.Format("OmemoDeviceId%d", i++);
- setDword(szSetting, current_id);
+ } else {
+ szSetting.Format("OmemoDeviceId%d", i++);
+ setDword(szSetting, current_id);
+ }
}
uint32_t val = 0;
@@ -1694,11 +1675,17 @@ void CJabberProto::OmemoHandleDeviceList(const char *from, const TiXmlElement *n szSetting.Format("OmemoDeviceId%d", i);
val = getDword(szSetting, 0);
}
- if (!own_device_listed)
- OmemoAnnounceDevice();
+ if (!own_device_listed) {
+ OmemoAnnounceDevice(true);
+ OmemoSendBundle();
+ }
}
else {
// store device id's
+ MCONTACT hContact = HContactFromJID(from);
+ if (!hContact)
+ return true; //unknown jid
+
int i = 0;
for (auto *list_item : TiXmlFilter(node, "device")) {
uint32_t current_id = list_item->IntAttribute("id");
@@ -1715,45 +1702,39 @@ void CJabberProto::OmemoHandleDeviceList(const char *from, const TiXmlElement *n val = getDword(hContact, szSetting, 0);
}
}
+
+ return true;
}
-void CJabberProto::OmemoAnnounceDevice()
+void CJabberProto::OmemoAnnounceDevice(bool include_cache)
{
// check "OmemoDeviceId%d" for own id and send updated list if not exist
unsigned int own_id = m_omemo.GetOwnDeviceId();
- CMStringA szSetting;
- for (int i = 0;; ++i) {
- szSetting.Format("OmemoDeviceId%d", i);
- uint32_t val = getDword(szSetting);
- if (val == 0)
- break;
- if (val == own_id)
- return; // nothing to do, list is fresh enough
- }
-
// add own device id
// construct node
char szBareJid[JABBER_MAX_JID_LEN];
XmlNodeIq iq("set", SerialNext());
- iq << XATTR("from", JabberStripJid(m_ThreadInfo->fullJID, szBareJid, _countof_portable(szBareJid)));
+ iq << XATTR("from", JabberStripJid(m_ThreadInfo->fullJID, szBareJid, _countof(szBareJid)));
TiXmlElement *publish_node = iq << XCHILDNS("pubsub", "http://jabber.org/protocol/pubsub")
<< XCHILD("publish") << XATTR("node", JABBER_FEAT_OMEMO ".devicelist");
TiXmlElement *list_node = publish_node << XCHILD("item") << XATTR ("id", "current")
<< XCHILDNS("list", JABBER_FEAT_OMEMO);
+ if (include_cache) { //use cache only if it is fresh
+ CMStringA szSetting;
+ for (int i = 0; ; ++i) {
+ szSetting.Format("OmemoDeviceId%d", i);
+ uint32_t val = getDword(szSetting);
+ if (val == 0)
+ break;
- for (int i = 0; ; ++i) {
- szSetting.Format("OmemoDeviceId%d", i);
- uint32_t val = getDword(szSetting);
- if (val == 0)
- break;
-
- list_node << XCHILD("device") << XATTRI64("id", val);
+ list_node << XCHILD("device") << XATTRI64("id", val);
+ }
}
list_node << XCHILD("device") << XATTRI64("id", own_id);
// send device list back
- //TODOL handle response
+ // TODO handle response
m_ThreadInfo->send(iq);
}
@@ -1779,7 +1760,7 @@ void CJabberProto::OmemoSendBundle() // construct bundle node
char szBareJid[JABBER_MAX_JID_LEN];
XmlNodeIq iq("set", SerialNext());
- iq << XATTR("from", JabberStripJid(m_ThreadInfo->fullJID, szBareJid, _countof_portable(szBareJid)));
+ iq << XATTR("from", JabberStripJid(m_ThreadInfo->fullJID, szBareJid, _countof(szBareJid)));
TiXmlElement *publish_node = iq << XCHILDNS("pubsub", "http://jabber.org/protocol/pubsub") << XCHILD("publish");
{
@@ -1838,12 +1819,6 @@ void CJabberProto::OmemoSendBundle() m_ThreadInfo->send(iq);
}
-void CJabberProto::OmemoPublishNodes()
-{
- OmemoAnnounceDevice();
- OmemoSendBundle();
-}
-
bool CJabberProto::OmemoCheckSession(MCONTACT hContact)
{
if (m_omemo.session_checked[hContact])
@@ -1866,7 +1841,7 @@ bool CJabberProto::OmemoCheckSession(MCONTACT hContact) XmlNodeIq iq(AddIQ(&CJabberProto::OmemoOnIqResultGetBundle, JABBER_IQ_TYPE_GET, nullptr, _id));
char szBareJid[JABBER_MAX_JID_LEN];
- iq << XATTR("from", JabberStripJid(m_ThreadInfo->fullJID, szBareJid, _countof_portable(szBareJid)));
+ iq << XATTR("from", JabberStripJid(m_ThreadInfo->fullJID, szBareJid, _countof(szBareJid)));
char *jid = ContactToJID(hContact);
iq << XATTR("to", jid);
@@ -2029,18 +2004,18 @@ int CJabberProto::OmemoEncryptMessage(XmlNode &msg, const char *msg_text, MCONTA const EVP_CIPHER *cipher = EVP_aes_128_gcm();
unsigned char key[16], iv[12], tag[16] /*, aad[48]*/;
- Utils_GetRandom(key, _countof_portable(key));
- Utils_GetRandom(iv, _countof_portable(iv));
- Utils_GetRandom(tag, _countof_portable(tag));
- //Utils_GetRandom(aad, _countof_portable(aad));
+ Utils_GetRandom(key, _countof(key));
+ Utils_GetRandom(iv, _countof(iv));
+ Utils_GetRandom(tag, _countof(tag));
+ //Utils_GetRandom(aad, _countof(aad));
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, _countof_portable(iv), nullptr);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, _countof(iv), nullptr);
EVP_EncryptInit(ctx, cipher, key, iv);
char *out;
const size_t inl = strlen(msg_text);
int tmp_len = 0, outl;
- //EVP_EncryptUpdate(ctx, nullptr, &outl, aad, _countof_portable(aad));
- out = (char*)mir_alloc(inl + _countof_portable(key) - 1);
+ //EVP_EncryptUpdate(ctx, nullptr, &outl, aad, _countof(aad));
+ out = (char*)mir_alloc(inl + _countof(key) - 1);
for (;;) {
EVP_EncryptUpdate(ctx, (unsigned char*)(out + tmp_len), &outl, (unsigned char*)(msg_text + tmp_len), (int)(inl - tmp_len));
tmp_len += outl;
@@ -2050,7 +2025,7 @@ int CJabberProto::OmemoEncryptMessage(XmlNode &msg, const char *msg_text, MCONTA EVP_EncryptFinal(ctx, (unsigned char*)(msg_text + tmp_len), &outl);
tmp_len += outl;
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, _countof_portable(tag), tag);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, _countof(tag), tag);
EVP_CIPHER_CTX_free(ctx);
TiXmlElement *encrypted = msg << XCHILDNS("encrypted", JABBER_FEAT_OMEMO);
@@ -2095,7 +2070,7 @@ int CJabberProto::OmemoEncryptMessage(XmlNode &msg, const char *msg_text, MCONTA }
TiXmlElement *iv_node = header << XCHILD("iv");
- iv_node->SetText(ptrA(mir_base64_encode(iv, _countof_portable(iv))).get());
+ iv_node->SetText(ptrA(mir_base64_encode(iv, _countof(iv))).get());
msg << XCHILDNS("store", "urn:xmpp:hints");
if (!session_count)
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index 05d8a6f4ee..8cd4ac4b64 100644 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -713,11 +713,10 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface void OmemoPutMessageToOutgoingQueue(MCONTACT hContact, int, const char *pszSrc);
void OmemoPutMessageToIncommingQueue(const TiXmlElement *node, const char *jid, time_t msgTime);
void OmemoHandleMessageQueue();
- void OmemoHandleDeviceList(const char *from, const TiXmlElement *node);
+ bool OmemoHandleDeviceList(const char *from, const TiXmlElement *node);
void OmemoInitDevice();
- void OmemoAnnounceDevice();
+ void OmemoAnnounceDevice(bool include_cache);
void OmemoSendBundle();
- void OmemoPublishNodes();
bool OmemoCheckSession(MCONTACT hContact);
int OmemoEncryptMessage(XmlNode &msg, const char *msg_text, MCONTACT hContact);
bool OmemoIsEnabled(MCONTACT hContact);
diff --git a/protocols/JabberG/src/jabber_userinfo.cpp b/protocols/JabberG/src/jabber_userinfo.cpp index 17ee16a485..5fe597a2f8 100644 --- a/protocols/JabberG/src/jabber_userinfo.cpp +++ b/protocols/JabberG/src/jabber_userinfo.cpp @@ -785,6 +785,7 @@ static void AddListItem(HWND hwndList, const CMStringA &pszStr1, const wchar_t * LVITEM lvi = {}; lvi.mask = LVIF_TEXT; lvi.pszText = mir_a2u(pszStr1); + lvi.iItem = 100500; int idx = ListView_InsertItem(hwndList, &lvi); mir_free(lvi.pszText); @@ -848,61 +849,51 @@ INT_PTR CALLBACK JabberUserOmemoDlgProc(HWND hwndDlg, UINT msg, WPARAM, LPARAM l ListView_DeleteAllItems(hwndList); if (pInfo->hContact == 0) { - uint32_t ownDeviceId = pInfo->ppro->getDword("OmemoDeviceId"); - CMStringA str1(FORMAT, "%d", ownDeviceId); + // GetOwnDeviceId() creates own keys if they don't exist + CMStringA str1(FORMAT, "%d", pInfo->ppro->m_omemo.GetOwnDeviceId()); CMStringA str2(pInfo->ppro->getMStringA("OmemoFingerprintOwn")); - // AddListItem(hwndList, "Other devices", "Not implemented yet", ""); AddListItem(hwndList, str1, TranslateT("Own device"), str2.Mid(2)); -/* - LIST<char> arSettings(1); - db_enum_settings(pInfo->hContact, EnumOwnSessions, pInfo->ppro->m_szModuleName, &arSettings); - - str2 = ""; - for (auto &it : arSettings) { - str1.Format("%d", pInfo->ppro->getDword(it)); - AddListItem(hwndList, str1, str2); - }*/ } - else { - for (int i=0;; i++) { - CMStringA szSetting(FORMAT, "%s%d", omemo::DevicePrefix, i); - uint32_t device_id = pInfo->ppro->getDword(pInfo->hContact, szSetting, 0); - if (device_id == 0) - break; - - char* jiddev = pInfo->ppro->getStringA(pInfo->hContact, "jid"); - if (jiddev == 0) - continue; - - size_t len = strlen(jiddev); - jiddev = (char*)mir_realloc(jiddev, len + sizeof(int32_t)); - memcpy(jiddev+len, &device_id, sizeof(int32_t)); - - szSetting = omemo::IdentityPrefix; - szSetting.Append(ptrA(mir_base64_encode(jiddev, len + sizeof(int32_t)))); - mir_free(jiddev); - - const wchar_t *pwszStatus = L""; - CMStringA fp_hex; - DBVARIANT dbv = { 0 }; - dbv.type = DBVT_BLOB; - db_get(pInfo->hContact, pInfo->ppro->m_szModuleName, szSetting, &dbv); - if (dbv.cpbVal == 33) { - fp_hex.Truncate(33 * 2); - bin2hex(dbv.pbVal, 33, fp_hex.GetBuffer()); - uint8_t trusted = pInfo->ppro->getByte(pInfo->hContact, "OmemoFingerprintTrusted_" + fp_hex); - pwszStatus = trusted ? TranslateT("Trusted") : TranslateT("UNTRUSTED"); - //TODO: 3 states Trusted, Untrusted, TOFU - fp_hex = fp_hex.Mid(2); - } - else if (dbv.cpbVal) - pwszStatus = TranslateT("Unknown"); + + for (int i=0;; i++) { + CMStringA szSetting(FORMAT, "%s%d", omemo::DevicePrefix, i); + uint32_t device_id = pInfo->ppro->getDword(pInfo->hContact, szSetting, 0); + if (device_id == 0) + break; + + char* jiddev = pInfo->ppro->getStringA(pInfo->hContact, "jid"); + if (jiddev == 0) + continue; + + size_t len = strlen(jiddev); + jiddev = (char*)mir_realloc(jiddev, len + sizeof(int32_t)); + memcpy(jiddev+len, &device_id, sizeof(int32_t)); + + szSetting = omemo::IdentityPrefix; + szSetting.Append(ptrA(mir_base64_encode(jiddev, len + sizeof(int32_t)))); + mir_free(jiddev); + + const wchar_t *pwszStatus = L""; + CMStringA fp_hex; + DBVARIANT dbv = { 0 }; + dbv.type = DBVT_BLOB; + db_get(pInfo->hContact, pInfo->ppro->m_szModuleName, szSetting, &dbv); + if (dbv.cpbVal == 33) { + fp_hex.Truncate(33 * 2); + bin2hex(dbv.pbVal, 33, fp_hex.GetBuffer()); + uint8_t trusted = pInfo->ppro->getByte(pInfo->hContact, "OmemoFingerprintTrusted_" + fp_hex); + pwszStatus = trusted ? TranslateT("Trusted") : TranslateT("UNTRUSTED"); + //TODO: 3 states Trusted, Untrusted, TOFU + fp_hex = fp_hex.Mid(2); + } + else if (dbv.cpbVal) + pwszStatus = TranslateT("Unknown"); - db_free(&dbv); + db_free(&dbv); - AddListItem(hwndList, CMStringA(FORMAT, "%d", device_id), pwszStatus, fp_hex); - } + AddListItem(hwndList, CMStringA(FORMAT, "%d", device_id), pwszStatus, fp_hex); } + break; } return FALSE; |