Protocols/MSNP/Reference/Relaying Party Suite

From NINA Wiki
Jump to navigation Jump to search
Relaying Party Suite, also known as RPS or `SSO` (Single Sign-On) authentication is a challenge-response method introduced in MSNP15 and stayed in the protocol as a primary authentication mechanism up to when MSNP21 was unveiled (and past the MSN realm, MSNP22 but as a secondary mechanism and possibly not used officially). The mechanism involves retrieving a challenge string from the notification server, authenticating through a web service to get a binary secret and hashing it with several HMAC hash functions, and using the resulting HMAC hash to encrypt the challenge string and store it in a binary structure that's then encoded and sent back to the notification server to complete the login process.

When logging in on MSNP15+, you send a `USR SSO I` command with your email address as a parameter, and in return should get a `USR SSO S` with a policy and a challenge string, which is usually a randomly generated Base64-encoded value (in our implementation we simply generate 48 random bytes of data and Base64-encode it):

```
<<< USR [TrID] SSO I [email]
>>> USR [TrID] SSO S [policy] [challenge string]
```

The policy is used when querying the web service for the binary secret and tokens, but the challenge string itself is a crucial part of the RPS process and necessary for creating the end result.

After this is sent, authentication to a web service is performed, which in the case of official MSN clients is done on RST.srf. The technical details of how that works as a whole is out of this document's scope, but for our purposes we'll summarize how it works. The requesting client supplies account credentials and a list of domains to authenticate to, and the service returns the tokens for each domain if successful. In the `messengerclear.live.com` domain, there's also a unique binary secret defined that the client will need for RPS authentication.

Once the binary secret is obtained, it has to be Base64-decoded and used to derive a TripleDES key used in the encryption process. The process for this involves SHA1-HMAC using the decoded binary secret as a key, and goes as follows:

- Hash the message `WS-SecureConversationSESSION KEY HASH` with SHA1-HMAC - this will be referred to as `hash1`
- Hash a concatenation of `hash1` and the same message from before with SHA1-HMAC - this will be referred to as `hash2` and will be needed later on
- Hash `hash1` with SHA1-HMAC - this will be referred to as `hash3`
- Hash a concatenation of `hash3` and the same message used to create `hash1` with SHA1-HMAC - this will be referred to as `hash4` and will be needed later on.

After creating all 4 hashes, the first 20 bytes of `hash2` and the first 4 bytes of `hash4` have to be combined to create the resulting key. This will be referred to as `key2` in this document (`key1` would be the binary secret). `key3` is generated in a similar way, but the only difference is that the starting message is `WS-SecureConversationSESSION KEY ENCRYPTION` instead of `WS-SecureConversationSESSION KEY HASH`.

Now the client is at the stage where it has to start creating the hash and cipher responses to send back to the notification server. To create the hash response, an SHA1-HMAC is performed on the challenge string retrieved earlier, using `key2` as the key. Before creating the cipher response, TripleDES encryption capable of utilizing CBC mode will have to be set up, and PKCS#5 padding for messages will have to be implemented. A random 8-byte value will also have to be generated as an IV for the encryption process. To create the cipher, the challenge string has to be encrypted with `key3` as the key and the randomly generated value as the IV.

The IV, final hash, and cipher are then bundled up in a struct, with all packed values being little endian and unless stated otherwise, are unsigned 32-bit integers.

```
structHeaderSize (4 bytes) - Counts the length of the header (the data before the IV/cipher and hash). The length includes the length of this value.

cryptMode (4 bytes) - Defines the mode the encryption algorithm operated under. Typical value has been observed as CRYPT_MODE_CBC (0x00000001).

cipherType (4 bytes) - Defines the type of encryption algorithm used to generate the cipher. Typical value has been observed as 0x6603 (TripleDES).

hashType (4 bytes) - Defines the type of hash algorithm used to generate the hash. Typical value has been observed as 0x8004 (SHA-1).

ivLen (4 bytes) - Length of the IV in the struct. Typical value has been observed as 8.

hashLen (4 bytes) - Length of the hash in the struct. Typical value has been observed as 20.

cipherLen (4 bytes) - Length of the cipher in the struct. Typical value has been reported as 72, but can and will change depending on the length of the challenge string that has been encrypted.

---------------

ivBytes (variable-length, but usually 8 bytes) - A byte array containing the IV used to create the cipher.

hashBytes (variable-length, but usually 20 bytes) - A byte array containing the hash response generated.

cipherBytes (variable-length) - A byte array containing the cipher generated.
```

This value is then Base64-encoded and sent along with some other parameters in a `USR SSO S` to the server to be verified:

```
<<< USR [TrID] SSO S [token] [base64-encoded struct] [...]
```