From 2d043179f4723b15eb63df92d6cdb031511f10ee Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Sun, 2 Nov 2014 10:29:30 +0000 Subject: MSN protocol stopped working (R.I.P), moved to deprecated, banned by the core, delete mask in PluginUpdater was created git-svn-id: http://svn.miranda-ng.org/main/trunk@10896 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/!Deprecated/MSN/src/msn_auth.cpp | 485 +++++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 plugins/!Deprecated/MSN/src/msn_auth.cpp (limited to 'plugins/!Deprecated/MSN/src/msn_auth.cpp') diff --git a/plugins/!Deprecated/MSN/src/msn_auth.cpp b/plugins/!Deprecated/MSN/src/msn_auth.cpp new file mode 100644 index 0000000000..9474b71dfc --- /dev/null +++ b/plugins/!Deprecated/MSN/src/msn_auth.cpp @@ -0,0 +1,485 @@ +/* +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol. + +Copyright (c) 2012-2014 Miranda NG Team +Copyright (c) 2007-2012 Boris Krasnovskiy. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "msn_global.h" +#include "msn_proto.h" +#include "des.h" + +static const char defaultPassportUrl[] = "https://login.live.com/RST2.srf"; + +static const char authPacket[] = +"" +"" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" + "HTTPS://login.live.com:443//RST2.srf" + "%u" + "" + "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}" + "5" + "1" + "" + "AQAAAAIAAABsYwQAAAAxMDMz" + "" + "" + "" + "%s" + "%s" + "" + "" + "%s" + "%s" + "" + "" + "" + "" + "" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" + "" + "" + "http://Passport.NET/tb" + "" + "" + "" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" + "" + "" + "messengerclear.live.com" + "" + "" + "" + "" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" + "" + "" + "messenger.msn.com" + "" + "" + "" + "" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" + "" + "" + "messengersecure.live.com" + "" + "" + "" + "" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" + "" + "" + "contacts.msn.com" + "" + "" + "" + "" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" + "" + "" + "storage.msn.com" + "" + "" + "" + "" + "" + "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" + "" + "" + "sup.live.com" + "" + "" + "" + "" + "" + "" +""; + + +///////////////////////////////////////////////////////////////////////////////////////// +// Performs the MSN Passport login via TLS + +int CMsnProto::MSN_GetPassportAuth(void) +{ + int retVal = -1; + + char szPassword[100]; + db_get_static(NULL, m_szModuleName, "Password", szPassword, sizeof(szPassword)); + szPassword[16] = 0; + char* szEncPassword = HtmlEncode(szPassword); + + time_t ts = time(NULL); + + TCHAR szTs1[64], szTs2[64]; + + tmi.printTimeStamp(UTC_TIME_HANDLE, ts, _T("I"), szTs1, SIZEOF(szTs1), 0); + tmi.printTimeStamp(UTC_TIME_HANDLE, ts + 20 * 60, _T("I"), szTs2, SIZEOF(szTs2), 0); + + char *szTs1A = mir_t2a(szTs1), *szTs2A = mir_t2a(szTs2); + + const size_t len = sizeof(authPacket) + 2048; + char* szAuthInfo = (char*)alloca(len); + mir_snprintf(szAuthInfo, len, authPacket, int(ts), MyOptions.szEmail, szEncPassword, szTs1A, szTs2A); + + mir_free(szTs2A); + mir_free(szTs1A); + mir_free(szEncPassword); + + char* szPassportHost = (char*)mir_alloc(256); + if (db_get_static(NULL, m_szModuleName, "MsnPassportHost", szPassportHost, 256)) + strcpy(szPassportHost, defaultPassportUrl); + + bool defaultUrlAllow = strcmp(szPassportHost, defaultPassportUrl) != 0; + char *tResult = NULL; + + while (retVal == -1) + { + unsigned status; + + tResult = getSslResult(&szPassportHost, szAuthInfo, NULL, status); + if (tResult == NULL) + { + if (defaultUrlAllow) + { + strcpy(szPassportHost, defaultPassportUrl); + defaultUrlAllow = false; + continue; + } + else + { + retVal = 4; + break; + } + } + + switch (status) + { + case 200: + { + const char *errurl = NULL; + ezxml_t xml = ezxml_parse_str(tResult, strlen(tResult)); + + ezxml_t tokr = ezxml_get(xml, "S:Body", 0, + "wst:RequestSecurityTokenResponseCollection", 0, + "wst:RequestSecurityTokenResponse", -1); + + while (tokr != NULL) + { + ezxml_t toks = ezxml_get(tokr, "wst:RequestedSecurityToken", 0, + "wsse:BinarySecurityToken", -1); + + const char* addr = ezxml_txt(ezxml_get(tokr, "wsp:AppliesTo", 0, + "wsa:EndpointReference", 0, "wsa:Address", -1)); + + if (strcmp(addr, "http://Passport.NET/tb") == 0) + { + ezxml_t node = ezxml_get(tokr, "wst:RequestedSecurityToken", 0, "EncryptedData", -1); + free(hotAuthToken); + hotAuthToken = ezxml_toxml(node, 0); + + node = ezxml_get(tokr, "wst:RequestedProofToken", 0, "wst:BinarySecret", -1); + replaceStr(hotSecretToken, ezxml_txt(node)); + } + else if (strcmp(addr, "messengerclear.live.com") == 0) + { + ezxml_t node = ezxml_get(tokr, "wst:RequestedProofToken", 0, + "wst:BinarySecret", -1); + if (toks) + { + replaceStr(authStrToken, ezxml_txt(toks)); + replaceStr(authSecretToken, ezxml_txt(node)); + retVal = 0; + } + else + { + errurl = ezxml_txt(ezxml_get(tokr, "S:Fault", 0, "psf:pp", 0, "psf:flowurl", -1)); + } + } + else if (strcmp(addr, "messenger.msn.com") == 0 && toks) + { + const char* tok = ezxml_txt(toks); + char* ch = (char*)strchr(tok, '&'); + *ch = 0; + replaceStr(tAuthToken, tok+2); + replaceStr(pAuthToken, ch+3); + *ch = '&'; + } + else if (strcmp(addr, "contacts.msn.com") == 0 && toks) + { + replaceStr(authContactToken, ezxml_txt(toks)); + } + else if (strcmp(addr, "messengersecure.live.com") == 0 && toks) + { + replaceStr(oimSendToken, ezxml_txt(toks)); + } + else if (strcmp(addr, "storage.msn.com") == 0 && toks) + { + replaceStr(authStorageToken, ezxml_txt(toks)); + } + + tokr = ezxml_next(tokr); + } + + if (retVal != 0) + { + if (errurl) + { + debugLogA("Starting URL: '%s'", errurl); + CallService(MS_UTILS_OPENURL, 1, (LPARAM)errurl); + } + + ezxml_t tokf = ezxml_get(xml, "S:Body", 0, "S:Fault", 0, "S:Detail", -1); + ezxml_t tokrdr = ezxml_child(tokf, "psf:redirectUrl"); + if (tokrdr != NULL) + { + strcpy(szPassportHost, ezxml_txt(tokrdr)); + debugLogA("Redirected to '%s'", szPassportHost); + } + else + { + const char* szFault = ezxml_txt(ezxml_get(tokf, "psf:error", 0, "psf:value", -1)); + retVal = strcmp(szFault, "0x80048821") == 0 ? 3 : (tokf ? 5 : 7); + if (retVal != 3 && defaultUrlAllow) + { + strcpy(szPassportHost, defaultPassportUrl); + defaultUrlAllow = false; + retVal = -1; + } + else if (retVal != 3 && retVal != 7) + { + char err[512]; + mir_snprintf(err, sizeof(err), "Unknown Authentication error: %s", szFault); + MSN_ShowError(err); + } + } + } + + ezxml_free(xml); + break; + } + default: + if (defaultUrlAllow) + { + strcpy(szPassportHost, defaultPassportUrl); + defaultUrlAllow = false; + } + else + retVal = 6; + } + mir_free(tResult); + } + + if (retVal != 0) + { + if (!Miranda_Terminated()) + { + switch (retVal) + { + case 3: + MSN_ShowError("Your username or password is incorrect"); + ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD); + break; + + case 5: + break; + + default: + MSN_ShowError("Unable to contact MS Passport servers check proxy/firewall settings"); + ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER); + break; + } + } + } + else + setString("MsnPassportHost", szPassportHost); + + mir_free(szPassportHost); + debugLogA("MSN_CheckRedirector exited with errorCode = %d", retVal); + return retVal; +} + +static void derive_key(BYTE* der, unsigned char* key, size_t keylen, unsigned char* data, size_t datalen) +{ + BYTE hash1[MIR_SHA1_HASH_SIZE]; + BYTE hash2[MIR_SHA1_HASH_SIZE]; + BYTE hash3[MIR_SHA1_HASH_SIZE]; + BYTE hash4[MIR_SHA1_HASH_SIZE]; + + const size_t buflen = MIR_SHA1_HASH_SIZE + datalen; + BYTE* buf = (BYTE*)alloca(buflen); + + mir_hmac_sha1(hash1, key, keylen, data, datalen); + mir_hmac_sha1(hash3, key, keylen, hash1, MIR_SHA1_HASH_SIZE); + + memcpy(buf, hash1, MIR_SHA1_HASH_SIZE); + memcpy(buf + MIR_SHA1_HASH_SIZE, data, datalen); + mir_hmac_sha1(hash2, key, keylen, buf, buflen); + + memcpy(buf, hash3, MIR_SHA1_HASH_SIZE); + memcpy(buf + MIR_SHA1_HASH_SIZE, data, datalen); + mir_hmac_sha1(hash4, key, keylen, buf, buflen); + + memcpy(der, hash2, MIR_SHA1_HASH_SIZE); + memcpy(der + MIR_SHA1_HASH_SIZE, hash4, 4); +} + +typedef struct tag_MsgrUsrKeyHdr +{ + unsigned size; + unsigned cryptMode; + unsigned cipherType; + unsigned hashType; + unsigned ivLen; + unsigned hashLen; + unsigned long cipherLen; +} MsgrUsrKeyHdr; + +static const MsgrUsrKeyHdr userKeyHdr = +{ + sizeof(MsgrUsrKeyHdr), + 1, // CRYPT_MODE_CBC + 0x6603, // CALG_3DES + 0x8004, // CALG_SHA1 + 8, // sizeof(ivBytes) + MIR_SHA1_HASH_SIZE, + 72 // sizeof(cipherBytes); +}; + + +static unsigned char* PKCS5_Padding(char* in, size_t &len) +{ + const size_t nlen = ((len >> 3) + 1) << 3; + unsigned char* res = (unsigned char*)mir_alloc(nlen); + memcpy(res, in, len); + + const unsigned char pad = 8 - (len & 7); + memset(res + len, pad, pad); + + len = nlen; + return res; +} + + +char* CMsnProto::GenerateLoginBlob(char* challenge) +{ + unsigned key1len; + BYTE *key1 = (BYTE*)mir_base64_decode(authSecretToken, &key1len); + + BYTE key2[MIR_SHA1_HASH_SIZE+4]; + BYTE key3[MIR_SHA1_HASH_SIZE+4]; + + static const unsigned char encdata1[] = "WS-SecureConversationSESSION KEY HASH"; + static const unsigned char encdata2[] = "WS-SecureConversationSESSION KEY ENCRYPTION"; + + derive_key(key2, key1, key1len, (unsigned char*)encdata1, sizeof(encdata1) - 1); + derive_key(key3, key1, key1len, (unsigned char*)encdata2, sizeof(encdata2) - 1); + + size_t chllen = strlen(challenge); + + BYTE hash[MIR_SHA1_HASH_SIZE]; + mir_hmac_sha1(hash, key2, MIR_SHA1_HASH_SIZE+4, (BYTE*)challenge, chllen); + + unsigned char* newchl = PKCS5_Padding(challenge, chllen); + + const size_t pktsz = sizeof(MsgrUsrKeyHdr) + MIR_SHA1_HASH_SIZE + 8 + chllen; + unsigned char* userKey = (unsigned char*)alloca(pktsz); + + unsigned char* p = userKey; + memcpy(p, &userKeyHdr, sizeof(MsgrUsrKeyHdr)); + ((MsgrUsrKeyHdr*)p)->cipherLen = (int)chllen; + p += sizeof(MsgrUsrKeyHdr); + + unsigned char iv[8]; + CallService(MS_UTILS_GETRANDOM, sizeof(iv), (LPARAM)iv); + + memcpy(p, iv, sizeof(iv)); + p += sizeof(iv); + + memcpy(p, hash, sizeof(hash)); + p += MIR_SHA1_HASH_SIZE; + + des3_context ctxd; + memset(&ctxd, 0, sizeof(ctxd)); + des3_set_3keys(&ctxd, key3); + des3_cbc_encrypt(&ctxd, iv, newchl, p, (int)chllen); + + mir_free(newchl); + + return mir_base64_encode(userKey, (unsigned)pktsz); +} + + +CMStringA CMsnProto::HotmailLogin(const char* url) +{ + unsigned char nonce[24]; + CallService(MS_UTILS_GETRANDOM, sizeof(nonce), (LPARAM)nonce); + + const size_t hotSecretlen = strlen(hotSecretToken); + unsigned key1len; + BYTE *key1 = (BYTE*)mir_base64_decode(hotSecretToken, &key1len); + + static const unsigned char encdata[] = "WS-SecureConversation"; + const size_t data1len = sizeof(nonce) + sizeof(encdata) - 1; + + unsigned char* data1 = (unsigned char*)alloca(data1len); + memcpy(data1, encdata, sizeof(encdata) - 1); + memcpy(data1 + sizeof(encdata) - 1, nonce, sizeof(nonce)); + + unsigned char key2[MIR_SHA1_HASH_SIZE+4]; + derive_key(key2, key1, key1len, data1, data1len); + + CMStringA result; + result.Format("%s&da=%s&nonce=", url, ptrA(mir_urlEncode(hotAuthToken))); + + ptrA noncenc(mir_base64_encode(nonce, sizeof(nonce))); + result.Append(ptrA(mir_urlEncode(noncenc))); + + BYTE hash[MIR_SHA1_HASH_SIZE]; + mir_hmac_sha1(hash, key2, sizeof(key2), (BYTE*)result.GetString(), result.GetLength()); + ptrA szHash(mir_base64_encode(hash, sizeof(hash))); + result.AppendFormat("&hash=%s", ptrA(mir_urlEncode(szHash))); + return result; +} + +void CMsnProto::FreeAuthTokens(void) +{ + mir_free(pAuthToken); + mir_free(tAuthToken); + mir_free(oimSendToken); + mir_free(authStrToken); + mir_free(authSecretToken); + mir_free(authContactToken); + mir_free(authStorageToken); + mir_free(hotSecretToken); + free(hotAuthToken); +} -- cgit v1.2.3