diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2010-08-11 09:08:39 +0100 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2010-08-11 09:08:39 +0100 |
commit | 523fb2324a351e9607ad2a803c6e866c5175aa16 (patch) | |
tree | 52e1d753a149196a50630415d51bb22f46b9b94e /protocols/msn/soap.c | |
parent | 7db65b7df08a3c7cab28e065b2ffa3d9941ceccb (diff) |
Implement MSNP15 SSO (Sadistic Sign-On).
Diffstat (limited to 'protocols/msn/soap.c')
-rw-r--r-- | protocols/msn/soap.c | 175 |
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; } |