]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
rapid PT-TLS AR/PDP prototype
authorAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 7 Aug 2013 17:41:29 +0000 (19:41 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 15 Aug 2013 21:34:22 +0000 (23:34 +0200)
14 files changed:
configure.ac
src/Makefile.am
src/libcharon/plugins/tnc_imc/tnc_imc.c
src/libcharon/plugins/tnc_imc/tnc_imc_manager.c
src/libcharon/plugins/tnc_pdp/tnc_pdp.c
src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c
src/libcharon/plugins/tnccs_20/tnccs_20.c
src/libpttls/pt_tls.h
src/libpttls/pt_tls_client.c
src/libpttls/pt_tls_dispatcher.c
src/libpttls/pt_tls_server.c
src/pt-tls-client/Makefile.am [new file with mode: 0644]
src/pt-tls-client/pt-tls-client [new file with mode: 0755]
src/pt-tls-client/pt-tls-client.c [new file with mode: 0644]

index a2be84495f9b44d27a33f467c41426cd957d1354..7b23a9cb513da900e82e58fd28b1f489f51eecd7 100644 (file)
@@ -1467,6 +1467,7 @@ AC_CONFIG_FILES([
        src/medsrv/Makefile
        src/checksum/Makefile
        src/conftest/Makefile
+       src/pt-tls-client/Makefile
        scripts/Makefile
        testing/Makefile
 ])
index 47299b03c3c2f1e32f79e0098a76aa6cb0d6e3f5..1a025ad244d7a77be1219e8a5ef81920e91aaa1f 100644 (file)
@@ -33,7 +33,7 @@ if USE_LIBTNCCS
 endif
 
 if USE_LIBPTTLS
-  SUBDIRS += libpttls
+  SUBDIRS += libpttls pt-tls-client
 endif
 
 if USE_IMCV
index 9ac578401a10099c15a9b8a6126cb4d7ea9d62d6..122554abe76c810a0eca008ac84f51c94eb83796 100644 (file)
@@ -21,7 +21,6 @@
 #include <tncif_pa_subtypes.h>
 
 #include <utils/debug.h>
-#include <daemon.h>
 #include <library.h>
 #include <collections/linked_list.h>
 #include <threading/mutex.h>
@@ -304,7 +303,7 @@ METHOD(imc_t, destroy, void,
        private_tnc_imc_t *this)
 {
        if (this->handle && lib->settings->get_bool(lib->settings,
-               "%s.plugins.tnc-imc.dlclose", TRUE, charon->name))
+               "%s.plugins.tnc-imc.dlclose", TRUE, "charon"))
        {
                dlclose(this->handle);
        }
index 078f7bc344f7503500fb2e151621ad41cbac6c2b..b34a6ffd8f75c3d114b07a05f99c19a263de1e59 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <tncifimc.h>
 
-#include <daemon.h>
 #include <utils/debug.h>
 #include <threading/rwlock.h>
 #include <threading/mutex.h>
