2 * @file sipe-certificate.c
6 * Copyright (C) 2011 SIPE Project <http://sipe.sourceforge.net/>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * Specification references:
26 * - [MS-SIPAE]: http://msdn.microsoft.com/en-us/library/cc431510.aspx
27 * - [MS-OCAUTHWS]: http://msdn.microsoft.com/en-us/library/ff595592.aspx
28 * - MS Tech-Ed Europe 2010 "UNC310: Microsoft Lync 2010 Technology Explained"
29 * http://ecn.channel9.msdn.com/o9/te/Europe/2010/pptx/unc310.pptx
40 #include "sipe-common.h"
41 #include "sipe-backend.h"
42 #include "sipe-core.h"
43 #include "sipe-core-private.h"
44 #include "sipe-certificate.h"
47 #include "sipe-utils.h"
50 struct certificate_callback_data
{
53 gchar
*webticket_anon_uri
;
54 gchar
*webticket_fedbearer_uri
;
57 gboolean tried_fedbearer
;
59 struct sipe_svc_random entropy
;
62 static void callback_data_free(struct certificate_callback_data
*ccd
)
66 g_free(ccd
->authuser
);
67 g_free(ccd
->webticket_anon_uri
);
68 g_free(ccd
->webticket_fedbearer_uri
);
69 g_free(ccd
->certprov_uri
);
70 sipe_svc_free_random(&ccd
->entropy
);
75 gpointer
sipe_certificate_tls_dsk_find(struct sipe_core_private
*sipe_private
,
87 static void certificate_failure(struct sipe_core_private
*sipe_private
,
89 const gchar
*parameter
)
91 gchar
*tmp
= g_strdup_printf(format
, parameter
);
92 sipe_backend_connection_error(SIPE_CORE_PUBLIC
,
93 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED
,
98 static gchar
*extract_raw_xml(const gchar
*xml
,
100 gboolean include_tag
)
102 gchar
*tag_start
= g_strdup_printf("<%s", tag
);
103 gchar
*tag_end
= g_strdup_printf("</%s>", tag
);
105 const gchar
*start
= strstr(xml
, tag_start
);
108 const gchar
*end
= strstr(start
+ strlen(tag_start
), tag_end
);
111 data
= g_strndup(start
, end
+ strlen(tag_end
) - start
);
113 const gchar
*tmp
= strchr(start
+ strlen(tag_start
), '>') + 1;
114 data
= g_strndup(tmp
, end
- tmp
);
124 static void webticket_token(struct sipe_core_private
*sipe_private
,
128 gpointer callback_data
)
130 struct certificate_callback_data
*ccd
= callback_data
;
131 gboolean success
= (uri
== NULL
); /* abort case */
134 gchar
*lifetime
= extract_raw_xml(raw
, "wst:Lifetime", FALSE
);
135 gchar
*keydata
= extract_raw_xml(raw
, "EncryptedData", TRUE
);
137 if (lifetime
&& keydata
) {
138 gchar
*webticket_xml
;
140 SIPE_DEBUG_INFO("webticket_token: received valid SOAP message from service %s",
143 /* Create security data for request */
144 webticket_xml
= g_strdup_printf("<wsu:TimeStamp>%s</wsu:TimeStamp>%s",
149 SIPE_DEBUG_INFO("webticket_token: TOKEN\n%s", webticket_xml
);
150 g_free(webticket_xml
);
157 /* Retry with federated authentication? */
158 success
= !ccd
->webticket_fedbearer_uri
|| ccd
->tried_fedbearer
;
160 SIPE_DEBUG_INFO("webticket_token: anonymous authentication to service %s failed, retrying with federated authentication",
163 ccd
->tried_fedbearer
= TRUE
;
164 success
= sipe_svc_webticket_lmc(sipe_private
,
166 ccd
->webticket_fedbearer_uri
,
170 /* callback data passed down the line */
177 certificate_failure(sipe_private
,
178 _("Web ticket request to %s failed"),
182 callback_data_free(ccd
);
185 static void webticket_metadata(struct sipe_core_private
*sipe_private
,
187 SIPE_UNUSED_PARAMETER
const gchar
*raw
,
189 gpointer callback_data
)
191 struct certificate_callback_data
*ccd
= callback_data
;
194 const sipe_xml
*node
;
196 SIPE_DEBUG_INFO("webticket_metadata: metadata for service %s retrieved successfully",
199 /* Authentication ports accepted by WebTicket Service */
200 for (node
= sipe_xml_child(metadata
, "service/port");
202 node
= sipe_xml_twin(node
)) {
203 const gchar
*auth_uri
= sipe_xml_attribute(sipe_xml_child(node
,
208 if (sipe_strcase_equal(sipe_xml_attribute(node
, "name"),
209 "WebTicketServiceAnon")) {
210 SIPE_DEBUG_INFO("webticket_metadata: WebTicket Anon Auth URI %s", auth_uri
);
211 g_free(ccd
->webticket_anon_uri
);
212 ccd
->webticket_anon_uri
= g_strdup(auth_uri
);
213 } else if (sipe_strcase_equal(sipe_xml_attribute(node
, "name"),
215 SIPE_DEBUG_INFO("webticket_metadata: WebTicket Anon Auth URI %s", auth_uri
);
216 g_free(ccd
->webticket_fedbearer_uri
);
217 ccd
->webticket_fedbearer_uri
= g_strdup(auth_uri
);
222 if (ccd
->webticket_anon_uri
|| ccd
->webticket_fedbearer_uri
) {
225 if (ccd
->webticket_anon_uri
) {
226 /* Try anonymous authentication first */
227 /* Entropy: 256 random bits */
228 sipe_svc_fill_random(&ccd
->entropy
, 256);
230 success
= sipe_svc_webticket(sipe_private
,
231 ccd
->webticket_anon_uri
,
238 ccd
->tried_fedbearer
= TRUE
;
239 success
= sipe_svc_webticket_lmc(sipe_private
,
241 ccd
->webticket_fedbearer_uri
,
247 /* callback data passed down the line */
250 certificate_failure(sipe_private
,
251 _("Can't request security token from %s"),
252 ccd
->webticket_anon_uri
? ccd
->webticket_anon_uri
: ccd
->webticket_fedbearer_uri
);
256 certificate_failure(sipe_private
,
257 _("Can't find the authentication port for TLS-DSK web ticket URI %s"),
262 certificate_failure(sipe_private
,
263 _("Can't retrieve metadata for TLS-DSK web ticket URI %s"),
267 callback_data_free(ccd
);
270 static void certprov_metadata(struct sipe_core_private
*sipe_private
,
272 SIPE_UNUSED_PARAMETER
const gchar
*raw
,
274 gpointer callback_data
)
276 struct certificate_callback_data
*ccd
= callback_data
;
279 const sipe_xml
*node
;
280 gchar
*ticket_uri
= NULL
;
282 SIPE_DEBUG_INFO("certprov_metadata: metadata for service %s retrieved successfully",
285 /* WebTicket policies accepted by Certificate Provisioning Service */
286 for (node
= sipe_xml_child(metadata
, "Policy");
288 node
= sipe_xml_twin(node
)) {
289 if (sipe_strcase_equal(sipe_xml_attribute(node
, "Id"),
290 "CertProvisioningServiceWebTicketProof_SHA1_policy")) {
292 SIPE_DEBUG_INFO_NOFORMAT("certprov_metadata: WebTicket policy found");
294 ticket_uri
= sipe_xml_data(sipe_xml_child(node
,
295 "ExactlyOne/All/EndorsingSupportingTokens/Policy/IssuedToken/Issuer/Address"));
297 SIPE_DEBUG_INFO("certprov_metadata: WebTicket URI %s", ticket_uri
);
299 certificate_failure(sipe_private
,
300 _("Can't find the WebTicket URI for TLS-DSK certificate provisioning URI %s"),
309 /* Authentication ports accepted by Certificate Provisioning Service */
310 for (node
= sipe_xml_child(metadata
, "service/port");
312 node
= sipe_xml_twin(node
)) {
313 if (sipe_strcase_equal(sipe_xml_attribute(node
, "name"),
314 "CertProvisioningServiceWebTicketProof_SHA1")) {
315 const gchar
*auth_uri
;
317 SIPE_DEBUG_INFO_NOFORMAT("certprov_metadata: authentication port found");
319 auth_uri
= sipe_xml_attribute(sipe_xml_child(node
,
323 SIPE_DEBUG_INFO("certprov_metadata: CertProv Auth URI %s", auth_uri
);
325 if (sipe_svc_metadata(sipe_private
,
329 /* Remember for later */
330 ccd
->certprov_uri
= g_strdup(auth_uri
);
332 /* callback data passed down the line */
335 certificate_failure(sipe_private
,
336 _("Can't request metadata from %s"),
347 certificate_failure(sipe_private
,
348 _("Can't find the authentication port for TLS-DSK certificate provisioning URI %s"),
353 certificate_failure(sipe_private
,
354 _("Can't find the WebTicket Policy for TLS-DSK certificate provisioning URI %s"),
359 certificate_failure(sipe_private
,
360 _("Can't retrieve metadata for TLS-DSK certificate provisioning URI %s"),
364 callback_data_free(ccd
);
367 gboolean
sipe_certificate_tls_dsk_generate(struct sipe_core_private
*sipe_private
,
369 const gchar
*authuser
,
372 struct certificate_callback_data
*ccd
= g_new0(struct certificate_callback_data
, 1);
375 ccd
->target
= g_strdup(target
);
376 ccd
->authuser
= g_strdup(authuser
);
378 ret
= sipe_svc_metadata(sipe_private
, uri
, certprov_metadata
, ccd
);
380 callback_data_free(ccd
);