From 04c5581dc25b8a5823a067d1647d731e8454a1de Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Wed, 14 Dec 2011 21:21:01 +0200 Subject: [PATCH] ms-dlx: send SearchAbRequest to service DLX Web Service does not accept signed Web Tickets. Update sipe-webticket.c to also generate unsigned Web Tickets. --- src/core/sipe-buddy.c | 51 ++++++++++-- src/core/sipe-svc.c | 41 +++++++++ src/core/sipe-svc.h | 20 ++++- src/core/sipe-tls.c | 2 +- src/core/sipe-webticket.c | 206 +++++++++++++++++++++++++--------------------- 5 files changed, 213 insertions(+), 107 deletions(-) diff --git a/src/core/sipe-buddy.c b/src/core/sipe-buddy.c index 03f5d354..38d7870d 100644 --- a/src/core/sipe-buddy.c +++ b/src/core/sipe-buddy.c @@ -49,6 +49,7 @@ #include "sipe-schedule.h" #include "sipe-session.h" #include "sipe-subscriptions.h" +#include "sipe-svc.h" #include "sipe-utils.h" #include "sipe-webticket.h" #include "sipe-xml.h" @@ -655,6 +656,29 @@ static void get_info_finalize(struct sipe_core_private *sipe_private, sipe_backend_buddy_info_finalize(SIPE_CORE_PUBLIC, info, uri); } +static void ab_entry_response(struct sipe_core_private *sipe_private, + const gchar *uri, + SIPE_UNUSED_PARAMETER const gchar *raw, + sipe_xml *soap_body, + gpointer callback_data) +{ + gchar *who = callback_data; + + if (soap_body) { + + SIPE_DEBUG_INFO("ab_entry_response: received valid SOAP message from service %s", + uri); + } + + /* request failed: this will show the minmum information */ + get_info_finalize(sipe_private, + NULL, + who, + NULL, + NULL); + g_free(who); +} + static void ms_dlx_webticket(struct sipe_core_private *sipe_private, const gchar *base_uri, const gchar *auth_uri, @@ -664,30 +688,39 @@ static void ms_dlx_webticket(struct sipe_core_private *sipe_private, gchar *who = callback_data; if (wsse_security) { + gchar *search = g_strdup_printf("msRTCSIP-PrimaryUserAddress" + "%s", + who); SIPE_DEBUG_INFO("ms_dlx_webticket: got ticket for %s", base_uri); - /* TBD... MS-DLX request to auth_uri */ - (void) auth_uri; - get_info_finalize(sipe_private, - NULL, - who, - NULL, - NULL); + if (sipe_svc_ab_entry_request(sipe_private, + auth_uri, + wsse_security, + search, + ab_entry_response, + who)) { + /* callback data passed down the line */ + who = NULL; + } + g_free(search); } else { /* no ticket: this will show the minmum information */ SIPE_DEBUG_ERROR("ms_dlx_webticket: no web ticket for %s", base_uri); + } + + if (who) { + /* request failed: this will show the minmum information */ get_info_finalize(sipe_private, NULL, who, NULL, NULL); + g_free(who); } - - g_free(who); } static gboolean process_get_info_response(struct sipe_core_private *sipe_private, diff --git a/src/core/sipe-svc.c b/src/core/sipe-svc.c index 90fd5fda..936b3baa 100644 --- a/src/core/sipe-svc.c +++ b/src/core/sipe-svc.c @@ -337,6 +337,47 @@ gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, return(ret); } +gboolean sipe_svc_ab_entry_request(struct sipe_core_private *sipe_private, + const gchar *uri, + const gchar *wsse_security, + const gchar *search, + sipe_svc_callback *callback, + gpointer callback_data) +{ + gboolean ret; + gchar *soap_body = g_strdup_printf("" + " " + " " + " " + " %s" + " " + " " + " " + " false" + " 1" + " displayName,msRTCSIP-PrimaryUserAddress,telephoneNumber,homePhone,mobile,otherTelephone,custom1Phone,mail,company,country" + " " + " " + "", + search); + + ret = new_soap_req(sipe_private, + uri, + "DistributionListExpander/IAddressBook/SearchAbEntry", + wsse_security, + soap_body, + sipe_svc_wsdl_response, + callback, + callback_data); + g_free(soap_body); + + return(ret); +} + /* * This functions encodes what the Microsoft Lync client does for * Office365 accounts. It will most definitely fail for internal Lync diff --git a/src/core/sipe-svc.h b/src/core/sipe-svc.h index 8f1af4b8..d4f32b25 100644 --- a/src/core/sipe-svc.h +++ b/src/core/sipe-svc.h @@ -56,7 +56,7 @@ typedef void (sipe_svc_callback)(struct sipe_core_private *sipe_private, * @param certreq certificate request (Base64 encoded) * @param callback callback function * @param callback_data callback data - * @return @c TRUE if token fetch was triggered + * @return @c TRUE if certificate fetch was triggered */ gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, const gchar *uri, @@ -66,6 +66,24 @@ gboolean sipe_svc_get_and_publish_cert(struct sipe_core_private *sipe_private, gpointer callback_data); /** + * Trigger [MS-DLX] address book entry search + * + * @param sipe_private SIPE core private data + * @param uri service URI + * @param wsse_security predefined authentication token + * @param search [MS-DLX] AbEntryRequest.ChangeSearchQuery in XML + * @param callback callback function + * @param callback_data callback data + * @return @c TRUE if search was triggered + */ +gboolean sipe_svc_ab_entry_request(struct sipe_core_private *sipe_private, + const gchar *uri, + const gchar *wsse_security, + const gchar *search, + sipe_svc_callback *callback, + gpointer callback_data); + +/** * Trigger fetch of WebTicket security token * * @param sipe_private SIPE core private data diff --git a/src/core/sipe-tls.c b/src/core/sipe-tls.c index eb9f9aa8..c5311ae0 100644 --- a/src/core/sipe-tls.c +++ b/src/core/sipe-tls.c @@ -226,7 +226,7 @@ void sipe_tls_fill_random(struct sipe_tls_random *random, guint bytes = ((bits + 15) / 16) * 2; guint16 *p = g_malloc(bytes); - SIPE_DEBUG_INFO("sipe_svc_fill_random: %d bits -> %d bytes", + SIPE_DEBUG_INFO("sipe_tls_fill_random: %d bits -> %d bytes", bits, bytes); random->buffer = (guint8*) p; diff --git a/src/core/sipe-webticket.c b/src/core/sipe-webticket.c index 7094c29e..0c3c4567 100644 --- a/src/core/sipe-webticket.c +++ b/src/core/sipe-webticket.c @@ -53,6 +53,7 @@ struct webticket_callback_data { gboolean tried_fedbearer; gboolean webticket_for_service; + gboolean requires_signing; struct sipe_tls_random entropy; @@ -153,106 +154,114 @@ static gchar *generate_sha1_proof_wsse(const gchar *raw, gchar *wsse_security = NULL; if (timestamp && keydata) { - gchar *assertionID = extract_raw_xml_attribute(keydata, - "AssertionID"); - - /* - * WS-Trust 1.3 - * - * http://docs.oasis-open.org/ws-sx/ws-trust/200512/CK/PSHA1: - * - * "The key is computed using P_SHA1() from the TLS sepcification to generate - * a bit stream using entropy from both sides. The exact form is: - * - * key = P_SHA1(Entropy_REQ, Entropy_RES)" - */ - gchar *entropy_res_base64 = extract_raw_xml(raw, "BinarySecret", FALSE); - gsize entropy_res_length; - guchar *entropy_response = g_base64_decode(entropy_res_base64, - &entropy_res_length); - guchar *key = sipe_tls_p_sha1(entropy->buffer, - entropy->length, - entropy_response, - entropy_res_length, - entropy->length); - g_free(entropy_response); - g_free(entropy_res_base64); - - SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found timestamp & keydata"); - - if (assertionID && key) { - /* same as SIPE_DIGEST_HMAC_SHA1_LENGTH */ - guchar digest[SIPE_DIGEST_SHA1_LENGTH]; - gchar *base64; - gchar *signed_info; - gchar *canon; - - SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found assertionID and successfully computed the key"); - - /* Digest over reference element (#timestamp -> wsu:Timestamp) */ - sipe_digest_sha1((guchar *) timestamp, - strlen(timestamp), - digest); - base64 = g_base64_encode(digest, - SIPE_DIGEST_SHA1_LENGTH); - - /* XML-Sig: SignedInfo for reference element */ - signed_info = g_strdup_printf("" - "" - "" - "" - "" - "" - "" - "" - "%s" - "" - "", - base64); - g_free(base64); - - /* XML-Sig: SignedInfo in canonical form */ - canon = sipe_xml_exc_c14n(signed_info); - g_free(signed_info); - - if (canon) { - gchar *signature; - - /* calculate signature */ - sipe_digest_hmac_sha1(key, entropy->length, - (guchar *)canon, - strlen(canon), - digest); + if (entropy) { + gchar *assertionID = extract_raw_xml_attribute(keydata, + "AssertionID"); + + /* + * WS-Trust 1.3 + * + * http://docs.oasis-open.org/ws-sx/ws-trust/200512/CK/PSHA1: + * + * "The key is computed using P_SHA1() from the TLS sepcification to generate + * a bit stream using entropy from both sides. The exact form is: + * + * key = P_SHA1(Entropy_REQ, Entropy_RES)" + */ + gchar *entropy_res_base64 = extract_raw_xml(raw, "BinarySecret", FALSE); + gsize entropy_res_length; + guchar *entropy_response = g_base64_decode(entropy_res_base64, + &entropy_res_length); + guchar *key = sipe_tls_p_sha1(entropy->buffer, + entropy->length, + entropy_response, + entropy_res_length, + entropy->length); + g_free(entropy_response); + g_free(entropy_res_base64); + + SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found timestamp & keydata"); + + if (assertionID && key) { + /* same as SIPE_DIGEST_HMAC_SHA1_LENGTH */ + guchar digest[SIPE_DIGEST_SHA1_LENGTH]; + gchar *base64; + gchar *signed_info; + gchar *canon; + + SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found assertionID and successfully computed the key"); + + /* Digest over reference element (#timestamp -> wsu:Timestamp) */ + sipe_digest_sha1((guchar *) timestamp, + strlen(timestamp), + digest); base64 = g_base64_encode(digest, - SIPE_DIGEST_HMAC_SHA1_LENGTH); - - /* XML-Sig: Signature from SignedInfo + Key */ - signature = g_strdup_printf("" - " %s" - " %s" - " " - " " - " %s" - " " - " " - "", - canon, - base64, - assertionID); + SIPE_DIGEST_SHA1_LENGTH); + + /* XML-Sig: SignedInfo for reference element */ + signed_info = g_strdup_printf("" + "" + "" + "" + "" + "" + "" + "" + "%s" + "" + "", + base64); g_free(base64); - g_free(canon); - wsse_security = g_strconcat(timestamp, - keydata, - signature, - NULL); - g_free(signature); + /* XML-Sig: SignedInfo in canonical form */ + canon = sipe_xml_exc_c14n(signed_info); + g_free(signed_info); + + if (canon) { + gchar *signature; + + /* calculate signature */ + sipe_digest_hmac_sha1(key, entropy->length, + (guchar *)canon, + strlen(canon), + digest); + base64 = g_base64_encode(digest, + SIPE_DIGEST_HMAC_SHA1_LENGTH); + + /* XML-Sig: Signature from SignedInfo + Key */ + signature = g_strdup_printf("" + " %s" + " %s" + " " + " " + " %s" + " " + " " + "", + canon, + base64, + assertionID); + g_free(base64); + g_free(canon); + + wsse_security = g_strconcat(timestamp, + keydata, + signature, + NULL); + g_free(signature); + } + } + g_free(key); + g_free(assertionID); + } else { + /* token doesn't require signature */ + SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found timestamp & keydata, no signing required"); + wsse_security = g_strconcat(timestamp, + keydata, + NULL); } - - g_free(key); - g_free(assertionID); } g_free(keydata); @@ -273,7 +282,7 @@ static void webticket_token(struct sipe_core_private *sipe_private, /* WebTicket for Web Service */ if (wcd->webticket_for_service) { gchar *wsse_security = generate_sha1_proof_wsse(raw, - &wcd->entropy); + wcd->requires_signing ? &wcd->entropy : NULL); if (wsse_security) { /* callback takes ownership of wsse_security */ @@ -450,9 +459,14 @@ static void service_metadata(struct sipe_core_private *sipe_private, ticket_uri = sipe_xml_data(sipe_xml_child(node, "ExactlyOne/All/EndorsingSupportingTokens/Policy/IssuedToken/Issuer/Address")); - if (!ticket_uri) + if (ticket_uri) { + /* this token type requires signing */ + wcd->requires_signing = TRUE; + } else { + /* try alternative token type */ ticket_uri = sipe_xml_data(sipe_xml_child(node, "ExactlyOne/All/SignedSupportingTokens/Policy/IssuedToken/Issuer/Address")); + } if (ticket_uri) { SIPE_DEBUG_INFO("webservice_metadata: WebTicket URI %s", ticket_uri); } -- 2.11.4.GIT