@@ -225,7 +224,7 @@ METHOD(imc_manager_t, get_preferred_language, char*,
        private_tnc_imc_manager_t *this)
 {
        return lib->settings->get_str(lib->settings,
-                               "%s.plugins.tnc-imc.preferred_language", "en", charon->name);
+                               "%s.plugins.tnc-imc.preferred_language", "en", "charon");
 }
 
 METHOD(imc_manager_t, notify_connection_change, void,
index 7ef67fd1826a129615311d8dceb3fa0c99a7883f..686df15c7e3c9624547962df28fd83c6ef1d0064 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Andreas Steffen
+ * Copyright (C) 2012-2013 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -22,7 +22,9 @@
 #include <radius_message.h>
 #include <radius_mppe.h>
 
-#include <pt_tls_dispatcher.h>
+#include <pt_tls_server.h>
+
+#include <tnc/tnc.h>
 
 #include <daemon.h>
 #include <utils/debug.h>
@@ -38,11 +40,6 @@ typedef struct private_tnc_pdp_t private_tnc_pdp_t;
  */
 #define RADIUS_PORT 1812
 
-/**
- * Default PT-TLS port, when not configured
- */
-#define PT_TLS_PORT     271
-
 /**
  * Maximum size of a RADIUS IP packet
  */
@@ -69,14 +66,24 @@ struct private_tnc_pdp_t {
        eap_type_t type;
 
        /**
-        * IPv4 RADIUS socket
+        * PT-TLS IPv4 socket
+        */
+       int pt_tls_ipv4;
+
+       /**
+        * PT-TLS IPv6 socket
+        */
+       int pt_tls_ipv6;
+
+       /**
+        * RADIUS IPv4 socket
         */
-       int ipv4;
+       int radius_ipv4;
 
        /**
-        * IPv6 RADIUS socket
+        * RADIUS IPv6 socket
         */
-       int ipv6;
+       int radius_ipv6;
 
        /**
         * RADIUS shared secret
@@ -103,18 +110,12 @@ struct private_tnc_pdp_t {
         */
        tnc_pdp_connections_t *connections;
 
-       /**
-        * PT-TLS dispatcher
-        */
-       pt_tls_dispatcher_t *pt_tls_dispatcher;
-
 };
 
-
 /**
- * Open IPv4 or IPv6 UDP RADIUS socket
+ * Open IPv4 or IPv6 UDP socket
  */
-static int open_socket(int family, u_int16_t port)
+static int open_udp_socket(int family, u_int16_t port)
 {
        int on = TRUE;
        struct sockaddr_storage addr;
@@ -153,20 +154,115 @@ static int open_socket(int family, u_int16_t port)
        skt = socket(family, SOCK_DGRAM, IPPROTO_UDP);
        if (skt < 0)
        {
-               DBG1(DBG_CFG, "opening RADIUS socket failed: %s", strerror(errno));
+               DBG1(DBG_CFG, "opening UDP socket failed: %s", strerror(errno));
+               return 0;
+       }
+       if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
+       {
+               DBG1(DBG_CFG, "unable to set SO_REUSEADDR on socket: %s",
+                                          strerror(errno));
+               close(skt);
+               return 0;
+       }
+       if (family == AF_INET6)
+       {
+               if (setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY,
+                                                       (void *)&on, sizeof(on)) < 0)
+               {
+                       DBG1(DBG_CFG, "unable to set IPV6_V6ONLY on socket: %s",
+                                                  strerror(errno));
+                       close(skt);
+                       return 0;
+               }
+       }
+
+       /* bind the socket */
+       if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0)
+       {
+               DBG1(DBG_CFG, "unable to bind UDP socket: %s", strerror(errno));
+               close(skt);
+               return 0;
+       }
+
+       return skt;
+}
+
+/**
+ * Open IPv4 or IPv6 TCP socket
+ */
+static int open_tcp_socket(int family, u_int16_t port)
+{
+       int on = TRUE;
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       int skt;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.ss_family = family;
+
+       /* precalculate constants depending on address family */
+       switch (family)
+       {
+               case AF_INET:
+               {
+                       struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+
+                       htoun32(&sin->sin_addr.s_addr, INADDR_ANY);
+                       htoun16(&sin->sin_port, port);
+                       addrlen = sizeof(struct sockaddr_in);
+                       break;
+               }
+               case AF_INET6:
+               {
+                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+
+                       memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any));
+                       htoun16(&sin6->sin6_port, port);
+                       addrlen = sizeof(struct sockaddr_in6);
+                       break;
+               }
+               default:
+                       return 0;
+       }
+
+       /* open the socket */
+       skt = socket(family, SOCK_STREAM, IPPROTO_TCP);
+       if (skt < 0)
+       {
+               DBG1(DBG_CFG, "opening TCP socket failed: %s", strerror(errno));
                return 0;
        }
        if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0)
        {
-               DBG1(DBG_CFG, "unable to set SO_REUSEADDR on socket: %s", strerror(errno));
+               DBG1(DBG_CFG, "unable to set SO_REUSEADDR on socket: %s",
+                                          strerror(errno));
                close(skt);
                return 0;
        }
+       if (family == AF_INET6)
+       {
+       if (setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY,
+                                                       (void *)&on, sizeof(on)) < 0)
+               {
+                       DBG1(DBG_CFG, "unable to set IPV6_V6ONLY on socket: %s",
+                                                  strerror(errno));
+                       close(skt);
+                       return 0;
+               }
+       }
 
        /* bind the socket */
        if (bind(skt, (struct sockaddr *)&addr, addrlen) < 0)
        {
-               DBG1(DBG_CFG, "unable to bind RADIUS socket: %s", strerror(errno));
+               DBG1(DBG_CFG, "unable to bind TCP socket: %s", strerror(errno));
+               close(skt);
+               return 0;
+       }
+
+       /* start listening on socket */
+       if (listen(skt, 5) == -1)
+       {
+               DBG1(DBG_TNC, "listen on TCP socket failed: %s", strerror(errno));
                close(skt);
                return 0;
        }
