summaryrefslogtreecommitdiff
path: root/protocols/JabberG/src
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/JabberG/src')
-rw-r--r--protocols/JabberG/src/jabber_auth.cpp44
-rw-r--r--protocols/JabberG/src/jabber_proto.cpp7
-rw-r--r--protocols/JabberG/src/jabber_proto.h34
-rw-r--r--protocols/JabberG/src/jabber_sasl2.cpp112
-rw-r--r--protocols/JabberG/src/jabber_thread.cpp4
-rw-r--r--protocols/JabberG/src/stdafx.h3
6 files changed, 148 insertions, 56 deletions
diff --git a/protocols/JabberG/src/jabber_auth.cpp b/protocols/JabberG/src/jabber_auth.cpp
index 239586d58f..86c5495a1f 100644
--- a/protocols/JabberG/src/jabber_auth.cpp
+++ b/protocols/JabberG/src/jabber_auth.cpp
@@ -241,6 +241,24 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////
// SCRAM-SHA-1 authorization
+void Hi(const EVP_MD *hashMethod, uint8_t *res, char *passw, size_t passwLen, char *salt, size_t saltLen, int iterations)
+{
+ size_t bufLen = saltLen + sizeof(UINT32);
+ uint8_t *u = (uint8_t *)_alloca(max(bufLen, EVP_MAX_MD_SIZE));
+ memcpy(u, salt, saltLen); *(UINT32 *)(u + saltLen) = htonl(1);
+
+ memset(res, 0, EVP_MAX_MD_SIZE);
+
+ for (int i = 0; i < iterations; i++) {
+ unsigned int len;
+ HMAC(hashMethod, (uint8_t *)passw, (unsigned)passwLen, u, (unsigned)bufLen, u, &len);
+ bufLen = EVP_MD_size(hashMethod);
+
+ for (size_t j = 0; j < bufLen; j++)
+ res[j] ^= u[j];
+ }
+}
+
class TScramAuth : public TJabberAuth
{
typedef TJabberAuth CSuper;
@@ -294,7 +312,7 @@ public:
{
size_t chlLen, saltLen = 0;
ptrA snonce, salt;
- int ind = -1;
+ int iterations = -1;
ptrA chl((char *)mir_base64_decode(challenge, &chlLen)), cbd;
if (bindData.isEmpty())
@@ -313,16 +331,16 @@ public:
else if (*p == 's' && p[1] == '=') // salt
salt = (char *)mir_base64_decode(p + 2, &saltLen);
else if (*p == 'i' && p[1] == '=')
- ind = atoi(p + 2);
+ iterations = atoi(p + 2);
}
- if (snonce == nullptr || salt == nullptr || ind == -1)
+ if (snonce == nullptr || salt == nullptr || iterations == -1)
return nullptr;
int hashSize = EVP_MD_size(hashMethod);
uint8_t saltedPassw[EVP_MAX_MD_SIZE];
- Hi(saltedPassw, info->conn.password, mir_strlen(info->conn.password), salt, saltLen, ind);
+ Hi(hashMethod, saltedPassw, info->conn.password, mir_strlen(info->conn.password), salt, saltLen, iterations);
uint8_t clientKey[EVP_MAX_MD_SIZE];
unsigned int len;
@@ -364,24 +382,6 @@ public:
ptrA chl((char *)mir_base64_decode(challenge, &chlLen));
return chl && strncmp((char *)chl + 2, serverSignature, chlLen - 2) == 0;
}
-
- void Hi(uint8_t *res, char *passw, size_t passwLen, char *salt, size_t saltLen, int iterations)
- {
- size_t bufLen = saltLen + sizeof(UINT32);
- uint8_t *u = (uint8_t *)_alloca(max(bufLen, EVP_MAX_MD_SIZE));
- memcpy(u, salt, saltLen); *(UINT32 *)(u + saltLen) = htonl(1);
-
- memset(res, 0, EVP_MAX_MD_SIZE);
-
- for (int i = 0; i < iterations; i++) {
- unsigned int len;
- HMAC(hashMethod, (uint8_t *)passw, (unsigned)passwLen, u, (unsigned)bufLen, u, &len);
- bufLen = EVP_MD_size(hashMethod);
-
- for (size_t j = 0; j < bufLen; j++)
- res[j] ^= u[j];
- }
- }
};
/////////////////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp
index 0ec19dfc69..0245cfa2db 100644
--- a/protocols/JabberG/src/jabber_proto.cpp
+++ b/protocols/JabberG/src/jabber_proto.cpp
@@ -57,13 +57,18 @@ static int compareAuth(const TJabberAuth *p1, const TJabberAuth *p2)
return p2->getPriority() - p1->getPriority(); // reverse sorting order
}
+static int compareTasks(const TUpgradeTask *p1, const TUpgradeTask *p2)
+{
+ return p2->getPriority() - p1->getPriority(); // reverse sorting order
+}
+
CJabberProto::CJabberProto(const char *aProtoName, const wchar_t *aUserName) :
PROTO<CJabberProto>(aProtoName, aUserName),
m_impl(*this),
m_omemo(this),
m_arChatMarks(50, NumericKeySortT),
m_arAuthMechs(1, compareAuth),
- m_arSaslUpgrade(1, compareAuth),
+ m_arSaslUpgrade(1, compareTasks),
m_lstTransports(50, compareTransports),
m_lstRoster(50, compareListItems),
m_iqManager(this),
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h
index 8ec6d498be..969f59ee9b 100644
--- a/protocols/JabberG/src/jabber_proto.h
+++ b/protocols/JabberG/src/jabber_proto.h
@@ -108,6 +108,36 @@ public:
}
};
+class TUpgradeTask : public MZeroedObject
+{
+protected:
+ ptrA szName, szInitData;
+ ThreadData *info;
+ int priority;
+
+public:
+ TUpgradeTask(ThreadData *pInfo, const char *pszMech) :
+ info(pInfo),
+ szName(mir_strdup(pszMech))
+ {}
+
+ virtual ~TUpgradeTask() {}
+
+ __forceinline const char *getName() const {
+ return szName;
+ }
+
+ __forceinline int getPriority() const {
+ return priority;
+ }
+
+ void setInitData(const char *pszData) {
+ szInitData = mir_strdup(pszData);
+ }
+
+ virtual bool perform(const TiXmlElement *src, TiXmlElement *dest) = 0;
+};
+
struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
{
friend struct ThreadData;
@@ -859,11 +889,11 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface
void SearchDeleteFromRecent(const char *szAddr, bool deleteLastFromDB);
void SearchAddToRecent(const char *szAddr, HWND hwndDialog = nullptr);
- //---- jabber_secur.cpp --------------------------------------------------------------
+ //---- jabber_auth.cpp ---------------------------------------------------------------
- OBJLIST<TJabberAuth> m_arSaslUpgrade;
OBJLIST<TJabberAuth> m_arAuthMechs;
+ OBJLIST<TUpgradeTask> m_arSaslUpgrade;
bool OnProcessMechanism(const TiXmlElement *node, ThreadData *info);
void OnProcessUpgrade(const TiXmlElement *node, ThreadData *info);
diff --git a/protocols/JabberG/src/jabber_sasl2.cpp b/protocols/JabberG/src/jabber_sasl2.cpp
index 5784bf8f3e..b63350acd9 100644
--- a/protocols/JabberG/src/jabber_sasl2.cpp
+++ b/protocols/JabberG/src/jabber_sasl2.cpp
@@ -17,41 +17,92 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
+void Hi(const EVP_MD *hashMethod, uint8_t *res, char *passw, size_t passwLen, char *salt, size_t saltLen, int iterations);
+
+struct TScramTask : public TUpgradeTask
+{
+ const EVP_MD *hashMethod;
+
+ TScramTask(ThreadData *info, const char *pszMech, const EVP_MD *pMethod, int iPriority) :
+ TUpgradeTask(info, pszMech),
+ hashMethod(pMethod)
+ {
+ priority = iPriority;
+ }
+
+ ~TScramTask() {}
+
+ bool perform(const TiXmlElement *src, TiXmlElement *dest) override
+ {
+ auto *salt = XmlGetChildByTag(src, "salt", "xmlns", "urn:xmpp:scram-upgrade:0");
+ if (!salt || !mir_strlen(szInitData))
+ return false;
+
+ int iterations = salt->IntAttribute("iterations");
+ auto *pszSalt = salt->GetText();
+ if (!mir_strlen(pszSalt) || !iterations)
+ return false;
+
+ size_t cbNonce, cbSalt;
+ ptrA szInit((char *)mir_base64_decode(szInitData, &cbNonce));
+ ptrA szNonce((char*)mir_base64_decode(szInit.get() + 2, &cbNonce));
+ ptrA szSalt((char *)mir_base64_decode(pszSalt, &cbSalt));
+ ptrA cbd(mir_base64_encode("n,,", 3)), chl(mir_strdup("")), msg1(mir_strdup(""));
+
+ int hashSize = EVP_MD_size(hashMethod);
+
+ uint8_t saltedPassw[EVP_MAX_MD_SIZE];
+ Hi(hashMethod, saltedPassw, info->conn.password, mir_strlen(info->conn.password), szSalt, cbSalt, iterations);
+
+ uint8_t clientKey[EVP_MAX_MD_SIZE];
+ unsigned int len;
+ HMAC(hashMethod, saltedPassw, hashSize, (uint8_t *)"Client Key", 10, clientKey, &len);
+
+ uint8_t storedKey[EVP_MAX_MD_SIZE];
+ {
+ EVP_MD_CTX *pctx = EVP_MD_CTX_new();
+ EVP_DigestInit(pctx, hashMethod);
+ EVP_DigestUpdate(pctx, clientKey, hashSize);
+ EVP_DigestFinal(pctx, storedKey, &len);
+ EVP_MD_CTX_free(pctx);
+ }
+
+ uint8_t clientSig[EVP_MAX_MD_SIZE];
+ CMStringA authmsg(FORMAT, "%s,%s,c=%s,r=%s", msg1, chl.get(), cbd.get(), szNonce.get());
+ HMAC(hashMethod, storedKey, hashSize, (uint8_t *)authmsg.c_str(), authmsg.GetLength(), clientSig, &len);
+
+ uint8_t clientProof[EVP_MAX_MD_SIZE];
+ for (int j = 0; j < hashSize; j++)
+ clientProof[j] = clientKey[j] ^ clientSig[j];
+
+ ptrA szEncoded(mir_base64_encode(clientProof, hashSize));
+ auto *pHash = dest << XCHILD("hash", szEncoded);
+ pHash << XATTR("xmlns", "urn:xmpp:scram-upgrade:0");
+ return true;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// SASL2: common tasks processing methods
+
void CJabberProto::OnProcessUpgrade(const TiXmlElement *n, ThreadData *info)
{
- /*
- TJabberAuth *pAuth = nullptr;
+ TUpgradeTask *pTask;
auto *szMechanism = n->GetText();
if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-1"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 500);
- else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-1-PLUS"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha1(), 601);
- else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-224"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha224(), 510);
- else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-224-PLUS"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha224(), 611);
+ pTask = new TScramTask(info, szMechanism, EVP_sha1(), 500);
else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-256"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 520);
- else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-256-PLUS"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha256(), 621);
+ pTask = new TScramTask(info, szMechanism, EVP_sha256(), 520);
else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-384"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha384(), 530);
- else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-384-PLUS"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha384(), 631);
+ pTask = new TScramTask(info, szMechanism, EVP_sha384(), 530);
else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-512"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha512(), 540);
- else if (!mir_strcmp(szMechanism, "UPGR-SCRAM-SHA-512-PLUS"))
- pAuth = new TScramAuth(info, szMechanism, EVP_sha512(), 641);
-
- if (pAuth == nullptr) {
+ pTask = new TScramTask(info, szMechanism, EVP_sha512(), 540);
+ else {
debugLogA("Unsupported mechanism for upgrade: %s, skipping", szMechanism);
return;
}
- if (!pAuth->isValid())
- delete pAuth;
- else
- m_arSaslUpgrade.insert(pAuth);*/
+ m_arSaslUpgrade.insert(pTask);
}
void CJabberProto::OnProcessContinue(const TiXmlElement *node, ThreadData *info)
@@ -61,7 +112,7 @@ void CJabberProto::OnProcessContinue(const TiXmlElement *node, ThreadData *info)
return;
}
- TJabberAuth *pTask = nullptr;
+ TUpgradeTask *pTask = nullptr;
for (auto *task : TiXmlFilter(node->FirstChildElement("tasks"), "task"))
for (auto &it : m_arSaslUpgrade)
if (!mir_strcmp(it->getName(), task->GetText())) {
@@ -75,9 +126,8 @@ void CJabberProto::OnProcessContinue(const TiXmlElement *node, ThreadData *info)
return;
}
+ pTask->setInitData(XmlGetChildText(node, "additional-data"));
info->m_saslUpgrade = pTask;
- if (auto *n = node->FirstChildElement("additional-data"))
- info->saslInitData = mir_strdup(n->GetText());
XmlNode next("next");
next << XATTR("xmlns", JABBER_FEAT_SASL2) << XATTR("task", pTask->getName());
@@ -86,5 +136,13 @@ void CJabberProto::OnProcessContinue(const TiXmlElement *node, ThreadData *info)
void CJabberProto::OnProcessTaskData(const TiXmlElement *node, ThreadData *info)
{
+ if (!info->m_saslUpgrade)
+ return;
+ XmlNode reply("task-data");
+ reply << XATTR("xmlns", JABBER_FEAT_SASL2);
+ if (info->m_saslUpgrade->perform(node, reply))
+ info->send(reply);
+ else
+ info->send("</stream:stream>"); // bye-bye
}
diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp
index d895c34ca0..77a702aec6 100644
--- a/protocols/JabberG/src/jabber_thread.cpp
+++ b/protocols/JabberG/src/jabber_thread.cpp
@@ -709,8 +709,8 @@ void CJabberProto::OnProcessFeatures(const TiXmlElement *node, ThreadData *info)
// dunno why we need to handle that
}
}
- else if (!mir_strcmp(c->Name(), "upgrade") && c->Attribute("xmlns", "urn:xmpp:sasl:upgrade:0"))
- OnProcessUpgrade(c, info);
+ // else if (!mir_strcmp(c->Name(), "upgrade") && c->Attribute("xmlns", "urn:xmpp:sasl:upgrade:0"))
+ // OnProcessUpgrade(c, info);
}
}
else if (!mir_strcmp(pszName, "session"))
diff --git a/protocols/JabberG/src/stdafx.h b/protocols/JabberG/src/stdafx.h
index 8bd9d976f9..fac757dfcd 100644
--- a/protocols/JabberG/src/stdafx.h
+++ b/protocols/JabberG/src/stdafx.h
@@ -383,8 +383,7 @@ struct ThreadData
char* gssapiHostName;
- class TJabberAuth *m_saslUpgrade;
- ptrA saslInitData;
+ class TUpgradeTask *m_saslUpgrade;
CJabberIqInfo *pPendingQuery;
JabberCapsBits jabberServerCaps;