diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2013-03-29 22:29:12 +0100 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2013-03-29 22:29:12 +0100 |
commit | b885c3cde6bc05862ce052eb8349ebc5c82424dd (patch) | |
tree | 834a199d05bde44c21cff5f100a12bfe7574fbcb | |
parent | e99aab35dec8d6a414e4018f7f2d8b051d505954 (diff) | |
download | strongswan-b885c3cde6bc05862ce052eb8349ebc5c82424dd.tar.bz2 strongswan-b885c3cde6bc05862ce052eb8349ebc5c82424dd.tar.xz |
implement NewSession and PurgePublisher messages using the libxml2 library
-rw-r--r-- | configure.in | 6 | ||||
-rw-r--r-- | src/libcharon/plugins/tnc_ifmap2/Makefile.am | 6 | ||||
-rw-r--r-- | src/libcharon/plugins/tnc_ifmap2/gaga.txt | 32 | ||||
-rw-r--r-- | src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c | 306 |
4 files changed, 268 insertions, 82 deletions
diff --git a/configure.in b/configure.in index 659d4e9ba..5ad0f7e75 100644 --- a/configure.in +++ b/configure.in @@ -169,11 +169,11 @@ ARG_ENABL_SET([xauth-eap], [enable XAuth backend using EAP methods to verif ARG_ENABL_SET([xauth-pam], [enable XAuth backend using PAM to verify passwords.]) ARG_ENABL_SET([xauth-noauth], [enable XAuth pseudo-backend that does not actually verify or even request any credentials.]) ARG_ENABL_SET([tnc-ifmap], [enable TNC IF-MAP module.]) -ARG_ENABL_SET([tnc-ifmap2], [enable TNC IF-MAP v2 module.]) +ARG_ENABL_SET([tnc-ifmap2], [enable TNC IF-MAP v2 module. Requires libxml]) ARG_ENABL_SET([tnc-pdp], [enable TNC policy decision point module.]) ARG_ENABL_SET([tnc-imc], [enable TNC IMC module.]) ARG_ENABL_SET([tnc-imv], [enable TNC IMV module.]) -ARG_ENABL_SET([tnccs-11], [enable TNCCS 1.1 protocol module.]) +ARG_ENABL_SET([tnccs-11], [enable TNCCS 1.1 protocol module. Requires libxml]) ARG_ENABL_SET([tnccs-20], [enable TNCCS 2.0 protocol module.]) ARG_ENABL_SET([tnccs-dynamic], [enable dynamic TNCCS protocol discovery module.]) ARG_ENABL_SET([imc-test], [enable IMC test module.]) @@ -339,7 +339,7 @@ if test x$fips_prf = xtrue; then fi fi -if test x$smp = xtrue -o x$tnccs_11 = xtrue; then +if test x$smp = xtrue -o x$tnccs_11 = xtrue -o x$tnc_ifmap2 = xtrue; then xml=true fi diff --git a/src/libcharon/plugins/tnc_ifmap2/Makefile.am b/src/libcharon/plugins/tnc_ifmap2/Makefile.am index 20bb3ca0e..11524795c 100644 --- a/src/libcharon/plugins/tnc_ifmap2/Makefile.am +++ b/src/libcharon/plugins/tnc_ifmap2/Makefile.am @@ -3,7 +3,8 @@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libtls \ -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libcharon + -I$(top_srcdir)/src/libcharon \ + ${xml_CFLAGS} AM_CFLAGS = -rdynamic @@ -13,7 +14,8 @@ else plugin_LTLIBRARIES = libstrongswan-tnc-ifmap2.la endif -libstrongswan_tnc_ifmap2_la_LIBADD = $(top_builddir)/src/libtls/libtls.la +libstrongswan_tnc_ifmap2_la_LIBADD = \ + $(top_builddir)/src/libtls/libtls.la ${xml_LIBS} libstrongswan_tnc_ifmap2_la_SOURCES = \ tnc_ifmap2_plugin.h tnc_ifmap2_plugin.c \ diff --git a/src/libcharon/plugins/tnc_ifmap2/gaga.txt b/src/libcharon/plugins/tnc_ifmap2/gaga.txt deleted file mode 100644 index c93a50ac8..000000000 --- a/src/libcharon/plugins/tnc_ifmap2/gaga.txt +++ /dev/null @@ -1,32 +0,0 @@ -POST /ifmap HTTP/1.1 -Content-Type: application/soap+xml; charset=utf-8 -Content-Length: 236 - -<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"> - <soapenv:Body> - <ifmap:newSession xmlns:ifmap="http://www.trustedcomputinggroup.org/2010/IFMAP/2"></ifmap:newSession> - </soapenv:Body> -</soapenv:Envelope> - -2013-03-27 20:29:56,704 [pool-5-thread-2] DEBUG - ChannelAcceptor: New connection from 127.0.0.1:44019 on port 8444 -2013-03-27 20:29:56,887 [pool-6-thread-1] DEBUG - ChannelThread: Client koala.strongsec.com authenticated successfully on channel 127.0.0.1:44019:0 -2013-03-27 20:29:56,891 [pool-1-thread-1] TRACE - EventProcessor: RequestChannelEvent on channel 127.0.0.1:44019:0 -2013-03-27 20:29:57,057 [pool-1-thread-1] DEBUG - EventProcessor: newSession for koala.strongsec.com on 127.0.0.1:44019:0 -2013-03-27 20:29:57,058 [pool-1-thread-1] TRACE - ClientService: newSession for koala.strongsec.com--515754026-1 and maxPollResultSize=5000000 bytes -2013-03-27 20:29:57,058 [pool-1-thread-1] TRACE - Adding new Publisher: sessionid=1890214968-1490695359-237418166-218822252 publisherid=koala.strongsec.com--515754026-1 -2013-03-27 20:29:57,058 [pool-1-thread-1] TRACE - Creating new Publisher... -2013-03-27 20:29:57,064 [pool-3-thread-1] TRACE - ActionProcessor: Forward response to channel 127.0.0.1:44019:0 -2013-03-27 20:29:57,065 [pool-3-thread-1] DEBUG - ChannelThread: Sending reply to koala.strongsec.com -2013-03-27 20:29:57,066 [pool-3-thread-1] TRACE - ChannelThread: Length of reply on wire=376 -2013-03-27 20:29:57,091 [pool-5-thread-2] DEBUG - ChannelAcceptor: New connection from 127.0.0.1:44020 on port 8444 -2013-03-27 20:29:57,103 [pool-6-thread-1] DEBUG - ChannelThread: 127.0.0.1:44019:0 closed -2013-03-27 20:29:57,104 [pool-1-thread-2] DEBUG - EventProcessor: Got ClosedChannelEvent for 127.0.0.1:44019:0 -2013-03-27 20:29:57,104 [pool-1-thread-2] DEBUG - EventProcessor: Creating Timer for koala.strongsec.com - -2013-03-27 20:29:57,120 [pool-6-thread-2] DEBUG - ChannelThread: Client koala.strongsec.com authenticated successfully on channel 127.0.0.1:44020:1 -2013-03-27 20:29:57,122 [pool-1-thread-3] TRACE - EventProcessor: RequestChannelEvent on channel 127.0.0.1:44020:1 -2013-03-27 20:29:57,129 [pool-1-thread-3] DEBUG - EventProcessor: purgePublisher for koala.strongsec.com on 127.0.0.1:44020:1 -2013-03-27 20:29:57,129 [pool-1-thread-3] TRACE - EventProcessor: koala.strongsec.com uses 127.0.0.1:44020:1 as new SSRC -2013-03-27 20:29:57,130 [pool-1-thread-3] TRACE - EventProcessor: Cancel timer for koala.strongsec.com -2013-03-27 20:29:57,130 [pool-1-thread-3] DEBUG - ClientService: publisher{koala.strongsec.com--515754026-1} is purging 0 metadata objects of publisher{koala.strongsec.com--515754026-1} - diff --git a/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c index 994b36c0c..65f92653b 100644 --- a/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c +++ b/src/libcharon/plugins/tnc_ifmap2/tnc_ifmap2_soap.c @@ -13,25 +13,33 @@ * for more details. */ +#define _GNU_SOURCE /* for asprintf() */ + #include "tnc_ifmap2_soap.h" #include <utils/debug.h> +#include <utils/lexparser.h> #include <credentials/sets/mem_cred.h> #include <daemon.h> #include <tls_socket.h> +#include <libxml/parser.h> + +#define _GNU_SOURCE + +#include <stdio.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> -#define IFMAP_NO_FD -1 -#define IFMAP_SERVER_ID "C=DE, ST=Niedersachsen, L=Hannover, O=Hochschule Hannover, OU=Trust@FHH, CN=irond.trust.inform.fh-hannover.de" +#define SOAP_NS "http://www.w3.org/2003/05/soap-envelope" #define IFMAP_NS "http://www.trustedcomputinggroup.org/2010/IFMAP/2" #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2" #define IFMAP_LOGFILE "strongswan_ifmap.log" #define IFMAP_SERVER "https://localhost:8443/" +#define IFMAP_NO_FD -1 typedef struct private_tnc_ifmap2_soap_t private_tnc_ifmap2_soap_t; @@ -83,52 +91,235 @@ struct private_tnc_ifmap2_soap_t { }; /** - * Send request and receive result via SOAP + * Send HTTP POST request and receive HTTP response */ -static bool send_receive(private_tnc_ifmap2_soap_t *this, - char *request_qname, chunk_t request, - char *receipt_qname, chunk_t *result) - +static bool http_send_receive(private_tnc_ifmap2_soap_t *this, chunk_t out, + chunk_t *in) { - int written, len; - char *pos; - - char soap[] = - "<?xml version=\"1.0\"?>" - "<env:Envelope xmlns:env=\"http://www.w3.org/2003/05/soap-envelope\">" - " <env:Body>" - " <ifmap:newSession xmlns:ifmap=\"http://www.trustedcomputinggroup.org/2010/IFMAP/2\"></ifmap:newSession>" - " </env:Body>" - "</env:Envelope>"; - - char http_header[] = + char header[] = "POST /ifmap HTTP/1.1\r\n" - "Content-Type: application/soap+xml; charset=utf-8\r\n" + "Content-Type: application/soap+xml;charset=utf-8\r\n" "Content-Length: "; + char *request, response[2048]; + chunk_t line, http, parameter; + int len, code, content_len = 0; + + /* Write HTTP POST request */ + len = asprintf(&request, "%s%d\r\n\r\n%.*s", header, out.len, + out.len, out.ptr); + if (len == -1) + { + return FALSE; + } + this->tls->write(this->tls, request, len); + free(request); + + /* Read HTTP response */ + len = this->tls->read(this->tls, response, sizeof(response), TRUE); + if (len == -1) + { + return FALSE; + } + *in = chunk_create(response, len); + + /* Process HTTP protocol version */ + if (!fetchline(in, &line) || !extract_token(&http, ' ', &line) || + !match("HTTP/1.1", &http) || sscanf(line.ptr, "%d", &code) != 1) + { + DBG1(DBG_TNC, "malformed http response header"); + return FALSE; + } + if (code != 200) + { + DBG1(DBG_TNC, "http response returns error code %d", code); + return FALSE; + } + + /* Process HTTP header line by line until the HTTP body is reached */ + while (fetchline(in, &line)) + { + if (line.len == 0) + { + break; + } + + if (extract_token(¶meter, ':', &line) && + match("Content-Length", ¶meter) && + sscanf(line.ptr, "%d", &len) == 1) + { + content_len = len; + } + } + + /* Found Content-Length parameter and check size of HTTP body */ + if (content_len) + { + if (content_len > in->len) + { + DBG1(DBG_TNC, "http body is smaller than content length"); + return FALSE; + } + in->len = content_len; + } + *in = chunk_clone(*in); - char buf[2048]; - - pos = buf; - len = sizeof(buf); - written = snprintf(pos, len, "%s", http_header); - pos += written; - len -= written; - written = snprintf(pos, len, "%d\r\n\r\n%s", strlen(soap), soap); - - this->tls->write(this->tls, buf, strlen(buf)); - len = this->tls->read(this->tls, buf, sizeof(buf), TRUE); - *result = chunk_create(buf, len); - DBG2(DBG_TNC, "%B", result); - + return TRUE; +} + +/** + * Find a child node with a given name + */ +static xmlNodePtr find_child(xmlNodePtr parent, const xmlChar* name) +{ + xmlNodePtr child; + + child = parent->xmlChildrenNode; + while (child) + { + if (xmlStrcmp(child->name, name) == 0) + { + return child; + } + child = child->next; + } + + DBG1(DBG_TNC, "child node \"%s\" not found", name); + return NULL; +} + +/** + * Send request and receive result via SOAP + */ +static bool soap_send_receive(private_tnc_ifmap2_soap_t *this, + char *request_name, xmlNodePtr request, + char *result_name, xmlNodePtr *result, + xmlDocPtr *result_doc) +{ + xmlDocPtr doc; + xmlNodePtr env, body, cur; + xmlNsPtr ns; + xmlChar *xml; + int len; + chunk_t in, out; + + *result_doc = NULL; + DBG2(DBG_TNC, "sending ifmap %s", request_name); + + /* Generate XML Document containing SOAP Envelope */ + doc = xmlNewDoc("1.0"); + env =xmlNewNode(NULL, "Envelope"); + ns = xmlNewNs(env, SOAP_NS, "env"); + xmlSetNs(env, ns); + xmlDocSetRootElement(doc, env); + + /* Add SOAP Body containing IF-MAP request */ + body = xmlNewNode(ns, "Body"); + xmlAddChild(body, request); + xmlAddChild(env, body); + + /* Convert XML Document into a character string */ + xmlDocDumpFormatMemory(doc, &xml, &len, 1); + xmlFreeDoc(doc); + DBG3(DBG_TNC, "%.*s", len, xml); + out = chunk_create(xml, len); + + /* Send SOAP-XML request via HTTP */ + if (!http_send_receive(this, out, &in)) + { + xmlFree(xml); + return FALSE; + } + xmlFree(xml); + + DBG3(DBG_TNC, "%B", &in); + doc = xmlParseMemory(in.ptr, in.len); + free(in.ptr); + + if (!doc) + { + DBG1(DBG_TNC, "failed to parse XML message"); + return FALSE; + } + *result_doc = doc; + + /* check out XML document */ + cur = xmlDocGetRootElement(doc); + if (!cur) + { + DBG1(DBG_TNC, "empty XML message"); + return FALSE; + } + + /* get XML Document type is a SOAP Envelope */ + if (xmlStrcmp(cur->name, "Envelope")) + { + DBG1(DBG_TNC, "XML message does not contain a SOAP Envelope"); + return FALSE; + } + + /* get SOAP Body */ + cur = find_child(cur, "Body"); + if (!cur) + { + return FALSE; + } + + /* get IF-MAP response */ + cur = find_child(cur, "response"); + if (!cur) + { + return FALSE; + } + + /* get IF-MAP result */ + cur = find_child(cur, result_name); + if (!cur) + { + return FALSE; + } + + if (result) + { + *result = cur; + } return TRUE; } METHOD(tnc_ifmap2_soap_t, newSession, bool, private_tnc_ifmap2_soap_t *this) { - chunk_t request, result; + xmlNodePtr request, result; + xmlDocPtr result_doc; + xmlNsPtr ns; + + /*build newSession request */ + request = xmlNewNode(NULL, "newSession"); + ns = xmlNewNs(request, IFMAP_NS, "ifmap"); + xmlSetNs(request, ns); - send_receive(this, "newSession", request, "newSessionResult", &result); + if (!soap_send_receive(this, "newSession", request, "newSessionResult", + &result, &result_doc)) + { + if (result_doc) + { + xmlFreeDoc(result_doc); + } + return FALSE; + } + + /* get session-id and ifmap-publisher-id properties */ + this->session_id = xmlGetProp(result, "session-id"); + this->ifmap_publisher_id = xmlGetProp(result, "ifmap-publisher-id"); + xmlFreeDoc(result_doc); + + DBG1(DBG_TNC, "session-id: %s, ifmap-publisher-id: %s", + this->session_id, this->ifmap_publisher_id); + + /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */ + this->device_name = lib->settings->get_str(lib->settings, + "%s.plugins.tnc-ifmap2.device_name", + this->ifmap_publisher_id, charon->name); + this->device_name = strdup(this->device_name); return this->session_id && this->ifmap_publisher_id; } @@ -136,10 +327,25 @@ METHOD(tnc_ifmap2_soap_t, newSession, bool, METHOD(tnc_ifmap2_soap_t, purgePublisher, bool, private_tnc_ifmap2_soap_t *this) { - /* send purgePublisher request and receive purgePublisherReceived */ - /* return send_receive(this, "purgePublisher", request, - "purgePublisherReceived", NULL); */ - return FALSE; + xmlNodePtr request; + xmlDocPtr result_doc; + xmlNsPtr ns; + bool success; + + /* build purgePublisher request */ + request = xmlNewNode(NULL, "purgePublisher"); + ns = xmlNewNs(request, IFMAP_NS, "ifmap"); + xmlSetNs(request, ns); + xmlNewProp(request, "session-id", this->session_id); + xmlNewProp(request, "ifmap-publisher-id", this->ifmap_publisher_id); + + success = soap_send_receive(this, "purgePublisher", request, + "purgePublisherReceived", NULL, &result_doc); + if (result_doc) + { + xmlFreeDoc(result_doc); + } + return success; } METHOD(tnc_ifmap2_soap_t, publish_ike_sa, bool, @@ -203,7 +409,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this) private_key_t *key; identification_t *server_id, *client_id; - /** Load [self-signed] MAP server certificate */ + /** + * Load [self-signed] MAP server certificate + */ server_cert = lib->settings->get_str(lib->settings, "%s.plugins.tnc-ifmap2.server_cert", NULL, charon->name); if (!server_cert) @@ -223,7 +431,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this) server_id = cert->get_subject(cert); this->creds->add_cert(this->creds, TRUE, cert); - /* Load MAP client certificate */ + /** + * Load MAP client certificate + */ client_cert = lib->settings->get_str(lib->settings, "%s.plugins.tnc-ifmap2.client_cert", NULL, charon->name); if (!client_cert) @@ -243,7 +453,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this) client_id = cert->get_subject(cert); this->creds->add_cert(this->creds, TRUE, cert); - /* Load MAP client private key */ + /** + * Load MAP client private key + */ client_key = lib->settings->get_str(lib->settings, "%s.plugins.tnc-ifmap2.client_key", NULL, charon->name); if (!client_key) @@ -262,7 +474,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this) DBG1(DBG_TNC, "loaded MAP client RSA private key from '%s'", client_key); this->creds->add_key(this->creds, key); - /* Open TCP socket and connect to MAP server */ + /** + * Open TCP socket and connect to MAP server + */ server = "127.0.0.1"; this->host = host_create_from_dns(server, 0, 8444); if (!this->host) @@ -286,7 +500,9 @@ static bool soap_init(private_tnc_ifmap2_soap_t *this) return FALSE; } - /* Open TLS socket */ + /** + * Open TLS socket + */ this->tls = tls_socket_create(FALSE, server_id, client_id, this->fd, NULL); if (!this->tls) { |