@@ -183,7 +279,8 @@ static void send_message(private_tnc_pdp_t *this, radius_message_t *message,
        int fd;
        chunk_t data;
 
-       fd = (client->get_family(client) == AF_INET) ? this->ipv4 : this->ipv6;
+       fd = (client->get_family(client) == AF_INET) ?
+                       this->radius_ipv4 : this->radius_ipv6;
        data = message->get_encoding(message);
 
        DBG2(DBG_CFG, "sending RADIUS packet to %#H", client);
@@ -465,10 +562,80 @@ end:
        }
 }
 
+/**
+ * Get more data on a PT-TLS connection
+ */
+static bool pt_tls_receive_more(pt_tls_server_t *this, int fd,
+                                                               watcher_event_t event)
+{
+       switch (this->handle(this))
+       {
+               case NEED_MORE:
+                       DBG1(DBG_TNC, "PT-TLS connection needs more");
+                       break;
+               case FAILED:
+               case SUCCESS:
+               default:
+                       DBG1(DBG_TNC, "PT-TLS connection terminates");
+                       lib->watcher->remove(lib->watcher, fd);
+                       close(fd);
+                       this->destroy(this);
+                       break;
+       }
+
+       return TRUE;
+}
+
+/**
+ * Accept TCP connection received on the PT-TLS listening socket
+ */
+static bool pt_tls_receive(private_tnc_pdp_t *this, int fd, watcher_event_t event)
+{
+       int pt_tls_fd;
+       identification_t *peer;
+       pt_tls_server_t *pt_tls;
+       tnccs_t *tnccs;
+
+       pt_tls_fd = accept(fd, NULL, NULL);
+       if (pt_tls_fd == -1)
+       {
+               DBG1(DBG_TNC, "accepting PT-TLS stream failed: %s", strerror(errno));
+               return FALSE;
+       }
+
+       /* At this moment the peer identity is not known yet */
+       peer = identification_create_from_encoding(ID_ANY, chunk_empty),
+
+       tnccs = tnc->tnccs->create_instance(tnc->tnccs, TNCCS_2_0, TRUE,
+                                                                               this->server, peer, TNC_IFT_TLS_2_0);
+       peer->destroy(peer);
+
+       if (!tnccs)
+       {
+               DBG1(DBG_TNC, "could not create TNCCS 2.0 connection instance");
+               close(pt_tls_fd);
+               return FALSE;
+       }
+
+       pt_tls = pt_tls_server_create(this->server, pt_tls_fd, PT_TLS_AUTH_NONE,
+                                                                 tnccs);
+       if (!pt_tls)
+       {
+               DBG1(DBG_TNC, "could not create PT-TLS connection instance");
+               close(pt_tls_fd);
+               return FALSE;
+       }
+
+       lib->watcher->add(lib->watcher, pt_tls_fd, WATCHER_READ,
+                                                        (watcher_cb_t)pt_tls_receive_more, pt_tls);
+
+       return TRUE;
+}
+
 /**
  * Process packets received on the RADIUS socket
  */
