2 * Copyright (C) 2011-2013 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "tnc_ifmap2_soap.h"
17 #include "tnc_ifmap2_soap_msg.h"
19 #include <utils/debug.h>
20 #include <credentials/sets/mem_cred.h>
23 #include <tls_socket.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
30 #define IFMAP_NS "http://www.trustedcomputinggroup.org/2010/IFMAP/2"
31 #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2"
32 #define IFMAP_URI "https://localhost:8444/imap"
33 #define IFMAP_NO_FD -1
35 typedef struct private_tnc_ifmap2_soap_t private_tnc_ifmap2_soap_t
;
38 * Private data of an tnc_ifmap2_soap_t object.
40 struct private_tnc_ifmap2_soap_t
{
43 * Public tnc_ifmap2_soap_t interface.
45 tnc_ifmap2_soap_t
public;
55 xmlChar
*ifmap_publisher_id
;
63 * IF-MAP metadata namespace
68 * PEP and PDP device name
73 * HTTPS Server URI with https:// prefix removed
78 * Optional base64-encoded username:password for HTTP Basic Authentication
83 * IF-MAP Server (IP address and port)
93 * File descriptor for secure TCP socket
98 * In memory credential set
104 METHOD(tnc_ifmap2_soap_t
, newSession
, bool,
105 private_tnc_ifmap2_soap_t
*this)
107 tnc_ifmap2_soap_msg_t
*soap_msg
;
108 xmlNodePtr request
, result
;
110 /*build newSession request */
111 request
= xmlNewNode(NULL
, "newSession");
112 this->ns
= xmlNewNs(request
, IFMAP_NS
, "ifmap");
113 xmlSetNs(request
, this->ns
);
115 soap_msg
= tnc_ifmap2_soap_msg_create(this->uri
, this->user_pass
, this->tls
);
116 if (!soap_msg
->post(soap_msg
, request
, "newSessionResult", &result
))
118 soap_msg
->destroy(soap_msg
);
122 /* get session-id and ifmap-publisher-id properties */
123 this->session_id
= xmlGetProp(result
, "session-id");
124 this->ifmap_publisher_id
= xmlGetProp(result
, "ifmap-publisher-id");
125 soap_msg
->destroy(soap_msg
);
127 DBG1(DBG_TNC
, "session-id: %s, ifmap-publisher-id: %s",
128 this->session_id
, this->ifmap_publisher_id
);
130 /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */
131 this->device_name
= lib
->settings
->get_str(lib
->settings
,
132 "%s.plugins.tnc-ifmap2.device_name",
133 this->ifmap_publisher_id
, charon
->name
);
134 this->device_name
= strdup(this->device_name
);
136 return this->session_id
&& this->ifmap_publisher_id
;
139 METHOD(tnc_ifmap2_soap_t
, purgePublisher
, bool,
140 private_tnc_ifmap2_soap_t
*this)
142 tnc_ifmap2_soap_msg_t
*soap_msg
;
146 /* build purgePublisher request */
147 request
= xmlNewNode(NULL
, "purgePublisher");
148 this->ns
= xmlNewNs(request
, IFMAP_NS
, "ifmap");
149 xmlSetNs(request
, this->ns
);
150 xmlNewProp(request
, "session-id", this->session_id
);
151 xmlNewProp(request
, "ifmap-publisher-id", this->ifmap_publisher_id
);
153 soap_msg
= tnc_ifmap2_soap_msg_create(this->uri
, this->user_pass
, this->tls
);
154 success
= soap_msg
->post(soap_msg
, request
, "purgePublisherReceived", NULL
);
155 soap_msg
->destroy(soap_msg
);
161 * Create an access-request based on device_name and ike_sa_id
163 static xmlNodePtr
create_access_request(private_tnc_ifmap2_soap_t
*this,
169 node
= xmlNewNode(NULL
, "access-request");
171 snprintf(buf
, BUF_LEN
, "%s:%d", this->device_name
, id
);
172 xmlNewProp(node
, "name", buf
);
180 static xmlNodePtr
create_identity(private_tnc_ifmap2_soap_t
*this,
181 identification_t
*id
, bool is_user
)
184 char buf
[BUF_LEN
], *id_type
;
186 node
= xmlNewNode(NULL
, "identity");
188 snprintf(buf
, BUF_LEN
, "%Y", id
);
189 xmlNewProp(node
, "name", buf
);
191 switch (id
->get_type(id
))
195 xmlNewProp(node
, "other-type-definition", "36906:ipv4-address");
198 id_type
= is_user ?
"username" : "dns-name";
201 id_type
= "email-address";
205 xmlNewProp(node
, "other-type-definition", "36906:ipv6-address");
208 id_type
= "distinguished-name";
212 xmlNewProp(node
, "other-type-definition", "36906:key-id");
216 xmlNewProp(node
, "other-type-definition", "36906:other");
218 xmlNewProp(node
, "type", id_type
);
224 * Create enforcement-report metadata
226 static xmlNodePtr
create_enforcement_report(private_tnc_ifmap2_soap_t
*this,
227 xmlChar
*action
, xmlChar
*reason
)
229 xmlNodePtr node
, node2
, node3
;
231 node
= xmlNewNode(NULL
, "metadata");
232 node2
= xmlNewNode(this->ns_meta
, "enforcement-report");
233 xmlAddChild(node
, node2
);
234 xmlNewProp(node2
, "ifmap-cardinality", "multiValue");
236 node3
= xmlNewNode(NULL
, "enforcement-action");
237 xmlAddChild(node2
, node3
);
238 xmlNodeAddContent(node3
, action
);
240 node3
= xmlNewNode(NULL
, "enforcement-reason");
241 xmlAddChild(node2
, node3
);
242 xmlNodeAddContent(node3
, reason
);
248 * Create delete filter
250 static xmlNodePtr
create_delete_filter(private_tnc_ifmap2_soap_t
*this,
256 node
= xmlNewNode(NULL
, "delete");
258 snprintf(buf
, BUF_LEN
, "meta:%s[@ifmap-publisher-id='%s']",
259 metadata
, this->ifmap_publisher_id
);
260 xmlNewProp(node
, "filter", buf
);
266 * Create a publish request
268 static xmlNodePtr
create_publish_request(private_tnc_ifmap2_soap_t
*this)
272 request
= xmlNewNode(NULL
, "publish");
273 this->ns
= xmlNewNs(request
, IFMAP_NS
, "ifmap");
274 xmlSetNs(request
, this->ns
);
275 this->ns_meta
= xmlNewNs(request
, IFMAP_META_NS
, "meta");
276 xmlNewProp(request
, "session-id", this->session_id
);
284 static xmlNodePtr
create_device(private_tnc_ifmap2_soap_t
*this)
286 xmlNodePtr node
, node2
;
288 node
= xmlNewNode(NULL
, "device");
289 node2
= xmlNewNode(NULL
, "name");
290 xmlAddChild(node
, node2
);
291 xmlNodeAddContent(node2
, this->device_name
);
297 * Create an ip-address
299 static xmlNodePtr
create_ip_address(private_tnc_ifmap2_soap_t
*this,
305 node
= xmlNewNode(NULL
, "ip-address");
307 if (host
->get_family(host
) == AF_INET6
)
314 /* output IPv6 address in canonical IF-MAP 2.0 format */
315 address
= host
->get_address(host
);
319 for (i
= 0; i
< address
.len
; i
= i
+ 2)
321 written
= snprintf(pos
, len
, "%s%x", first ?
"" : ":",
322 256*address
.ptr
[i
] + address
.ptr
[i
+1]);
323 if (written
< 0 || written
>= len
)
334 snprintf(buf
, BUF_LEN
, "%H", host
);
337 xmlNewProp(node
, "value", buf
);
338 xmlNewProp(node
, "type", host
->get_family(host
) == AF_INET ?
"IPv4" : "IPv6");
346 static xmlNodePtr
create_metadata(private_tnc_ifmap2_soap_t
*this,
349 xmlNodePtr node
, node2
;
351 node
= xmlNewNode(NULL
, "metadata");
352 node2
= xmlNewNode(this->ns_meta
, metadata
);
353 xmlAddChild(node
, node2
);
354 xmlNewProp(node2
, "ifmap-cardinality", "singleValue");
360 * Create capability metadata
362 static xmlNodePtr
create_capability(private_tnc_ifmap2_soap_t
*this,
363 identification_t
*name
)
365 xmlNodePtr node
, node2
;
368 node
= xmlNewNode(this->ns_meta
, "capability");
369 xmlNewProp(node
, "ifmap-cardinality", "multiValue");
371 node2
= xmlNewNode(NULL
, "name");
372 xmlAddChild(node
, node2
);
373 snprintf(buf
, BUF_LEN
, "%Y", name
);
374 xmlNodeAddContent(node2
, this->device_name
);
376 node2
= xmlNewNode(NULL
, "administrative-domain");
377 xmlNodeAddContent(node2
, "strongswan");
382 METHOD(tnc_ifmap2_soap_t
, publish_ike_sa
, bool,
383 private_tnc_ifmap2_soap_t
*this, ike_sa_t
*ike_sa
, bool up
)
385 tnc_ifmap2_soap_msg_t
*soap_msg
;
386 xmlNodePtr request
, node
, node2
= NULL
;
387 enumerator_t
*e1
, *e2
;
389 identification_t
*id
, *eap_id
, *group
;
393 bool is_user
= FALSE
, first
= TRUE
, success
;
395 /* extract relevant data from IKE_SA*/
396 ike_sa_id
= ike_sa
->get_unique_id(ike_sa
);
397 id
= ike_sa
->get_other_id(ike_sa
);
398 eap_id
= ike_sa
->get_other_eap_id(ike_sa
);
399 host
= ike_sa
->get_other_host(ike_sa
);
401 /* in the presence of an EAP Identity, treat it as a username */
402 if (!id
->equals(id
, eap_id
))
408 /* build publish request */
409 request
= create_publish_request(this);
411 /* delete any existing enforcement reports */
414 node
= create_delete_filter(this, "enforcement-report");
415 xmlAddChild(request
, node
);
416 xmlAddChild(node
, create_ip_address(this, host
));
417 xmlAddChild(node
, create_device(this));
421 * update or delete authenticated-as metadata
425 node
= xmlNewNode(NULL
, "update");
429 node
= create_delete_filter(this, "authenticated-as");
431 xmlAddChild(request
, node
);
433 /* add access-request, identity and [if up] metadata */
434 xmlAddChild(node
, create_access_request(this, ike_sa_id
));
435 xmlAddChild(node
, create_identity(this, id
, is_user
));
438 xmlAddChild(node
, create_metadata(this, "authenticated-as"));
442 * update or delete access-request-ip metadata
446 node
= xmlNewNode(NULL
, "update");
450 node
= create_delete_filter(this, "access-request-ip");
452 xmlAddChild(request
, node
);
454 /* add access-request, ip-address and [if up] metadata */
455 xmlAddChild(node
, create_access_request(this, ike_sa_id
));
456 xmlAddChild(node
, create_ip_address(this, host
));
459 xmlAddChild(node
, create_metadata(this, "access-request-ip"));
463 * update or delete authenticated-by metadata
467 node
= xmlNewNode(NULL
, "update");
471 node
= create_delete_filter(this, "authenticated-by");
473 xmlAddChild(request
, node
);
475 /* add access-request, device and [if up] metadata */
476 xmlAddChild(node
, create_access_request(this, ike_sa_id
));
477 xmlAddChild(node
, create_device(this));
480 xmlAddChild(node
, create_metadata(this, "authenticated-by"));
484 * update or delete capability metadata
486 e1
= ike_sa
->create_auth_cfg_enumerator(ike_sa
, FALSE
);
487 while (e1
->enumerate(e1
, &auth
) && (first
|| up
))
489 e2
= auth
->create_enumerator(auth
);
490 while (e2
->enumerate(e2
, &type
, &group
))
492 /* look for group memberships */
493 if (type
== AUTH_RULE_GROUP
)
501 node
= xmlNewNode(NULL
, "update");
505 node
= create_delete_filter(this, "capability");
507 xmlAddChild(request
, node
);
509 /* add access-request */
510 xmlAddChild(node
, create_access_request(this, ike_sa_id
));
515 node2
= xmlNewNode(NULL
, "metadata");
516 xmlAddChild(node
, node2
);
518 xmlAddChild(node2
, create_capability(this, group
));
525 soap_msg
= tnc_ifmap2_soap_msg_create(this->uri
, this->user_pass
, this->tls
);
526 success
= soap_msg
->post(soap_msg
, request
, "publishReceived", NULL
);
527 soap_msg
->destroy(soap_msg
);
532 METHOD(tnc_ifmap2_soap_t
, publish_device_ip
, bool,
533 private_tnc_ifmap2_soap_t
*this, host_t
*host
)
535 tnc_ifmap2_soap_msg_t
*soap_msg
;
536 xmlNodePtr request
, update
;
539 /* build publish update request */
540 request
= create_publish_request(this);
541 update
= xmlNewNode(NULL
, "update");
542 xmlAddChild(request
, update
);
544 /* add device, ip-address and metadata */
545 xmlAddChild(update
, create_device(this));
546 xmlAddChild(update
, create_ip_address(this, host
));
547 xmlAddChild(update
, create_metadata(this, "device-ip"));
549 soap_msg
= tnc_ifmap2_soap_msg_create(this->uri
, this->user_pass
, this->tls
);
550 success
= soap_msg
->post(soap_msg
, request
, "publishReceived", NULL
);
551 soap_msg
->destroy(soap_msg
);
556 METHOD(tnc_ifmap2_soap_t
, publish_enforcement_report
, bool,
557 private_tnc_ifmap2_soap_t
*this, host_t
*host
, char *action
, char *reason
)
559 tnc_ifmap2_soap_msg_t
*soap_msg
;
560 xmlNodePtr request
, update
;
563 /* build publish update request */
564 request
= create_publish_request(this);
565 update
= xmlNewNode(NULL
, "update");
566 xmlAddChild(request
, update
);
568 /* add ip-address and metadata */
569 xmlAddChild(update
, create_ip_address(this, host
));
570 xmlAddChild(update
, create_device(this));
571 xmlAddChild(update
, create_enforcement_report(this, action
, reason
));
573 soap_msg
= tnc_ifmap2_soap_msg_create(this->uri
, this->user_pass
, this->tls
);
574 success
= soap_msg
->post(soap_msg
, request
, "publishReceived", NULL
);
575 soap_msg
->destroy(soap_msg
);
580 METHOD(tnc_ifmap2_soap_t
, endSession
, bool,
581 private_tnc_ifmap2_soap_t
*this)
583 tnc_ifmap2_soap_msg_t
*soap_msg
;
587 /* build endSession request */
588 request
= xmlNewNode(NULL
, "endSession");
589 this->ns
= xmlNewNs(request
, IFMAP_NS
, "ifmap");
590 xmlSetNs(request
, this->ns
);
591 xmlNewProp(request
, "session-id", this->session_id
);
593 soap_msg
= tnc_ifmap2_soap_msg_create(this->uri
, this->user_pass
, this->tls
);
594 success
= soap_msg
->post(soap_msg
, request
, "endSessionResult", NULL
);
595 soap_msg
->destroy(soap_msg
);
600 METHOD(tnc_ifmap2_soap_t
, destroy
, void,
601 private_tnc_ifmap2_soap_t
*this)
603 if (this->session_id
)
606 xmlFree(this->session_id
);
607 xmlFree(this->ifmap_publisher_id
);
608 free(this->device_name
);
610 DESTROY_IF(this->tls
);
611 DESTROY_IF(this->host
);
613 if (this->fd
!= IFMAP_NO_FD
)
617 lib
->credmgr
->remove_set(lib
->credmgr
, &this->creds
->set
);
618 this->creds
->destroy(this->creds
);
619 free(this->user_pass
.ptr
);
623 static bool soap_init(private_tnc_ifmap2_soap_t
*this)
625 char *server_uri
, *server_str
, *port_str
, *uri_str
;
626 char *server_cert
, *client_cert
, *client_key
, *user_pass
;
630 identification_t
*server_id
, *client_id
= NULL
;
632 /* getting configuration parameters from strongswan.conf */
633 server_uri
= lib
->settings
->get_str(lib
->settings
,
634 "%s.plugins.tnc-ifmap2.server_uri", IFMAP_URI
, charon
->name
);
635 server_cert
= lib
->settings
->get_str(lib
->settings
,
636 "%s.plugins.tnc-ifmap2.server_cert", NULL
, charon
->name
);
637 client_cert
= lib
->settings
->get_str(lib
->settings
,
638 "%s.plugins.tnc-ifmap2.client_cert", NULL
, charon
->name
);
639 client_key
= lib
->settings
->get_str(lib
->settings
,
640 "%s.plugins.tnc-ifmap2.client_key", NULL
, charon
->name
);
641 user_pass
= lib
->settings
->get_str(lib
->settings
,
642 "%s.plugins.tnc-ifmap2.username_password", NULL
, charon
->name
);
644 /* load [self-signed] MAP server certificate */
647 DBG1(DBG_TNC
, "MAP server certificate not defined");
650 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
651 BUILD_FROM_FILE
, server_cert
, BUILD_END
);
654 DBG1(DBG_TNC
, "loading MAP server certificate from '%s' failed",
658 DBG1(DBG_TNC
, "loaded MAP server certificate from '%s'", server_cert
);
659 server_id
= cert
->get_subject(cert
);
660 this->creds
->add_cert(this->creds
, TRUE
, cert
);
662 /* check availability of client credentials */
663 if (!((client_cert
&& client_key
) || user_pass
))
665 DBG1(DBG_TNC
, "neither MAP client certificate and private key "
666 "nor username:password defined");
672 /* load MAP client certificate */
673 cert
= lib
->creds
->create(lib
->creds
, CRED_CERTIFICATE
, CERT_X509
,
674 BUILD_FROM_FILE
, client_cert
, BUILD_END
);
677 DBG1(DBG_TNC
, "loading MAP client certificate from '%s' failed",
681 DBG1(DBG_TNC
, "loaded MAP client certificate from '%s'", client_cert
);
682 this->creds
->add_cert(this->creds
, TRUE
, cert
);
684 /* load MAP client private key */
685 key
= lib
->creds
->create(lib
->creds
, CRED_PRIVATE_KEY
, KEY_RSA
,
686 BUILD_FROM_FILE
, client_key
, BUILD_END
);
689 DBG1(DBG_TNC
, "loading MAP client private key from '%s' failed",
693 DBG1(DBG_TNC
, "loaded MAP client RSA private key from '%s'", client_key
);
694 this->creds
->add_key(this->creds
, key
);
696 /* set client ID to certificate distinguished name */
697 client_id
= cert
->get_subject(cert
);
701 /* set base64-encoded username:password for HTTP Basic Authentication */
702 this->user_pass
= chunk_to_base64(chunk_from_str(user_pass
), NULL
);
705 /* remove HTTPS prefix if any */
706 if (strlen(server_uri
) >= 8 && strncaseeq(server_uri
, "https://", 8))
710 this->uri
= server_uri
;
712 /* duplicate server string since we are going to manipulate it */
713 server_str
= strdup(server_uri
);
715 /* extract server name and port from server URI */
716 port_str
= strchr(server_str
, ':');
720 if (sscanf(port_str
, "%d", &port
) != 1)
722 DBG1(DBG_TNC
, "parsing server port %s failed", port_str
);
729 /* use default https port */
731 uri_str
= strchr(server_str
, '/');
738 /* open TCP socket and connect to MAP server */
739 this->host
= host_create_from_dns(server_str
, 0, port
);
742 DBG1(DBG_TNC
, "resolving hostname %s failed", server_str
);
748 this->fd
= socket(this->host
->get_family(this->host
), SOCK_STREAM
, 0);
749 if (this->fd
== IFMAP_NO_FD
)
751 DBG1(DBG_TNC
, "opening socket failed: %s", strerror(errno
));
755 if (connect(this->fd
, this->host
->get_sockaddr(this->host
),
756 *this->host
->get_sockaddr_len(this->host
)) == -1)
758 DBG1(DBG_TNC
, "connecting to %#H failed: %s",
759 this->host
, strerror(errno
));
763 /* open TLS socket */
764 this->tls
= tls_socket_create(FALSE
, server_id
, client_id
, this->fd
, NULL
);
767 DBG1(DBG_TNC
, "creating TLS socket failed");
777 tnc_ifmap2_soap_t
*tnc_ifmap2_soap_create()
779 private_tnc_ifmap2_soap_t
*this;
783 .newSession
= _newSession
,
784 .purgePublisher
= _purgePublisher
,
785 .publish_ike_sa
= _publish_ike_sa
,
786 .publish_device_ip
= _publish_device_ip
,
787 .publish_enforcement_report
= _publish_enforcement_report
,
788 .endSession
= _endSession
,
792 .creds
= mem_cred_create(),
795 lib
->credmgr
->add_set(lib
->credmgr
, &this->creds
->set
);
797 if (!soap_init(this))
803 return &this->public;