Protocols/MSNP/MSNP15/SSO

From NINA Wiki
Jump to navigation Jump to search
MSNP Protocol
Version 15
General
OverviewChanges
Single Sign-OnTicket Tokens
New Features
Locations
Roaming Content
Overview
IntroductionTermsClients
Reference
Error ListCommandsRelying Party SuiteSpotlife
Services
XMPPHTTP GatewayTabsActivities
Documentation
Development ToolsMSNP Grid
PolygamyURLs used by MSN
Documents
Protocol Versions
Version 21
Version 18
Version 16
Version 15
Version 14
Version 13
Version 12
Version 11
Version 9
Version 8
Version 2
MSNC
IntroductionP2PObject DescriptorDisplay PicturesFile Transfer
Scenarios
Microsoft Messenger for Mac
MSNP on WebTV (MSNTV)


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