diff options
author | George Hazan <george.hazan@gmail.com> | 2024-12-02 21:54:38 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2024-12-02 21:54:38 +0300 |
commit | 2f093651c4edf10ba83088eb485b818a4a5e709f (patch) | |
tree | c3d77faa2bdd3c755d18153fa9df0165e991b84b /protocols/JabberG/src/jabber_sasl2.cpp | |
parent | 65836db9295f4faca1dece1d2ddf33afa7ed442d (diff) |
Jabber: upgrade tasks implementation
Diffstat (limited to 'protocols/JabberG/src/jabber_sasl2.cpp')
-rw-r--r-- | protocols/JabberG/src/jabber_sasl2.cpp | 112 |
1 files changed, 85 insertions, 27 deletions
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 } |