-static bool receive(private_tnc_pdp_t *this, int fd, watcher_event_t event)
+static bool radius_receive(private_tnc_pdp_t *this, int fd, watcher_event_t event)
 {
        radius_message_t *request;
        char buffer[MAX_PACKET];
@@ -528,18 +695,27 @@ static bool receive(private_tnc_pdp_t *this, int fd, watcher_event_t event)
 METHOD(tnc_pdp_t, destroy, void,
        private_tnc_pdp_t *this)
 {
-       if (this->ipv4)
+       if (this->pt_tls_ipv4)
+       {
+               lib->watcher->remove(lib->watcher, this->pt_tls_ipv4);
+               close(this->pt_tls_ipv4);
+       }
+       if (this->pt_tls_ipv6)
        {
-               lib->watcher->remove(lib->watcher, this->ipv4);
-               close(this->ipv4);
+               lib->watcher->remove(lib->watcher, this->pt_tls_ipv6);
+               close(this->pt_tls_ipv6);
        }
-       if (this->ipv6)
+       if (this->radius_ipv4)
        {
-               lib->watcher->remove(lib->watcher, this->ipv6);
-               close(this->ipv6);
+               lib->watcher->remove(lib->watcher, this->radius_ipv4);
+               close(this->radius_ipv4);
+       }
+       if (this->radius_ipv6)
+       {
+               lib->watcher->remove(lib->watcher, this->radius_ipv6);
+               close(this->radius_ipv6);
        }
        DESTROY_IF(this->server);
-       DESTROY_IF(this->pt_tls_dispatcher);
        DESTROY_IF(this->signer);
        DESTROY_IF(this->hasher);
        DESTROY_IF(this->ng);
@@ -555,8 +731,6 @@ tnc_pdp_t *tnc_pdp_create(void)
        private_tnc_pdp_t *this;
        char *secret, *server, *eap_type_str;
        int radius_port, pt_tls_port;
-       identification_t *id;
-       host_t *host;
 
        server = lib->settings->get_str(lib->settings,
                                        "%s.plugins.tnc-pdp.server", NULL, charon->name);
@@ -580,22 +754,15 @@ tnc_pdp_t *tnc_pdp_create(void)
                return NULL;
        }
 
-       host = host_create_from_dns(server, AF_UNSPEC, pt_tls_port);
-       if (!host)
-       {
-               DBG1(DBG_CFG, "could not resolve server name");
-               return NULL;
-       }
-       id = identification_create_from_string(server);
-
        INIT(this,
                .public = {
                        .destroy = _destroy,
                },
-               .server = id,
-               .pt_tls_dispatcher = pt_tls_dispatcher_create(host, id, PT_TLS_AUTH_NONE),
-               .ipv4 = open_socket(AF_INET,  radius_port),
-               .ipv6 = open_socket(AF_INET6, radius_port),
+               .server = identification_create_from_string(server),
+               .pt_tls_ipv4 = open_tcp_socket(AF_INET,  pt_tls_port),
+               .pt_tls_ipv6 = open_tcp_socket(AF_INET6, pt_tls_port),
+               .radius_ipv4 = open_udp_socket(AF_INET,  radius_port),
+               .radius_ipv6 = open_udp_socket(AF_INET6, radius_port),
                .secret = chunk_from_str(secret),
                .type = eap_type_from_string(eap_type_str),
                .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
@@ -604,6 +771,31 @@ tnc_pdp_t *tnc_pdp_create(void)
                .connections = tnc_pdp_connections_create(),
        );
 
+       if (!this->pt_tls_ipv4 && !this->pt_tls_ipv6)
+       {
+               DBG1(DBG_NET, "could not create any PT-TLS sockets");
+               destroy(this);
+               return NULL;
+       }
+       if (this->pt_tls_ipv4)
+       {
+               lib->watcher->add(lib->watcher, this->pt_tls_ipv4, WATCHER_READ,
+                                                                       (watcher_cb_t)pt_tls_receive, this);
+       }
+       else
+       {
+               DBG1(DBG_NET, "could not open IPv4 PT-TLS socket, IPv4 disabled");
+       }
+       if (this->pt_tls_ipv6)
+       {
+               lib->watcher->add(lib->watcher, this->pt_tls_ipv6, WATCHER_READ,
+                                                                        (watcher_cb_t)pt_tls_receive, this);
+       }
+       else
+       {
+               DBG1(DBG_NET, "could not open IPv6 PT-TLS socket, IPv6 disabled");
+       }
+
        if (!this->hasher || !this->signer || !this->ng)
        {
                DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/NG required");
@@ -611,25 +803,26 @@ tnc_pdp_t *tnc_pdp_create(void)
                return NULL;
        }
 
-       if (!this->ipv4 && !this->ipv6)
+       if (!this->radius_ipv4 && !this->radius_ipv6)
        {
                DBG1(DBG_NET, "could not create any RADIUS sockets");
                destroy(this);
                return NULL;
        }
-       if (this->ipv4)
+       if (this->radius_ipv4)
        {
-               lib->watcher->add(lib->watcher, this->ipv4, WATCHER_READ,
-                                                (watcher_cb_t)receive, this);
+               lib->watcher->add(lib->watcher, this->radius_ipv4, WATCHER_READ,
+                                                (watcher_cb_t)radius_receive, this);
        }
        else
        {
                DBG1(DBG_NET, "could not open IPv4 RADIUS socket, IPv4 disabled");
        }
-       if (this->ipv6)
+       if (this->radius_ipv6)
+
        {
-               lib->watcher->add(lib->watcher, this->ipv6, WATCHER_READ,
-                                                (watcher_cb_t)receive, this);
+               lib->watcher->add(lib->watcher, this->radius_ipv6, WATCHER_READ,
+                                                (watcher_cb_t)radius_receive, this);
        }
        else
        {
index 14ab9cf6f827819ac89f6112216e6815436d1057..5586b568b89187cdeb6734a3d048db5da4d81cae 100644 (file)
@@ -52,6 +52,10 @@ static bool plugin_cb(private_tnc_pdp_plugin_t *this,
        if (reg)
        {
                this->pdp = tnc_pdp_create();
+               if (!this->pdp)
+               {
+                       return FALSE;
+               }
        }
        else
        {
index 4c8f3a9255d9be44b7d1a96cc94f570a5656e2ba..55f33c14370b004693a48b459dd4391f18caee02 100644 (file)
@@ -34,9 +34,8 @@
 #include <tnc/imc/imc_manager.h>
 #include <tnc/imv/imv_manager.h>
 
-#include <utils/debug.h>
-#include <daemon.h>
 #include <threading/mutex.h>
+#include <utils/debug.h>
 #include <collections/linked_list.h>
 #include <pen/pen.h>
 
@@ -934,10 +933,10 @@ tnccs_t* tnccs_20_create(bool is_server,
                .messages = linked_list_create(),
                .max_batch_len = lib->settings->get_int(lib->settings,
                                                                "%s.plugins.tnccs-20.max_batch_size", 65522,
-                                                               charon->name),
+                                                               "charon"),
                .max_msg_len = lib->settings->get_int(lib->settings,
                                                                "%s.plugins.tnccs-20.max_message_size", 65490,
-                                                               charon->name),
+                                                               "charon"),
        );
 
        return &this->public;
index 92a040f3f6e4475e1c3ceaf0614609262ea81065..7384cf2d5b08cace8447ddb2cc016e95c6735eb7 100644 (file)
  */
 #define PT_TLS_HEADER_LEN 16
 
+/**
+ * Default PT-TLS port
+ */
+#define PT_TLS_PORT     271
+
 typedef enum pt_tls_message_type_t pt_tls_message_type_t;
 typedef enum pt_tls_sasl_result_t pt_tls_sasl_result_t;
 typedef enum pt_tls_auth_t pt_tls_auth_t;
index d3ac936a2476bcdf42035b784a18ffc538369cd2..76dd5ee445368f2d58b1379cd639d05ee66c7d8b 100644 (file)
@@ -437,19 +437,26 @@ METHOD(pt_tls_client_t, run_assessment, status_t,
 {
        if (!this->tls)
        {
+               DBG1(DBG_TNC, "entering PT-TLS setup phase");
                if (!make_connection(this))
                {
                        return FAILED;
                }
        }
+
+       DBG1(DBG_TNC, "entering PT-TLS negotiation phase");
        if (!negotiate_version(this))
        {
                return FAILED;
        }
+
+       DBG1(DBG_TNC, "doing SASL client authentication");
        if (!authenticate(this))
        {
                return FAILED;
        }
+
+       DBG1(DBG_TNC, "entering PT-TLS data transport phase");
        if (!assess(this, (tls_t*)tnccs))
        {
                return FAILED;
index 4699516164c2b50cca7f87a1524b2aba730dedf9..5c306371cb15317728f0f4e34b719fbc11355d60 100644 (file)
@@ -185,7 +185,7 @@ pt_tls_dispatcher_t *pt_tls_dispatcher_create(host_t *address,
                        .dispatch = _dispatch,
                        .destroy = _destroy,
                },
-               .server = id,
+               .server = id->clone(id),
                /* we currently don't authenticate the peer, use %any identity */
                .peer = identification_create_from_encoding(ID_ANY, chunk_empty),
                .fd = -1,
@@ -194,11 +194,9 @@ pt_tls_dispatcher_t *pt_tls_dispatcher_create(host_t *address,
 
        if (!open_socket(this, address))
        {
-               address->destroy(address);
                destroy(this);
                return NULL;
        }
-       address->destroy(address);
 
        return &this->public;
 }
index 3e134f0dd89548872cda6206942f7d07a452f14c..2796e0dd0b3604671aac15154e8d61550d324d6f 100644 (file)
@@ -478,7 +478,7 @@ METHOD(pt_tls_server_t, handle, status_t,
                        }
                        DBG1(DBG_TNC, "negotiated PT-TLS version %d", PT_TLS_VERSION);
                        this->state = PT_TLS_SERVER_AUTH;
-                       break;
+                       /* fall through to next state */
                case PT_TLS_SERVER_AUTH:
                        if (!authenticate(this))
                        {
diff --git a/src/pt-tls-client/Makefile.am b/src/pt-tls-client/Makefile.am
new file mode 100644 (file)
index 0000000..2ce1a10
--- /dev/null
@@ -0,0 +1,21 @@
+ipsec_PROGRAMS = pt-tls-client
+
+pt_tls_client_SOURCES = pt-tls-client.c
+
+pt-tls-client.o :      $(top_builddir)/config.status
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/libstrongswan \
+       -I$(top_srcdir)/src/libtls \
+       -I$(top_srcdir)/src/libpttls \
+       -I$(top_srcdir)/src/libtncif \
+       -I$(top_srcdir)/src/libtnccs \
+       -DIPSEC_CONFDIR=\"${sysconfdir}\" \
+       -DPLUGINS="\"pem openssl nonce tnc-tnccs tnc-imc tnccs-20\""
+
+pt_tls_client_LDADD = \
+       $(top_builddir)/src/libstrongswan/libstrongswan.la \
+       $(top_builddir)/src/libtls/libtls.la \
+       $(top_builddir)/src/libpttls/libpttls.la \
+       $(top_builddir)/src/libtnccs/libtnccs.la
+
diff --git a/src/pt-tls-client/pt-tls-client b/src/pt-tls-client/pt-tls-client
new file mode 100755 (executable)
index 0000000..4e52d99
--- /dev/null
@@ -0,0 +1,228 @@
+#! /bin/bash
+
+# pt-tls-client - temporary wrapper script for .libs/pt-tls-client
+# Generated by libtool (GNU libtool) 2.4.2 Debian-2.4.2-1.2ubuntu1
+#
+# The pt-tls-client program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command="(cd /home/andreas/strongswan/src/pt-tls-client; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games; export PATH; gcc -g -O2 -Wall -Wno-format -Wno-pointer-sign -include /home/andreas/strongswan/config.h -o \$progdir/\$file pt-tls-client.o  ../../src/libstrongswan/.libs/libstrongswan.so ../../src/libtls/.libs/libtls.so ../../src/libpttls/.libs/libpttls.so ../../src/libtnccs/.libs/libtnccs.so -Wl,-rpath -Wl,/home/andreas/strongswan/src/libstrongswan/.libs -Wl,-rpath -Wl,/home/andreas/strongswan/src/libtls/.libs -Wl,-rpath -Wl,/home/andreas/strongswan/src/libpttls/.libs -Wl,-rpath -Wl,/home/andreas/strongswan/src/libtnccs/.libs -Wl,-rpath -Wl,/usr/lib/ipsec)"
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='2.4.2'
+  notinst_deplibs=' ../../src/libstrongswan/libstrongswan.la ../../src/libtls/libtls.la ../../src/libpttls/libpttls.la ../../src/libtnccs/libtnccs.la'
+else
+  # When we are sourced in execute mode, $file and $ECHO are already set.
+  if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+    file="$0"
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+    ECHO="printf %s\\n"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string --lt-
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's ../../libtool value, followed by no.
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=$0
+  shift
+  for lt_opt
+  do
+    case "$lt_opt" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%/[^/]*$%%'`
+        test "X$lt_dump_D" = "X$lt_script_arg0" && lt_dump_D=.
+        lt_dump_F=`$ECHO "X$lt_script_arg0" | /bin/sed -e 's/^X//' -e 's%^.*/%%'`
+        cat "$lt_dump_D/$lt_dump_F"
+        exit 0
+      ;;
+    --lt-*)
+        $ECHO "Unrecognized --lt- option: '$lt_opt'" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n "$lt_option_debug"; then
+    echo "pt-tls-client:pt-tls-client:${LINENO}: libtool wrapper (GNU libtool) 2.4.2 Debian-2.4.2-1.2ubuntu1" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    $ECHO "pt-tls-client:pt-tls-client:${LINENO}: newargv[$lt_dump_args_N]: $lt_arg"
+    lt_dump_args_N=`expr $lt_dump_args_N + 1`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+
+      if test -n "$lt_option_debug"; then
+        $ECHO "pt-tls-client:pt-tls-client:${LINENO}: newargv[0]: $progdir/$program" 1>&2
+        func_lt_dump_args ${1+"$@"} 1>&2
+      fi
+      exec "$progdir/$program" ${1+"$@"}
+
+      $ECHO "$0: cannot exec $program $*" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from $@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case " $* " in
+  *\ --lt-*)
+    for lt_wr_arg
+    do
+      case $lt_wr_arg in
+      --lt-*) ;;
+      *) set x "$@" "$lt_wr_arg"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core ${1+"$@"}
+}
+
+  # Parse options
+  func_parse_lt_options "$0" ${1+"$@"}
+
+  # Find the directory that this script lives in.
+  thisdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
+  test "x$thisdir" = "x$file" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'`
+  while test -n "$file"; do
+    destdir=`$ECHO "$file" | /bin/sed 's%/[^/]*$%%'`
+
+    # If there was a directory component, then change thisdir.
+    if test "x$destdir" != "x$file"; then
+      case "$destdir" in
+      [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+      *) thisdir="$thisdir/$destdir" ;;
+      esac
+    fi
+
+    file=`$ECHO "$file" | /bin/sed 's%^.*/%%'`
+    file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+  if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+    # special case for '.'
+    if test "$thisdir" = "."; then
+      thisdir=`pwd`
+    fi
+    # remove .libs from thisdir
+    case "$thisdir" in
+    *[\\/].libs ) thisdir=`$ECHO "$thisdir" | /bin/sed 's%[\\/][^\\/]*$%%'` ;;
+    .libs )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=`cd "$thisdir" && pwd`
+  test -n "$absdir" && thisdir="$absdir"
+
+  program=lt-'pt-tls-client'
+  progdir="$thisdir/.libs"
+
+  if test ! -f "$progdir/$program" ||
+     { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \
+       test "X$file" != "X$progdir/$program"; }; then
+
+    file="$$-$program"
+
+    if test ! -d "$progdir"; then
+      mkdir "$progdir"
+    else
+      rm -f "$progdir/$file"
+    fi
+
+    # relink executable if necessary
+    if test -n "$relink_command"; then
+      if relink_command_output=`eval $relink_command 2>&1`; then :
+      else
+       printf %s\n "$relink_command_output" >&2
+       rm -f "$progdir/$file"
+       exit 1
+      fi
+    fi
+
+    mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null ||
+    { rm -f "$progdir/$program";
+      mv -f "$progdir/$file" "$progdir/$program"; }
+    rm -f "$progdir/$file"
+  fi
+
+  if test -f "$progdir/$program"; then
+    if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+      # Run the actual program with our arguments.
+      func_exec_program ${1+"$@"}
+    fi
+  else
+    # The program doesn't exist.
+    $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2
+    $ECHO "This script is just a wrapper for $program." 1>&2
+    $ECHO "See the libtool documentation for more information." 1>&2
+    exit 1
+  fi
+fi
diff --git a/src/pt-tls-client/pt-tls-client.c b/src/pt-tls-client/pt-tls-client.c
new file mode 100644 (file)
index 0000000..2b104f8
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2010-2013 Martin Willi, revosec AG
+ * Copyright (C) 2013 Andreas Steffen, HSR Hochschule für Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <getopt.h>
+#include <errno.h>
+#include <string.h>
+
+#include <library.h>
+#include <utils/debug.h>
+#include <pt_tls.h>
+#include <pt_tls_client.h>
+#include <tnc/tnc.h>
+#include <tls.h>
+
+#include <credentials/sets/mem_cred.h>
+
+/**
+ * Print usage information
+ */
+static void usage(FILE *out, char *cmd)
+{
+       fprintf(out, "usage:\n");
+       fprintf(out, "  %s --connect <address> [--port <port>] [--cert <file>]+\n", cmd);
+       fprintf(out, "               [--client <client-id>] [--secret <password>]\n");
+}
+
+/**
+ * Client routine
+ */
+static int client(char *address, u_int16_t port, char *identity)
+{
+       pt_tls_client_t *assessment;
+       tls_t *tnccs;
+       identification_t *server, *client;
+       host_t *host;
+       status_t status;
+
+       host = host_create_from_dns(address, AF_UNSPEC, port);
+       if (!host)
+       {
+               return 1;
+       }
+       server = identification_create_from_string(address);
+       client = identification_create_from_string(identity);
+       tnccs = (tls_t*)tnc->tnccs->create_instance(tnc->tnccs, TNCCS_2_0, FALSE,
+                                                                                               server, client, TNC_IFT_TLS_2_0);
+       if (!tnccs)
+       {
+               fprintf(stderr, "loading TNCCS failed: %s\n", PLUGINS);
+               host->destroy(host);
+               server->destroy(server);
+               client->destroy(client);
+               return 1;
+       }
+       assessment = pt_tls_client_create(host, server, client);
+       status = assessment->run_assessment(assessment, (tnccs_t*)tnccs);
+       assessment->destroy(assessment);
+       tnccs->destroy(tnccs);
+       return status;
+}
+
+
+/**
+ * In-Memory credential set
+ */
+static mem_cred_t *creds;
+
+/**
+ * Load certificate from file
+ */
+static bool load_certificate(char *filename)
+{
+       certificate_t *cert;
+
+       cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+                                                         BUILD_FROM_FILE, filename, BUILD_END);
+       if (!cert)
+       {
+               DBG1(DBG_TLS, "loading certificate from '%s' failed", filename);
+               return FALSE;
+       }
+       creds->add_cert(creds, TRUE, cert);
+       return TRUE;
+}
+
+/**
+ * Load private key from file
+ */
+static bool load_key(char *filename)
+{
+       private_key_t *key;
+
+       key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
+                                                        BUILD_FROM_FILE, filename, BUILD_END);
+       if (!key)
+       {
+               DBG1(DBG_TLS, "loading key from '%s' failed", filename);
+               return FALSE;
+       }
+       creds->add_key(creds, key);
+       return TRUE;
+}
+
+/**
+ * Debug level
+ */
+static level_t pt_tls_level = 2;
+
+static void dbg_pt_tls(debug_t group, level_t level, char *fmt, ...)
+{
+       if (level <= pt_tls_level)
+       {
+               va_list args;
+
+               va_start(args, fmt);
+               vfprintf(stderr, fmt, args);
+               fprintf(stderr, "\n");
+               va_end(args);
+       }
+}
+
+/**
+ * Cleanup
+ */
+static void cleanup()
+{
+       lib->processor->cancel(lib->processor);
+       lib->credmgr->remove_set(lib->credmgr, &creds->set);
+       creds->destroy(creds);
+       libtnccs_deinit();
+       library_deinit();
+}
+
+/**
+ * Initialize library
+ */
+static void init()
+{
+       library_init(NULL);
+       libtnccs_init();
+
+       dbg = dbg_pt_tls;
+
+       if (!lib->plugins->load(lib->plugins,
+                       lib->settings->get_str(lib->settings, "pt-tls-client.load", PLUGINS)))
+       {
+               exit(SS_RC_INITIALIZATION_FAILED);
+       }
+
+       creds = mem_cred_create();
+       lib->credmgr->add_set(lib->credmgr, &creds->set);
+
+       atexit(cleanup);
+}
+
+int main(int argc, char *argv[])
+{
+       char *address = NULL, *identity = "%any", *secret = NULL;
+       int port = PT_TLS_PORT;
+
+       init();
+
+       while (TRUE)
+       {
+               struct option long_opts[] = {
+                       {"help",                no_argument,                    NULL,           'h' },
+                       {"connect",             required_argument,              NULL,           'c' },
+                       {"client",              required_argument,              NULL,           'i' },
+                       {"secret",              required_argument,              NULL,           's' },
+                       {"port",                required_argument,              NULL,           'p' },
+                       {"cert",                required_argument,              NULL,           'x' },
+                       {"key",                 required_argument,              NULL,           'k' },
+                       {"debug",               required_argument,              NULL,           'd' },
+                       {0,0,0,0 }
+               };
+               switch (getopt_long(argc, argv, "", long_opts, NULL))
+               {
+                       case EOF:
+                               break;
+                       case 'h':
+                               usage(stdout, argv[0]);
+                               return 0;
+                       case 'x':
+                               if (!load_certificate(optarg))
+                               {
+                                       return 1;
+                               }
+                               continue;
+                       case 'k':
+                               if (!load_key(optarg))
+                               {
+                                       return 1;
+                               }
+                               continue;
+                       case 'c':
+                               if (address)
+                               {
+                                       usage(stderr, argv[0]);
+                                       return 1;
+                               }
+                               address = optarg;
+                               continue;
+                       case 'i':
+                               identity = optarg;
+                               continue;
+                       case 's':
+                               secret = optarg;
+                               continue;
+                       case 'p':
+                               port = atoi(optarg);
+                               continue;
+                       case 'd':
+                               pt_tls_level = atoi(optarg);
+                               continue;
+                       default:
+                               usage(stderr, argv[0]);
+                               return 1;
+               }
+               break;
+       }
+       if (!address)
+       {
+               usage(stderr, argv[0]);
+               return 1;
+       }
+       if (secret)
+       {
+               creds->add_shared(creds, shared_key_create(SHARED_EAP,
+                                                                               chunk_clone(chunk_from_str(secret))),
+                                                       identification_create_from_string(identity), NULL);
+       }
+
+       return client(address, port, identity);
+}