Protocols/MSNP/MSNP15/SSO: Difference between revisions
(Removed broken links in the 'code examples' section.) |
m (1 revision imported) |
||
(No difference)
|
Revision as of 00:23, 29 May 2020
Overview ·
Changes ·
Single Sign-On ·
Ticket Tokens
New features: Locations · Roaming Content
RPS/SSO Authentication
When you authenticate with MSNP15, you will notice that the USR command has changed slightly. Here is the new format:
Abstract
Client: USR <TrId> SSO I <email>\r\n Server: USR <TrId> SSO S <policy> <base64 encoded nonce>\r\n Client: USR <TrId> SSO S <ticket> <base64 encoded response structure>\r\n Server: USR <TrId> OK <email> <verified> 0\r\n
Example
Client: USR 10 SSO I buddy@live.com\r\n Server: USR 10 SSO S MBI_KEY_OLD E4Fhehbe0q2Je+SUSp7IRnJV+rN4uME75ljIpUjIZ1Si+DgmrfuiIL+AFmkMA6Wv\r\n Client: USR 11 SSO S t=... HAAAAAEAAAADZgAABIAAAA...\r\n Server: USR 11 OK buddy@live.com 1 0\r\n
After you receive the first "SSO S" command, you should take your given policy and connect to https://login.live.com/RST.srf.
Remark: For the account which ends up with @msn.com, this should be https://msnia.login.live.com/pp550/RST.srf.
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/06/secext" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:wssc="http://schemas.xmlsoap.org/ws/2004/04/sc" xmlns:wst="http://schemas.xmlsoap.org/ws/2004/04/trust"> <Header> <ps:AuthInfo xmlns:ps="http://schemas.microsoft.com/Passport/SoapServices/PPCRL" Id="PPAuthInfo"> <ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp> <ps:BinaryVersion>4</ps:BinaryVersion> <ps:UIVersion>1</ps:UIVersion> <ps:Cookies></ps:Cookies> <ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams> </ps:AuthInfo> <wsse:Security> <wsse:UsernameToken Id="user"> <wsse:Username>email@live.com</wsse:Username> <wsse:Password>PasswordGoesHere</wsse:Password> </wsse:UsernameToken> </wsse:Security> </Header> <Body> <ps:RequestMultipleSecurityTokens xmlns:ps="http://schemas.microsoft.com/Passport/SoapServices/PPCRL" Id="RSTS"> <wst:RequestSecurityToken Id="RST0"> <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> <wsp:AppliesTo> <wsa:EndpointReference> <wsa:Address>http://Passport.NET/tb</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> </wst:RequestSecurityToken> <wst:RequestSecurityToken Id="RSTn"> <wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType> <wsp:AppliesTo> <wsa:EndpointReference> <wsa:Address>domain</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <wsse:PolicyReference URI="policy parameter"></wsse:PolicyReference> </wst:RequestSecurityToken> ... ... </ps:RequestMultipleSecurityTokens> </Body> </Envelope>
Inside of ps:RequestMultipleSecurityTokens, you have a list of domains you want to authenticate to. You start from RST0 and you move to RST1 and so on. This allows you to get your MSPAuth and MSPProf cookies for multiple different domains all at the same time.
Some examples of sites that you can authenticate with
Domain: http://Passport.NET/tb Policy Ref URI: - Purpose: Unknown, but it's required for the request to succeed.
Domain: messengerclear.live.com Policy Ref URI: <obtain from the USR command> Purpose: Authentication for messenger.
Domain: messenger.msn.com Policy Ref URI: ?id=507 Purpose: Messenger website authentication.
Domain: contacts.msn.com Policy Ref URI: ?fs=1&id=24000&kv=9&rn=93S9SWWw&tw=0&ver=2.1.6000.1 New Policy Ref URI: MBI (used in WLM 8.5.1288.816) Purpose: Authentication for the Contact server.
Domain: messengersecure.live.com Policy Ref URI: MBI_SSL Purpose: Unknown
Domain: spaces.msn.com or spaces.live.com Policy Ref URI: MBI Purpose: Authentication for the Windows Live Spaces
Domain: livecontacts.live.com Policy Ref URI: MBI Purpose: Live Contacts API, a simplified version of the Contacts SOAP service
Domain: storage.live.com Policy Ref URI: MBI Purpose: Storage REST API
The response to this query when successful, looks like this.
<S:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header> There is really data here, but for space it has be removed </S:Header> <S:Body> <wst:RequestSecurityTokenResponseCollection xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wst="http://schemas.xmlsoap.org/ws/2004/04/trust" xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/06/secext" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy" xmlns:psf="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault"> <wst:RequestSecurityTokenResponse> <wst:TokenType>urn:passport:legacy</wst:TokenType> <wsp:AppliesTo xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing"> <wsa:EndpointReference> <wsa:Address>http://Passport.NET/tb</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <wst:LifeTime> <wsu:Created>2006-12-06T05:12:10Z</wsu:Created> <wsu:Expires>2006-12-07T05:12:10Z</wsu:Expires> </wst:LifeTime> <wst:RequestedSecurityToken> <EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" Id="BinaryDAToken0" Type="http://www.w3.org/2001/04/xmlenc#Element"> <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"> </EncryptionMethod> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:KeyName>http://Passport.NET/STS</ds:KeyName> </ds:KeyInfo> <CipherData> <CipherValue> cipher data you don't need to worry about </CipherValue> </CipherData> </EncryptedData> </wst:RequestedSecurityToken> <wst:RequestedTokenReference> <wsse:KeyIdentifier ValueType="urn:passport"></wsse:KeyIdentifier> <wsse:Reference URI="#BinaryDAToken0"></wsse:Reference> </wst:RequestedTokenReference> <wst:RequestedProofToken> <wst:BinarySecret>ignore this one</wst:BinarySecret> </wst:RequestedProofToken> </wst:RequestSecurityTokenResponse> <wst:RequestSecurityTokenResponse> <wst:TokenType>urn:passport:compact</wst:TokenType> <wsp:AppliesTo xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing"> <wsa:EndpointReference> <wsa:Address>messengerclear.live.com</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <wst:LifeTime> <wsu:Created>2006-12-06T05:12:10Z</wsu:Created> <wsu:Expires>2006-12-06T13:12:10Z</wsu:Expires> </wst:LifeTime> <wst:RequestedSecurityToken> <wsse:BinarySecurityToken Id="Compactn"> t=<ticket goes here>&p= </wsse:BinarySecurityToken> </wst:RequestedSecurityToken> <wst:RequestedTokenReference> <wsse:KeyIdentifier ValueType="urn:passport:compact"></wsse:KeyIdentifier> <wsse:Reference URI="#Compactn"></wsse:Reference> </wst:RequestedTokenReference> <wst:RequestedProofToken> <wst:BinarySecret>binary secret (you need this)</wst:BinarySecret> </wst:RequestedProofToken> </wst:RequestSecurityTokenResponse> <wst:RequestSecurityTokenResponse> <wst:TokenType>urn:passport:legacy</wst:TokenType> <wsp:AppliesTo xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing"> <wsa:EndpointReference> <wsa:Address>site domain</wsa:Address> </wsa:EndpointReference> </wsp:AppliesTo> <wst:LifeTime> <wsu:Created>2006-12-06T05:12:10Z</wsu:Created> <wsu:Expires>2006-12-06T05:20:30Z</wsu:Expires> </wst:LifeTime> <wst:RequestedSecurityToken> <wsse:BinarySecurityToken Id="PPTokenn"> t=<site ticket here>&p=<site profile here> </wsse:BinarySecurityToken> </wst:RequestedSecurityToken> <wst:RequestedTokenReference> <wsse:KeyIdentifier ValueType="urn:passport"></wsse:KeyIdentifier> <wsse:Reference URI="#PPTokenn"></wsse:Reference> </wst:RequestedTokenReference> </wst:RequestSecurityTokenResponse> ... ... </wst:RequestSecurityTokenResponseCollection> </S:Body> </S:Envelope>
In your response, you will need to look for the wst:RequestSecurityTokenResponseCollection section. This section contains the list of credentials for each site you requested. If your policy reference URI contained something like MBI, MBI_SSL or MBI_KEY_OLD, the your ticket/MSPAuth&MSPProf will be in the <wsse:BinarySecurityToken Id="Compactn"> where n is the same number as the RSTn request. If the policy reference contains a string starting in a question mark (like the end of a url), your security data will be in <wsse:BinarySecurityToken Id="PPTokenn"> Technically speaking you should check the <wst:TokenType> tag.
For logging in to messenger, you will need to grab your ticket, and the contents of the <wst:BinarySecret> tag.
Computing the return value
Now that you have your ticket(nonce) and your Binary secret, we need to create a structure of information to send back to the server. The C++ style structure looks like this:
struct tagMSGRUSRKEY { // Header unsigned int uStructHeaderSize; // 28. Does not count data unsigned int uCryptMode; // CRYPT_MODE_CBC (1) unsigned int uCipherType; // TripleDES (0x6603) unsigned int uHashType; // SHA1 (0x8004) unsigned int uIVLen; // 8 unsigned int uHashLen; // 20 unsigned int uCipherLen; // 72 // Data unsigned char aIVBytes[8]; unsigned char aHashBytes[20]; unsigned char aCipherBytes[72]; }MSGUSRKEY;
Note that these values are all Little-Endian. Each header element of the struct should be 4 bytes in size. unsinged int is 4 bytes on both x86_32 and x86_64 bit OSes.
ATTENTION: unsigned long is 4 bytes on x86_32 and 8 bytes on x86_64. So be careful if you're using long and building for x86_64 architectures.
If you use the default values that messenger gives, the sizes of the BYTE arrays will be correct, if you do not use the default values, you'll have to adjust properly.
We need to create some keys. Let's call them key1, key2 and key3.
1. Base64 decode your binary secret.
Store the resulting data in key1.
2. key2 and key3
Data for both key2 and key3 are calculated by the same logic. See this pseudo-code for key2:
hash1 = SHA1-HMAC(key1,"WS-SecureConversationSESSION KEY HASH") hash2 = SHA1-HMAC(key1,hash1+"WS-SecureConversationSESSION KEY HASH") hash3 = SHA1-HMAC(key1,hash1) hash4 = SHA1-HMAC(key1,hash3+"WS-SecureConversationSESSION KEY HASH")
Take all 20 bytes from hash2 and the first 4 bytes from hash4. Store that in key2. Now do the same thing only this time use the string "WS-SecureConversationSESSION KEY ENCRYPTION" (instead of "WS-SecureConversationSESSION KEY HASH") and store it in key3.
3. hash
You need to create an SHA1-HMAC hash with key2 and the nonce. Take a look at this pseudo-code:
hash = SHA1-HMAC(key2, nonce)
Let's store the data in hash
4. Pad the nonce
The official client appends to the nonce 8 bytes with the value 08 (hex)
5. Create 8 bytes of random data. These will be used in the next step.
6. TripleDes CBC encryption.
We need to use the TripleDes algorithm. Set the mode to CBC. As IV set the data obtained in step 5. As key use the key3. As input use the padded nonce (see step 4). Let's store the resulting data in a variable called encrypted_data.
7. Filling the struct
The header elements should have the value that is indicated in the comments next to them. (If you plan to use non-default values, adjust accordingly). The aIVBytes element should be assigned the data obtained in step 5. The aHashBytes element should be assigned the data of hash (see step 3). The aCipherBytes element should be assigned the data of encrypted_data (see step 6).
8. Base64 encode the struct
Now you need to base64-encode the struct. If you're using C or C++ you have to typecast the struct variable to "char*" to be able to base64 encode it.
These base64-endoded data are the return value that you need to send to the server.
Test Values
Nonce: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= Binary Secret: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= IV(hex): 00 00 00 00 00 00 00 00 Result (newline added readability): HAAAAAEAAAADZgAABIAAAAgAAAAUAAAASAAAAAAAAAAAAAAA7XgT5ohvaZdoXdrWUUcMF2G8OK2JohyY cK5l5MJSitab33scxJeK/RQXcUr0L+R2ZA9CEAzn0izmUzSMp2LZdxSbHtnuxCmptgtoScHp9E26HjQVkA9YJxgK/HM=
Nonce: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB= Binary Secret: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB= IV(hex): 00 00 00 00 00 00 00 00 Result (newline added readability): HAAAAAEAAAADZgAABIAAAAgAAAAUAAAASAAAAAAAAAAAAAAAywfWRZVnRRZTqPkW6HBIrOmPuYiFbzcpv YmP2QzhpH+VdKwtqUTt/gdbDqlMZvR1o7ve9ex44otMOxYtnNYIQ+lfoj+PKcsHT+T7GA1hfMsTVbGqoYYe3B5/WW0=
Code Examples
VC++ (MFC) MBI Hash Example
C++ QT4 QCA - SSO Crypto Example
VB .NET: MBI Code
C++ (cross platform): Simple implementation that computes the return value. Uses openssl for the crypto functions. Also it has hardcoded IV, nonce and binary secret to the first test values of this wiki page. It a proof of concept for others to built on and understand the documentation.
References
SingleSignOn WSDL & XSD files
Zoronax's Blog
MSNP15 authentication scheme REd