aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/msn/soap.c
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2010-08-11 09:08:39 +0100
committerWilmer van der Gaast <wilmer@gaast.net>2010-08-11 09:08:39 +0100
commit523fb2324a351e9607ad2a803c6e866c5175aa16 (patch)
tree52e1d753a149196a50630415d51bb22f46b9b94e /protocols/msn/soap.c
parent7db65b7df08a3c7cab28e065b2ffa3d9941ceccb (diff)
Implement MSNP15 SSO (Sadistic Sign-On).
Diffstat (limited to 'protocols/msn/soap.c')
-rw-r--r--protocols/msn/soap.c175
1 files changed, 165 insertions, 10 deletions
diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c
index 252bddeb..e837986e 100644
--- a/protocols/msn/soap.c
+++ b/protocols/msn/soap.c
@@ -27,6 +27,7 @@
#include "bitlbee.h"
#include "url.h"
#include "misc.h"
+#include "sha1.h"
#include "base64.h"
#include "xmltree.h"
#include <ctype.h>
@@ -82,27 +83,25 @@ static void msn_soap_handle_response( struct http_request *http_req );
static int msn_soap_send_request( struct msn_soap_req_data *soap_req )
{
- struct msn_data *md = soap_req->ic->proto_data;
char *http_req;
- char *pom, *s;
+ char *soap_action = NULL;
url_t url;
soap_req->build_request( soap_req );
- pom = g_new0( char, strlen( md->passport_token ) * 3 );
- strcpy( pom, md->passport_token + 2 );
- if( ( s = strchr( pom, '&' ) ) )
- *s = '\0';
+ if( soap_req->action )
+ soap_action = g_strdup_printf( "SOAPAction: \"%s\"\r\n", soap_req->action );
url_set( &url, soap_req->url );
http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host,
- soap_req->action, pom,
+ soap_action ? soap_action : "",
strlen( soap_req->payload ), soap_req->payload );
soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS,
http_req, msn_soap_handle_response, soap_req );
g_free( http_req );
+ g_free( soap_action );
return soap_req->http_req != NULL;
}
@@ -139,6 +138,160 @@ static void msn_soap_handle_response( struct http_request *http_req )
}
+/* passport_sso: Authentication MSNP15+ */
+
+struct msn_soap_passport_sso_data
+{
+ char *policy;
+ char *nonce;
+ char *secret;
+};
+
+static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req )
+{
+ struct msn_soap_passport_sso_data *sd = soap_req->data;
+ struct im_connection *ic = soap_req->ic;
+
+ soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL );
+ soap_req->payload = g_markup_printf_escaped( SOAP_PASSPORT_SSO_PAYLOAD,
+ ic->acc->user, ic->acc->pass, sd->policy );
+
+ return MSN_SOAP_OK;
+}
+
+static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer data )
+{
+ struct msn_soap_req_data *soap_req = data;
+ struct msn_soap_passport_sso_data *sd = soap_req->data;
+ struct msn_data *md = soap_req->ic->proto_data;
+ struct xt_node *p;
+ char *id;
+
+ if( ( id = xt_find_attr( node, "Id" ) ) == NULL )
+ return XT_HANDLED;
+ id += strlen( id ) - 1;
+ if( *id == '1' &&
+ ( p = node->parent ) && ( p = p->parent ) &&
+ ( p = xt_find_node( p->children, "wst:RequestedProofToken" ) ) &&
+ ( p = xt_find_node( p->children, "wst:BinarySecret" ) ) &&
+ p->text )
+ sd->secret = g_strdup( p->text );
+
+ if( *id == '1' )
+ md->tokens[0] = g_strdup( node->text );
+ else if( *id == '2' )
+ md->tokens[1] = g_strdup( node->text );
+
+ return XT_HANDLED;
+}
+
+static const struct xt_handler_entry msn_soap_passport_sso_parser[] = {
+ { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token },
+ { NULL, NULL, NULL }
+};
+
+static char *msn_key_fuckery( char *key, int key_len, char *type )
+{
+ unsigned char hash1[20+strlen(type)+1];
+ unsigned char hash2[20];
+ char *ret;
+
+ sha1_hmac( key, key_len, type, 0, hash1 );
+ strcpy( (char*) hash1 + 20, type );
+ sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash2 );
+
+ /* This is okay as hash1 is read completely before it's overwritten. */
+ sha1_hmac( key, key_len, (char*) hash1, 20, hash1 );
+ sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash1 );
+
+ ret = g_malloc( 24 );
+ memcpy( ret, hash2, 20 );
+ memcpy( ret + 20, hash1, 4 );
+ return ret;
+}
+
+static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap_req )
+{
+ struct msn_soap_passport_sso_data *sd = soap_req->data;
+ struct im_connection *ic = soap_req->ic;
+ char *key1, *key2, *key3, *blurb64;
+ int key1_len;
+ unsigned char *padnonce, *des3res;
+ struct
+ {
+ 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
+ unsigned char iv[8];
+ unsigned char hash[20];
+ unsigned char cipherbytes[72];
+ } blurb = {
+ GUINT32_TO_LE( 28 ),
+ GUINT32_TO_LE( 1 ),
+ GUINT32_TO_LE( 0x6603 ),
+ GUINT32_TO_LE( 0x8004 ),
+ GUINT32_TO_LE( 8 ),
+ GUINT32_TO_LE( 20 ),
+ GUINT32_TO_LE( 72 ),
+ };
+
+ key1_len = base64_decode( sd->secret, (unsigned char**) &key1 );
+
+ key2 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY HASH" );
+ key3 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION" );
+
+ sha1_hmac( key2, 24, sd->nonce, 0, blurb.hash );
+ padnonce = g_malloc( strlen( sd->nonce ) + 8 );
+ strcpy( (char*) padnonce, sd->nonce );
+ memset( padnonce + strlen( sd->nonce ), 8, 8 );
+
+ random_bytes( blurb.iv, 8 );
+
+ ssl_des3_encrypt( (unsigned char*) key3, 24, padnonce, strlen( sd->nonce ) + 8, blurb.iv, &des3res );
+ memcpy( blurb.cipherbytes, des3res, 72 );
+
+ blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ) );
+ msn_auth_got_passport_token( ic, blurb64 );
+
+ g_free( padnonce );
+ g_free( blurb64 );
+ g_free( des3res );
+ g_free( key1 );
+ g_free( key2 );
+ g_free( key3 );
+
+ return MSN_SOAP_OK;
+}
+
+static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req )
+{
+ struct msn_soap_passport_sso_data *sd = soap_req->data;
+
+ g_free( sd->policy );
+ g_free( sd->nonce );
+ g_free( sd->secret );
+
+ return MSN_SOAP_OK;
+}
+
+int msn_soap_passport_sso_request( struct im_connection *ic, const char *policy, const char *nonce )
+{
+ struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1 );
+
+ sd->policy = g_strdup( policy );
+ sd->nonce = g_strdup( nonce );
+
+ return msn_soap_start( ic, sd, msn_soap_passport_sso_build_request,
+ msn_soap_passport_sso_parser,
+ msn_soap_passport_sso_handle_response,
+ msn_soap_passport_sso_free_data );
+}
+
+
/* oim_send: Sending offline messages */
struct msn_soap_oim_send_data
@@ -161,13 +314,13 @@ static int msn_soap_oim_build_request( struct msn_soap_req_data *soap_req )
soap_req->url = g_strdup( SOAP_OIM_SEND_URL );
soap_req->action = g_strdup( SOAP_OIM_SEND_ACTION );
soap_req->payload = g_markup_printf_escaped( SOAP_OIM_SEND_PAYLOAD,
- ic->acc->user, display_name_b64, oim->to, md->passport_token,
+ ic->acc->user, display_name_b64, oim->to, "bla", //md->passport_token,
MSNP11_PROD_ID, md->lock_key ? md->lock_key : "",
oim->number, oim->number, oim->msg );
g_free( display_name_b64 );
- return 1;
+ return MSN_SOAP_OK;
}
static xt_status msn_soap_oim_send_challenge( struct xt_node *node, gpointer data )
@@ -219,7 +372,7 @@ static int msn_soap_oim_free_data( struct msn_soap_req_data *soap_req )
g_free( oim->msg );
g_free( oim );
- return 0;
+ return MSN_SOAP_OK;
}
int msn_soap_oim_send( struct im_connection *ic, const char *to, const char *msg )
@@ -262,6 +415,8 @@ int msn_soap_oim_send_queue( struct im_connection *ic, GSList **msgq )
*msgq = g_slist_remove( *msgq, m );
}
+
+ return 1;
}