nss: add RSA crypto functions
[siplcs.git] / src / core / sipe-certificate.c
blobf03ad1b6535891d56781c948618e70cd99a50c33
1 /**
2 * @file sipe-certificate.c
4 * pidgin-sipe
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
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #include <string.h>
38 #include <glib.h>
40 #include "sipe-common.h"
41 #include "sip-transport.h"
42 #include "sipe-backend.h"
43 #include "sipe-core.h"
44 #include "sipe-core-private.h"
45 #include "sipe-certificate.h"
46 #include "sipe-cert-crypto.h"
47 #include "sipe-digest.h"
48 #include "sipe-nls.h"
49 #include "sipe-svc.h"
50 #include "sipe-utils.h"
51 #include "sipe-xml.h"
53 struct sipe_certificate {
54 GHashTable *certificates;
55 struct sipe_cert_crypto *backend;
58 void sipe_certificate_free(struct sipe_core_private *sipe_private)
60 struct sipe_certificate *sc = sipe_private->certificate;
62 if (sc) {
63 g_hash_table_destroy(sc->certificates);
64 sipe_cert_crypto_free(sc->backend);
65 g_free(sc);
69 static gboolean sipe_certificate_init(struct sipe_core_private *sipe_private)
71 struct sipe_certificate *sc;
72 struct sipe_cert_crypto *ssc;
74 if (sipe_private->certificate)
75 return(TRUE);
77 ssc = sipe_cert_crypto_init();
78 if (!ssc) {
79 SIPE_DEBUG_ERROR_NOFORMAT("sipe_certificate_init: crypto backend init FAILED!");
80 return(FALSE);
83 sc = g_new0(struct sipe_certificate, 1);
84 sc->certificates = g_hash_table_new_full(g_str_hash, g_str_equal,
85 g_free,
86 sipe_cert_crypto_destroy);
87 sc->backend = ssc;
89 SIPE_DEBUG_INFO_NOFORMAT("sipe_certificate_init: DONE");
91 sipe_private->certificate = sc;
92 return(TRUE);
95 static gchar *create_certreq(struct sipe_core_private *sipe_private,
96 const gchar *subject)
98 gchar *base64;
100 if (!sipe_certificate_init(sipe_private))
101 return(NULL);
103 SIPE_DEBUG_INFO_NOFORMAT("create_req: generating new certificate request");
105 base64 = sipe_cert_crypto_request(sipe_private->certificate->backend,
106 subject);
107 if (base64) {
108 GString *format = g_string_new(NULL);
109 gsize count = strlen(base64);
110 const gchar *p = base64;
112 /* Base64 needs to be formated correctly */
113 #define CERTREQ_BASE64_LINE_LENGTH 76
114 while (count > 0) {
115 gsize chunk = count > CERTREQ_BASE64_LINE_LENGTH ?
116 CERTREQ_BASE64_LINE_LENGTH : count;
117 g_string_append_len(format, p, chunk);
118 if (chunk == CERTREQ_BASE64_LINE_LENGTH)
119 g_string_append(format, "\r\n");
120 count -= chunk;
121 p += chunk;
124 /* swap Base64 buffers */
125 g_free(base64);
126 base64 = format->str;
127 g_string_free(format, FALSE);
130 return(base64);
133 static void add_certificate(struct sipe_core_private *sipe_private,
134 const gchar *target,
135 gpointer certificate)
137 struct sipe_certificate *sc = sipe_private->certificate;
138 g_hash_table_insert(sc->certificates, g_strdup(target), certificate);
141 gpointer sipe_certificate_tls_dsk_find(struct sipe_core_private *sipe_private,
142 const gchar *target)
144 struct sipe_certificate *sc = sipe_private->certificate;
145 gpointer certificate;
147 if (!target || !sc)
148 return(NULL);
150 certificate = g_hash_table_lookup(sc->certificates, target);
152 /* Let's make sure the certificate is still valid for another hour */
153 if (!sipe_cert_crypto_valid(certificate, 60 * 60)) {
154 SIPE_DEBUG_ERROR("sipe_certificate_tls_dsk_find: certificate for '%s' is invalid",
155 target);
156 return(NULL);
159 return(certificate);
162 struct certificate_callback_data {
163 gchar *target;
164 gchar *authuser;
165 gchar *webticket_anon_uri;
166 gchar *webticket_fedbearer_uri;
167 gchar *certprov_uri;
169 gboolean tried_fedbearer;
170 gboolean webticket_for_certprov;
172 struct sipe_svc_random entropy;
175 static void callback_data_free(struct certificate_callback_data *ccd)
177 if (ccd) {
178 g_free(ccd->target);
179 g_free(ccd->authuser);
180 g_free(ccd->webticket_anon_uri);
181 g_free(ccd->webticket_fedbearer_uri);
182 g_free(ccd->certprov_uri);
183 sipe_svc_free_random(&ccd->entropy);
184 g_free(ccd);
188 static void certificate_failure(struct sipe_core_private *sipe_private,
189 const gchar *format,
190 const gchar *parameter)
192 gchar *tmp = g_strdup_printf(format, parameter);
193 sipe_backend_connection_error(SIPE_CORE_PUBLIC,
194 SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
195 tmp);
196 g_free(tmp);
199 static void get_and_publish_cert(struct sipe_core_private *sipe_private,
200 const gchar *uri,
201 SIPE_UNUSED_PARAMETER const gchar *raw,
202 sipe_xml *soap_body,
203 gpointer callback_data)
205 struct certificate_callback_data *ccd = callback_data;
206 gboolean success = (uri == NULL); /* abort case */
208 if (soap_body) {
209 gchar *cert_base64 = sipe_xml_data(sipe_xml_child(soap_body,
210 "Body/GetAndPublishCertResponse/RequestSecurityTokenResponse/RequestedSecurityToken/BinarySecurityToken"));
212 SIPE_DEBUG_INFO("get_and_publish_cert: received valid SOAP message from service %s",
213 uri);
215 if (cert_base64) {
216 gpointer opaque = sipe_cert_crypto_decode(sipe_private->certificate->backend,
217 cert_base64);
219 SIPE_DEBUG_INFO_NOFORMAT("get_and_publish_cert: found certificate");
221 if (opaque) {
222 add_certificate(sipe_private,
223 ccd->target,
224 opaque);
225 SIPE_DEBUG_INFO("get_and_publish_cert: certificate for target '%s' added",
226 ccd->target);
228 /* Let's try this again... */
229 sip_transport_authentication_completed(sipe_private);
230 success = TRUE;
233 g_free(cert_base64);
238 if (!success) {
239 certificate_failure(sipe_private,
240 _("Certitifcate request to %s failed"),
241 uri);
244 callback_data_free(ccd);
247 static gchar *extract_raw_xml_attribute(const gchar *xml,
248 const gchar *name)
250 gchar *attr_start = g_strdup_printf("%s=\"", name);
251 gchar *data = NULL;
252 const gchar *start = strstr(xml, attr_start);
254 if (start) {
255 const gchar *value = start + strlen(attr_start);
256 const gchar *end = strchr(value, '"');
257 if (end) {
258 data = g_strndup(value, end - value);
262 g_free(attr_start);
263 return(data);
266 static gchar *extract_raw_xml(const gchar *xml,
267 const gchar *tag,
268 gboolean include_tag)
270 gchar *tag_start = g_strdup_printf("<%s", tag);
271 gchar *tag_end = g_strdup_printf("</%s>", tag);
272 gchar *data = NULL;
273 const gchar *start = strstr(xml, tag_start);
275 if (start) {
276 const gchar *end = strstr(start + strlen(tag_start), tag_end);
277 if (end) {
278 if (include_tag) {
279 data = g_strndup(start, end + strlen(tag_end) - start);
280 } else {
281 const gchar *tmp = strchr(start + strlen(tag_start), '>') + 1;
282 data = g_strndup(tmp, end - tmp);
287 g_free(tag_end);
288 g_free(tag_start);
289 return(data);
292 static gchar *generate_timestamp(const gchar *raw,
293 const gchar *lifetime_tag)
295 gchar *lifetime = extract_raw_xml(raw, lifetime_tag, FALSE);
296 gchar *timestamp = NULL;
297 if (lifetime)
298 timestamp = g_strdup_printf("<wsu:Timestamp xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=\"timestamp\">%s</wsu:Timestamp>",
299 lifetime);
300 g_free(lifetime);
301 return(timestamp);
304 static gchar *generate_fedbearer_wsse(const gchar *raw)
306 gchar *timestamp = generate_timestamp(raw, "wst:Lifetime");
307 gchar *keydata = extract_raw_xml(raw, "EncryptedData", TRUE);
308 gchar *wsse_security = NULL;
310 if (timestamp && keydata) {
311 SIPE_DEBUG_INFO_NOFORMAT("generate_fedbearer_wsse: found timestamp & keydata");
312 wsse_security = g_strconcat(timestamp, keydata, NULL);
315 g_free(keydata);
316 g_free(timestamp);
317 return(wsse_security);
320 /* P_SHA1() - see RFC2246 "The TLS Protocol Version 1.0", Section 5 */
321 static guchar *p_sha1(const guchar *secret,
322 gsize secret_length,
323 const guchar *seed,
324 gsize seed_length,
325 gsize output_length)
327 guchar *output = NULL;
330 * output_length == 0 -> illegal
331 * output_length == 1..20 -> iterations = 1
332 * output_length == 21..40 -> iterations = 2
334 if (secret && seed && (output_length > 0)) {
335 guint iterations = (output_length + SIPE_DIGEST_HMAC_SHA1_LENGTH - 1) / SIPE_DIGEST_HMAC_SHA1_LENGTH;
336 guchar *concat = g_malloc(SIPE_DIGEST_HMAC_SHA1_LENGTH + seed_length);
337 guchar A[SIPE_DIGEST_HMAC_SHA1_LENGTH];
338 guchar *p;
340 SIPE_DEBUG_INFO("p_sha1: secret %" G_GSIZE_FORMAT " bytes, seed %" G_GSIZE_FORMAT " bytes",
341 secret_length, seed_length);
342 SIPE_DEBUG_INFO("p_sha1: output %" G_GSIZE_FORMAT " bytes -> %d iterations",
343 output_length, iterations);
345 /* A(1) = HMAC_SHA1(secret, A(0)), A(0) = seed */
346 sipe_digest_hmac_sha1(secret, secret_length,
347 seed, seed_length,
350 /* Each iteration adds SIPE_DIGEST_HMAC_SHA1_LENGTH bytes */
351 p = output = g_malloc(iterations * SIPE_DIGEST_HMAC_SHA1_LENGTH);
353 while (iterations-- > 0) {
354 /* P_SHA1(i) = HMAC_SHA1(secret, A(i) + seed), i = 1, 2, ... */
355 guchar P[SIPE_DIGEST_HMAC_SHA1_LENGTH];
356 memcpy(concat, A, SIPE_DIGEST_HMAC_SHA1_LENGTH);
357 memcpy(concat + SIPE_DIGEST_HMAC_SHA1_LENGTH, seed, seed_length);
358 sipe_digest_hmac_sha1(secret, secret_length,
359 concat, SIPE_DIGEST_HMAC_SHA1_LENGTH + seed_length,
361 memcpy(p, P, SIPE_DIGEST_HMAC_SHA1_LENGTH);
362 p += SIPE_DIGEST_HMAC_SHA1_LENGTH;
364 /* A(i+1) = HMAC_SHA1(secret, A(i)) */
365 sipe_digest_hmac_sha1(secret, secret_length,
366 A, SIPE_DIGEST_HMAC_SHA1_LENGTH,
369 g_free(concat);
372 return(output);
375 static gchar *generate_sha1_proof_wsse(const gchar *raw,
376 struct sipe_svc_random *entropy)
378 gchar *timestamp = generate_timestamp(raw, "Lifetime");
379 gchar *keydata = extract_raw_xml(raw, "saml:Assertion", TRUE);
380 gchar *wsse_security = NULL;
382 if (timestamp && keydata) {
383 gchar *assertionID = extract_raw_xml_attribute(keydata,
384 "AssertionID");
387 * WS-Trust 1.3
389 * http://docs.oasis-open.org/ws-sx/ws-trust/200512/CK/PSHA1:
391 * "The key is computed using P_SHA1() from the TLS sepcification to generate
392 * a bit stream using entropy from both sides. The exact form is:
394 * key = P_SHA1(Entropy_REQ, Entropy_RES)"
396 gchar *entropy_res_base64 = extract_raw_xml(raw, "BinarySecret", FALSE);
397 gsize entropy_res_length;
398 guchar *entropy_response = g_base64_decode(entropy_res_base64,
399 &entropy_res_length);
400 guchar *key = p_sha1(entropy->buffer,
401 entropy->length,
402 entropy_response,
403 entropy_res_length,
404 entropy->length);
405 g_free(entropy_response);
406 g_free(entropy_res_base64);
408 SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found timestamp & keydata");
410 if (assertionID && key) {
411 /* same as SIPE_DIGEST_HMAC_SHA1_LENGTH */
412 guchar digest[SIPE_DIGEST_SHA1_LENGTH];
413 gchar *base64;
414 gchar *signed_info;
415 gchar *canon;
417 SIPE_DEBUG_INFO_NOFORMAT("generate_sha1_proof_wsse: found assertionID and successfully computed the key");
419 /* Digest over reference element (#timestamp -> wsu:Timestamp) */
420 sipe_digest_sha1((guchar *) timestamp,
421 strlen(timestamp),
422 digest);
423 base64 = g_base64_encode(digest,
424 SIPE_DIGEST_SHA1_LENGTH);
426 /* XML-Sig: SignedInfo for reference element */
427 signed_info = g_strdup_printf("<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"
428 "<CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>"
429 "<SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#hmac-sha1\"/>"
430 "<Reference URI=\"#timestamp\">"
431 "<Transforms>"
432 "<Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>"
433 "</Transforms>"
434 "<DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"/>"
435 "<DigestValue>%s</DigestValue>"
436 "</Reference>"
437 "</SignedInfo>",
438 base64);
439 g_free(base64);
441 /* XML-Sig: SignedInfo in canonical form */
442 canon = sipe_xml_exc_c14n(signed_info);
443 g_free(signed_info);
445 if (canon) {
446 gchar *signature;
448 /* calculate signature */
449 sipe_digest_hmac_sha1(key, entropy->length,
450 (guchar *)canon,
451 strlen(canon),
452 digest);
453 base64 = g_base64_encode(digest,
454 SIPE_DIGEST_HMAC_SHA1_LENGTH);
456 /* XML-Sig: Signature from SignedInfo + Key */
457 signature = g_strdup_printf("<Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"
458 " %s"
459 " <SignatureValue>%s</SignatureValue>"
460 " <KeyInfo>"
461 " <wsse:SecurityTokenReference wsse:TokenType=\"http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1\">"
462 " <wsse:KeyIdentifier ValueType=\"http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID\">%s</wsse:KeyIdentifier>"
463 " </wsse:SecurityTokenReference>"
464 " </KeyInfo>"
465 "</Signature>",
466 canon,
467 base64,
468 assertionID);
469 g_free(base64);
470 g_free(canon);
472 wsse_security = g_strconcat(timestamp,
473 keydata,
474 signature,
475 NULL);
476 g_free(signature);
481 g_free(key);
482 g_free(assertionID);
485 g_free(keydata);
486 g_free(timestamp);
487 return(wsse_security);
490 static void webticket_token(struct sipe_core_private *sipe_private,
491 const gchar *uri,
492 const gchar *raw,
493 sipe_xml *soap_body,
494 gpointer callback_data)
496 struct certificate_callback_data *ccd = callback_data;
497 gboolean success = (uri == NULL); /* abort case */
499 if (soap_body) {
500 /* WebTicket for Certificate Provisioning Service */
501 if (ccd->webticket_for_certprov) {
502 gchar *wsse_security = generate_sha1_proof_wsse(raw,
503 &ccd->entropy);
505 if (wsse_security) {
506 gchar *certreq_base64 = create_certreq(sipe_private,
507 ccd->authuser);
509 SIPE_DEBUG_INFO("webticket_token: received valid SOAP message from service %s",
510 uri);
512 if (certreq_base64) {
514 SIPE_DEBUG_INFO_NOFORMAT("webticket_token: created certificate request");
516 success = sipe_svc_get_and_publish_cert(sipe_private,
517 ccd->certprov_uri,
518 ccd->authuser,
519 wsse_security,
520 certreq_base64,
521 get_and_publish_cert,
522 ccd);
523 if (success) {
524 /* callback data passed down the line */
525 ccd = NULL;
527 g_free(certreq_base64);
529 g_free(wsse_security);
532 /* WebTicket for federated authentication */
533 } else {
534 gchar *wsse_security = generate_fedbearer_wsse(raw);
536 if (wsse_security) {
538 SIPE_DEBUG_INFO("webticket_token: received valid SOAP message from service %s",
539 uri);
541 success = sipe_svc_webticket(sipe_private,
542 ccd->webticket_fedbearer_uri,
543 ccd->authuser,
544 wsse_security,
545 ccd->certprov_uri,
546 &ccd->entropy,
547 webticket_token,
548 ccd);
549 ccd->webticket_for_certprov = TRUE;
551 if (success) {
552 /* callback data passed down the line */
553 ccd = NULL;
555 g_free(wsse_security);
559 } else if (uri) {
560 /* Retry with federated authentication? */
561 success = ccd->webticket_fedbearer_uri && !ccd->tried_fedbearer;
562 if (success) {
563 SIPE_DEBUG_INFO("webticket_token: anonymous authentication to service %s failed, retrying with federated authentication",
564 uri);
566 ccd->tried_fedbearer = TRUE;
567 success = sipe_svc_webticket_lmc(sipe_private,
568 ccd->authuser,
569 ccd->webticket_fedbearer_uri,
570 webticket_token,
571 ccd);
572 ccd->webticket_for_certprov = FALSE;
574 if (success) {
575 /* callback data passed down the line */
576 ccd = NULL;
581 if (!success) {
582 certificate_failure(sipe_private,
583 _("Web ticket request to %s failed"),
584 uri);
587 callback_data_free(ccd);
590 static void webticket_metadata(struct sipe_core_private *sipe_private,
591 const gchar *uri,
592 SIPE_UNUSED_PARAMETER const gchar *raw,
593 sipe_xml *metadata,
594 gpointer callback_data)
596 struct certificate_callback_data *ccd = callback_data;
598 if (metadata) {
599 const sipe_xml *node;
601 SIPE_DEBUG_INFO("webticket_metadata: metadata for service %s retrieved successfully",
602 uri);
604 /* Authentication ports accepted by WebTicket Service */
605 for (node = sipe_xml_child(metadata, "service/port");
606 node;
607 node = sipe_xml_twin(node)) {
608 const gchar *auth_uri = sipe_xml_attribute(sipe_xml_child(node,
609 "address"),
610 "location");
612 if (auth_uri) {
613 if (sipe_strcase_equal(sipe_xml_attribute(node, "name"),
614 "WebTicketServiceAnon")) {
615 SIPE_DEBUG_INFO("webticket_metadata: WebTicket Anon Auth URI %s", auth_uri);
616 g_free(ccd->webticket_anon_uri);
617 ccd->webticket_anon_uri = g_strdup(auth_uri);
618 } else if (sipe_strcase_equal(sipe_xml_attribute(node, "name"),
619 "WsFedBearer")) {
620 SIPE_DEBUG_INFO("webticket_metadata: WebTicket FedBearer Auth URI %s", auth_uri);
621 g_free(ccd->webticket_fedbearer_uri);
622 ccd->webticket_fedbearer_uri = g_strdup(auth_uri);
627 if (ccd->webticket_anon_uri || ccd->webticket_fedbearer_uri) {
628 gboolean success;
630 if (ccd->webticket_anon_uri) {
631 /* Try anonymous authentication first */
632 /* Entropy: 256 random bits */
633 sipe_svc_fill_random(&ccd->entropy, 256);
635 success = sipe_svc_webticket(sipe_private,
636 ccd->webticket_anon_uri,
637 ccd->authuser,
638 NULL,
639 ccd->certprov_uri,
640 &ccd->entropy,
641 webticket_token,
642 ccd);
643 ccd->webticket_for_certprov = TRUE;
644 } else {
645 ccd->tried_fedbearer = TRUE;
646 success = sipe_svc_webticket_lmc(sipe_private,
647 ccd->authuser,
648 ccd->webticket_fedbearer_uri,
649 webticket_token,
650 ccd);
651 ccd->webticket_for_certprov = FALSE;
654 if (success) {
655 /* callback data passed down the line */
656 ccd = NULL;
657 } else {
658 certificate_failure(sipe_private,
659 _("Can't request security token from %s"),
660 ccd->webticket_anon_uri ? ccd->webticket_anon_uri : ccd->webticket_fedbearer_uri);
663 } else {
664 certificate_failure(sipe_private,
665 _("Can't find the authentication port for TLS-DSK web ticket URI %s"),
666 uri);
669 } else if (uri) {
670 certificate_failure(sipe_private,
671 _("Can't retrieve metadata for TLS-DSK web ticket URI %s"),
672 uri);
675 callback_data_free(ccd);
678 static void certprov_metadata(struct sipe_core_private *sipe_private,
679 const gchar *uri,
680 SIPE_UNUSED_PARAMETER const gchar *raw,
681 sipe_xml *metadata,
682 gpointer callback_data)
684 struct certificate_callback_data *ccd = callback_data;
686 if (metadata) {
687 const sipe_xml *node;
688 gchar *ticket_uri = NULL;
690 SIPE_DEBUG_INFO("certprov_metadata: metadata for service %s retrieved successfully",
691 uri);
693 /* WebTicket policies accepted by Certificate Provisioning Service */
694 for (node = sipe_xml_child(metadata, "Policy");
695 node;
696 node = sipe_xml_twin(node)) {
697 if (sipe_strcase_equal(sipe_xml_attribute(node, "Id"),
698 "CertProvisioningServiceWebTicketProof_SHA1_policy")) {
700 SIPE_DEBUG_INFO_NOFORMAT("certprov_metadata: WebTicket policy found");
702 ticket_uri = sipe_xml_data(sipe_xml_child(node,
703 "ExactlyOne/All/EndorsingSupportingTokens/Policy/IssuedToken/Issuer/Address"));
704 if (ticket_uri) {
705 SIPE_DEBUG_INFO("certprov_metadata: WebTicket URI %s", ticket_uri);
706 } else {
707 certificate_failure(sipe_private,
708 _("Can't find the WebTicket URI for TLS-DSK certificate provisioning URI %s"),
709 uri);
711 break;
715 if (ticket_uri) {
717 /* Authentication ports accepted by Certificate Provisioning Service */
718 for (node = sipe_xml_child(metadata, "service/port");
719 node;
720 node = sipe_xml_twin(node)) {
721 if (sipe_strcase_equal(sipe_xml_attribute(node, "name"),
722 "CertProvisioningServiceWebTicketProof_SHA1")) {
723 const gchar *auth_uri;
725 SIPE_DEBUG_INFO_NOFORMAT("certprov_metadata: authentication port found");
727 auth_uri = sipe_xml_attribute(sipe_xml_child(node,
728 "address"),
729 "location");
730 if (auth_uri) {
731 SIPE_DEBUG_INFO("certprov_metadata: CertProv Auth URI %s", auth_uri);
733 if (sipe_svc_metadata(sipe_private,
734 ticket_uri,
735 webticket_metadata,
736 ccd)) {
737 /* Remember for later */
738 ccd->certprov_uri = g_strdup(auth_uri);
740 /* callback data passed down the line */
741 ccd = NULL;
742 } else {
743 certificate_failure(sipe_private,
744 _("Can't request metadata from %s"),
745 ticket_uri);
748 break;
752 g_free(ticket_uri);
754 if (!node) {
755 certificate_failure(sipe_private,
756 _("Can't find the authentication port for TLS-DSK certificate provisioning URI %s"),
757 uri);
760 } else {
761 certificate_failure(sipe_private,
762 _("Can't find the WebTicket Policy for TLS-DSK certificate provisioning URI %s"),
763 uri);
766 } else if (uri) {
767 certificate_failure(sipe_private,
768 _("Can't retrieve metadata for TLS-DSK certificate provisioning URI %s"),
769 uri);
772 callback_data_free(ccd);
775 gboolean sipe_certificate_tls_dsk_generate(struct sipe_core_private *sipe_private,
776 const gchar *target,
777 const gchar *authuser,
778 const gchar *uri)
780 struct certificate_callback_data *ccd = g_new0(struct certificate_callback_data, 1);
781 gboolean ret;
783 ccd->target = g_strdup(target);
784 ccd->authuser = g_strdup(authuser);
786 ret = sipe_svc_metadata(sipe_private, uri, certprov_metadata, ccd);
787 if (!ret)
788 callback_data_free(ccd);
790 return(ret);
794 Local Variables:
795 mode: c
796 c-file-style: "bsd"
797 indent-tabs-mode: t
798 tab-width: 8
799 End: