added eap_ttls plugin configuration
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 6 Aug 2010 05:45:03 +0000 (07:45 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 7 Aug 2010 09:26:04 +0000 (11:26 +0200)
configure.in
src/libcharon/Makefile.am
src/libcharon/plugins/eap_ttls/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/eap_ttls/eap_ttls.c [new file with mode: 0644]
src/libcharon/plugins/eap_ttls/eap_ttls.h [new file with mode: 0644]
src/libcharon/plugins/eap_ttls/eap_ttls_plugin.c [new file with mode: 0644]
src/libcharon/plugins/eap_ttls/eap_ttls_plugin.h [new file with mode: 0644]

index dc73e39..2324f32 100644 (file)
@@ -16,7 +16,7 @@ dnl ===========================
 dnl  initialize & set some vars
 dnl ===========================
 
-AC_INIT(strongSwan,4.4.2)
+AC_INIT(strongSwan,4.4.2dr1)
 AM_INIT_AUTOMAKE(tar-ustar)
 AC_CONFIG_MACRO_DIR([m4/config])
 PKG_PROG_PKG_CONFIG
@@ -112,6 +112,7 @@ ARG_ENABL_SET([eap-aka],        [enable EAP AKA authentication module.])
 ARG_ENABL_SET([eap-aka-3gpp2],  [enable EAP AKA backend implementing 3GPP2 algorithms in software. Requires libgmp.])
 ARG_ENABL_SET([eap-mschapv2],   [enable EAP MS-CHAPv2 authenication module.])
 ARG_ENABL_SET([eap-tls],        [enable EAP TLS authenication module.])
+ARG_ENABL_SET([eap-ttls],       [enable EAP TTLS authenication module.])
 ARG_ENABL_SET([eap-radius],     [enable RADIUS proxy authenication module.])
 ARG_DISBL_SET([kernel-netlink], [disable the netlink kernel interface.])
 ARG_ENABL_SET([kernel-pfkey],   [enable the PF_KEY kernel interface.])
@@ -226,7 +227,7 @@ if test x$eap_sim = xtrue; then
        simaka=true;
 fi
 
-if test x$eap_tls = xtrue; then
+if test x$eap_tls = xtrue -o x$eap_ttls = xtrue; then
        tls=true;
 fi
 
@@ -857,6 +858,7 @@ AM_CONDITIONAL(USE_EAP_AKA, test x$eap_aka = xtrue)
 AM_CONDITIONAL(USE_EAP_AKA_3GPP2, test x$eap_aka_3gpp2 = xtrue)
 AM_CONDITIONAL(USE_EAP_MSCHAPV2, test x$eap_mschapv2 = xtrue)
 AM_CONDITIONAL(USE_EAP_TLS, test x$eap_tls = xtrue)
+AM_CONDITIONAL(USE_EAP_TTLS, test x$eap_ttls = xtrue)
 AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue)
 AM_CONDITIONAL(USE_KERNEL_NETLINK, test x$kernel_netlink = xtrue)
 AM_CONDITIONAL(USE_KERNEL_PFKEY, test x$kernel_pfkey = xtrue)
@@ -984,6 +986,7 @@ AC_OUTPUT(
        src/libcharon/plugins/eap_simaka_reauth/Makefile
        src/libcharon/plugins/eap_mschapv2/Makefile
        src/libcharon/plugins/eap_tls/Makefile
+       src/libcharon/plugins/eap_ttls/Makefile
        src/libcharon/plugins/eap_radius/Makefile
        src/libcharon/plugins/kernel_netlink/Makefile
        src/libcharon/plugins/kernel_pfkey/Makefile
index 4681fb9..4ea1565 100644 (file)
@@ -352,6 +352,14 @@ if MONOLITHIC
 endif
 endif
 
+if USE_EAP_TTLS
+  SUBDIRS += plugins/eap_ttls
+  PLUGINS += eap-ttls
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/eap_ttls/libstrongswan-eap-ttls.la
+endif
+endif
+
 if USE_TLS
 if MONOLITHIC
   # otherwise this library is linked to eap_tls
diff --git a/src/libcharon/plugins/eap_ttls/Makefile.am b/src/libcharon/plugins/eap_ttls/Makefile.am
new file mode 100644 (file)
index 0000000..fdd4606
--- /dev/null
@@ -0,0 +1,17 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libtls
+
+AM_CFLAGS = -rdynamic
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-eap-ttls.la
+else
+plugin_LTLIBRARIES = libstrongswan-eap-ttls.la
+libstrongswan_eap_ttls_la_LIBADD = $(top_builddir)/src/libtls/libtls.la
+endif
+
+libstrongswan_eap_ttls_la_SOURCES = \
+       eap_ttls_plugin.h eap_ttls_plugin.c eap_ttls.h eap_ttls.c
+
+libstrongswan_eap_ttls_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.c b/src/libcharon/plugins/eap_ttls/eap_ttls.c
new file mode 100644 (file)
index 0000000..96b4cff
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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 "eap_ttls.h"
+
+#include <tls.h>
+
+#include <daemon.h>
+#include <library.h>
+
+typedef struct private_eap_ttls_t private_eap_ttls_t;
+
+/**
+ * Private data of an eap_ttls_t object.
+ */
+struct private_eap_ttls_t {
+
+       /**
+        * Public interface.
+        */
+       eap_ttls_t public;
+
+       /**
+        * Number of EAP-TLS messages processed so far
+        */
+       int processed;
+
+       /**
+        * Is this method instance acting as server?
+        */
+       bool is_server;
+
+       /**
+        * TLS layers
+        */
+       tls_t *tls;
+
+       /**
+        * Allocated input buffer
+        */
+       chunk_t input;
+
+       /**
+        * Number of bytes read in input buffer
+        */
+       size_t inpos;
+
+       /**
+        * Allocated ouput buffer
+        */
+       chunk_t output;
+
+       /**
+        * Number of bytes sent from output buffer
+        */
+       size_t outpos;
+};
+
+/** Size limit for a single TLS message */
+#define MAX_TLS_MESSAGE_LEN 16384
+/** Size of a EAP-TLS fragment */
+#define EAP_TTLS_FRAGMENT_LEN 1014
+/** Maximum number of EAP-TLS messages/fragments allowed */
+#define MAX_EAP_TTLS_MESSAGE_COUNT 16
+
+/**
+ * Flags of an EAP-TLS message
+ */
+typedef enum {
+       EAP_TTLS_LENGTH = (1<<7),
+       EAP_TTLS_MORE_FRAGS = (1<<6),
+       EAP_TTLS_START = (1<<5),
+} eap_ttls_flags_t;
+
+/**
+ * EAP-TLS packet format
+ */
+typedef struct __attribute__((packed)) {
+       u_int8_t code;
+       u_int8_t identifier;
+       u_int16_t length;
+       u_int8_t type;
+       u_int8_t flags;
+} eap_ttls_packet_t;
+
+/**
+ * TLS record
+ */
+typedef struct __attribute__((packed)) {
+       u_int8_t type;
+       u_int16_t version;
+       u_int16_t length;
+       char data[];
+} tls_record_t;
+
+METHOD(eap_method_t, initiate, status_t,
+       private_eap_ttls_t *this, eap_payload_t **out)
+{
+       if (this->is_server)
+       {
+               eap_ttls_packet_t pkt = {
+                       .type = EAP_TTLS,
+                       .code = EAP_REQUEST,
+                       .flags = EAP_TTLS_START,
+               };
+               htoun16(&pkt.length, sizeof(eap_ttls_packet_t));
+               /* start with non-zero random identifier */
+               do {
+                       pkt.identifier = random();
+               } while (!pkt.identifier);
+
+               *out = eap_payload_create_data(chunk_from_thing(pkt));
+               return NEED_MORE;
+       }
+       return FAILED;
+}
+
+/**
+ * Write received TLS data to the input buffer
+ */
+static bool write_buf(private_eap_ttls_t *this, eap_ttls_packet_t *pkt)
+{
+       u_int32_t msg_len;
+       u_int16_t pkt_len;
+       chunk_t data;
+
+       pkt_len = untoh16(&pkt->length);
+
+       if (pkt->flags & EAP_TTLS_LENGTH)
+       {
+               if (pkt_len < sizeof(eap_ttls_packet_t) + sizeof(msg_len))
+               {
+                       DBG1(DBG_IKE, "EAP-TLS packet too short");
+                       return FALSE;
+               }
+               msg_len = untoh32(pkt + 1);
+               if (msg_len < pkt_len - sizeof(eap_ttls_packet_t) - sizeof(msg_len) ||
+                       msg_len > MAX_TLS_MESSAGE_LEN)
+               {
+                       DBG1(DBG_IKE, "invalid EAP-TLS packet length");
+                       return FALSE;
+               }
+               if (this->input.ptr)
+               {
+                       if (msg_len != this->input.len)
+                       {
+                               DBG1(DBG_IKE, "received unexpected TLS message length");
+                               return FALSE;
+                       }
+               }
+               else
+               {
+                       this->input = chunk_alloc(msg_len);
+                       this->inpos = 0;
+               }
+               data = chunk_create((char*)(pkt + 1) + sizeof(msg_len),
+                                               pkt_len - sizeof(eap_ttls_packet_t) - sizeof(msg_len));
+       }
+       else
+       {
+               data = chunk_create((char*)(pkt + 1),
+                                               pkt_len - sizeof(eap_ttls_packet_t));
+       }
+       if (data.len > this->input.len - this->inpos)
+       {
+               DBG1(DBG_IKE, "EAP-TLS fragment exceeds TLS message length");
+               return FALSE;
+       }
+       memcpy(this->input.ptr + this->inpos, data.ptr, data.len);
+       this->inpos += data.len;
+       return TRUE;
+}
+
+/**
+ * Send an ack to request next fragment
+ */
+static eap_payload_t *create_ack(private_eap_ttls_t *this, u_int8_t identifier)
+{
+       eap_ttls_packet_t pkt = {
+               .code = this->is_server ? EAP_REQUEST : EAP_RESPONSE,
+               .identifier = this->is_server ? identifier + 1 : identifier,
+               .type = EAP_TTLS,
+       };
+       htoun16(&pkt.length, sizeof(pkt));
+
+       return eap_payload_create_data(chunk_from_thing(pkt));
+}
+
+/**
+ * Create a eap response from data in the TLS output buffer
+ */
+static eap_payload_t *read_buf(private_eap_ttls_t *this, u_int8_t identifier)
+{
+       char buf[EAP_TTLS_FRAGMENT_LEN + sizeof(eap_ttls_packet_t) + 4], *start;
+       eap_ttls_packet_t *pkt = (eap_ttls_packet_t*)buf;
+       u_int16_t pkt_len = sizeof(eap_ttls_packet_t);
+
+       pkt->code = this->is_server ? EAP_REQUEST : EAP_RESPONSE;
+       pkt->identifier = this->is_server ? identifier + 1 : identifier;
+       pkt->type = EAP_TTLS;
+       pkt->flags = 0;
+
+       if (this->output.len)
+       {
+               start = (char*)(pkt + 1);
+               if (this->outpos == 0)
+               {       /* first fragment */
+                       pkt->flags = EAP_TTLS_LENGTH;
+                       pkt_len += 4;
+                       start += 4;
+                       htoun32(pkt + 1, this->output.len);
+               }
+
+               if (this->output.len - this->outpos > EAP_TTLS_FRAGMENT_LEN)
+               {
+                       pkt->flags |= EAP_TTLS_MORE_FRAGS;
+                       pkt_len += EAP_TTLS_FRAGMENT_LEN;
+                       memcpy(start, this->output.ptr + this->outpos, EAP_TTLS_FRAGMENT_LEN);
+                       this->outpos += EAP_TTLS_FRAGMENT_LEN;
+               }
+               else
+               {
+                       pkt_len += this->output.len - this->outpos;
+                       memcpy(start, this->output.ptr + this->outpos,
+                                  this->output.len - this->outpos);
+                       chunk_free(&this->output);
+                       this->outpos = 0;
+               }
+       }
+       htoun16(&pkt->length, pkt_len);
+       return eap_payload_create_data(chunk_create(buf, pkt_len));
+}
+
+/**
+ * Pass data in input buffer to upper layers, write result to output buffer
+ */
+static status_t process_buf(private_eap_ttls_t *this)
+{
+       tls_record_t *in, out;
+       chunk_t data;
+       u_int16_t len;
+       status_t status;
+
+       /* pass input buffer to upper layer, record for record */
+       data = this->input;
+       while (data.len > sizeof(tls_record_t))
+       {
+               in = (tls_record_t*)data.ptr;
+               len = untoh16(&in->length);
+               if (len > data.len - sizeof(tls_record_t))
+               {
+                       DBG1(DBG_IKE, "TLS record length invalid");
+                       return FAILED;
+               }
+               if (untoh16(&in->version) < TLS_1_0)
+               {
+                       DBG1(DBG_IKE, "%N invalid with EAP-TLS",
+                                tls_version_names, untoh16(&in->version));
+                       return FAILED;
+               }
+
+               status = this->tls->process(this->tls, in->type,
+                                                                       chunk_create(in->data, len));
+               if (status != NEED_MORE)
+               {
+                       return status;
+               }
+               data = chunk_skip(data, len + sizeof(tls_record_t));
+       }
+       chunk_free(&this->input);
+       this->inpos = 0;
+
+       /* read in records from upper layer, append to output buffer */
+       chunk_free(&this->output);
+       while (TRUE)
+       {
+               tls_content_type_t type;
+               chunk_t header = chunk_from_thing(out);
+
+               status = this->tls->build(this->tls, &type, &data);
+               switch (status)
+               {
+                       case NEED_MORE:
+                               break;
+                       case INVALID_STATE:
+                               /* invalid state means we need more input from peer first */
+                               return NEED_MORE;
+                       case SUCCESS:
+                               return SUCCESS;
+                       case FAILED:
+                       default:
+                               return FAILED;
+               }
+               out.type = type;
+               htoun16(&out.version, this->tls->get_version(this->tls));
+               htoun16(&out.length, data.len);
+               this->output = chunk_cat("mcm", this->output, header, data);
+       }
+}
+
+METHOD(eap_method_t, process, status_t,
+       private_eap_ttls_t *this, eap_payload_t *in, eap_payload_t **out)
+{
+       eap_ttls_packet_t *pkt;
+       chunk_t data;
+       status_t status;
+
+       if (++this->processed > MAX_EAP_TTLS_MESSAGE_COUNT)
+       {
+               DBG1(DBG_IKE, "EAP-TLS packet count exceeded");
+               return FAILED;
+       }
+
+       data = in->get_data(in);
+
+       pkt = (eap_ttls_packet_t*)data.ptr;
+       if (data.len < sizeof(eap_ttls_packet_t) ||
+               untoh16(&pkt->length) != data.len)
+       {
+               DBG1(DBG_IKE, "invalid EAP-TLS packet length");
+               return FAILED;
+       }
+       if (!(pkt->flags & EAP_TTLS_START))
+       {
+               if (data.len == sizeof(eap_ttls_packet_t))
+               {
+                       if (this->output.len)
+                       {       /* ACK to our fragment, send next */
+                               *out = read_buf(this, pkt->identifier);
+                               return NEED_MORE;
+                       }
+                       if (this->tls->is_complete(this->tls))
+                       {
+                               return SUCCESS;
+                       }
+                       return FAILED;
+               }
+               if (!write_buf(this, pkt))
+               {
+                       return FAILED;
+               }
+               if (pkt->flags & EAP_TTLS_MORE_FRAGS)
+               {       /* more fragments follow */
+                       *out = create_ack(this, pkt->identifier);
+                       return NEED_MORE;
+               }
+               else if (this->input.len != this->inpos)
+               {
+                       DBG1(DBG_IKE, "defragemented TLS message has invalid length");
+                       return FAILED;
+               }
+       }
+       status = process_buf(this);
+       if (status == NEED_MORE)
+       {
+               *out = read_buf(this, pkt->identifier);
+       }
+       return status;
+}
+
+METHOD(eap_method_t, get_type, eap_type_t,
+       private_eap_ttls_t *this, u_int32_t *vendor)
+{
+       *vendor = 0;
+       return EAP_TTLS;
+}
+
+METHOD(eap_method_t, get_msk, status_t,
+       private_eap_ttls_t *this, chunk_t *msk)
+{
+       *msk = this->tls->get_eap_msk(this->tls);
+       if (msk->len)
+       {
+               return SUCCESS;
+       }
+       return FAILED;
+}
+
+METHOD(eap_method_t, is_mutual, bool,
+       private_eap_ttls_t *this)
+{
+       return TRUE;
+}
+
+METHOD(eap_method_t, destroy, void,
+       private_eap_ttls_t *this)
+{
+       free(this->input.ptr);
+       free(this->output.ptr);
+
+       this->tls->destroy(this->tls);
+
+       free(this);
+}
+
+/**
+ * Generic private constructor
+ */
+static eap_ttls_t *eap_ttls_create(identification_t *server,
+                                                                identification_t *peer, bool is_server)
+{
+       private_eap_ttls_t *this;
+
+       INIT(this,
+               .public.eap_method = {
+                       .initiate = _initiate,
+                       .process = _process,
+                       .get_type = _get_type,
+                       .is_mutual = _is_mutual,
+                       .get_msk = _get_msk,
+                       .destroy = _destroy,
+               },
+               .is_server = is_server,
+       );
+       this->tls = tls_create(is_server, server, peer);
+
+       return &this->public;
+}
+
+eap_ttls_t *eap_ttls_create_server(identification_t *server,
+                                                                identification_t *peer)
+{
+       return eap_ttls_create(server, peer, TRUE);
+}
+
+eap_ttls_t *eap_ttls_create_peer(identification_t *server,
+                                                          identification_t *peer)
+{
+       return eap_ttls_create(server, peer, FALSE);
+}
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.h b/src/libcharon/plugins/eap_ttls/eap_ttls.h
new file mode 100644 (file)
index 0000000..74cc836
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010 HSR Hochschule fuer 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.
+ */
+
+/**
+ * @defgroup eap_ttls_i eap_ttls
+ * @{ @ingroup eap_ttls
+ */
+
+#ifndef EAP_TTLS_H_
+#define EAP_TTLS_H_
+
+typedef struct eap_ttls_t eap_ttls_t;
+
+#include <sa/authenticators/eap/eap_method.h>
+
+/**
+ * Implementation of eap_method_t using EAP-TTLS.
+ */
+struct eap_ttls_t {
+
+       /**
+        * Implements eap_method_t interface.
+        */
+       eap_method_t eap_method;
+};
+
+/**
+ * Creates the EAP method EAP-TTLS acting as server.
+ *
+ * @param server       ID of the EAP server
+ * @param peer         ID of the EAP client
+ * @return                     eap_ttls_t object
+ */
+eap_ttls_t *eap_ttls_create_server(identification_t *server,
+                                                                identification_t *peer);
+
+/**
+ * Creates the EAP method EAP-TTLS acting as peer.
+ *
+ * @param server       ID of the EAP server
+ * @param peer         ID of the EAP client
+ * @return                     eap_ttls_t object
+ */
+eap_ttls_t *eap_ttls_create_peer(identification_t *server,
+                                                          identification_t *peer);
+
+#endif /** EAP_TTLS_H_ @}*/
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_plugin.c b/src/libcharon/plugins/eap_ttls/eap_ttls_plugin.c
new file mode 100644 (file)
index 0000000..642e004
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010 HSR Hochschule fuer 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 "eap_ttls_plugin.h"
+
+#include "eap_ttls.h"
+
+#include <daemon.h>
+
+
+METHOD(plugin_t, destroy, void,
+       eap_ttls_plugin_t *this)
+{
+       charon->eap->remove_method(charon->eap,
+                                                          (eap_constructor_t)eap_ttls_create_server);
+       charon->eap->remove_method(charon->eap,
+                                                          (eap_constructor_t)eap_ttls_create_peer);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+plugin_t *eap_ttls_plugin_create()
+{
+       eap_ttls_plugin_t *this;
+
+       INIT(this,
+               .plugin.destroy = _destroy,
+       );
+
+       charon->eap->add_method(charon->eap, EAP_TTLS, 0, EAP_SERVER,
+                                                       (eap_constructor_t)eap_ttls_create_server);
+       charon->eap->add_method(charon->eap, EAP_TTLS, 0, EAP_PEER,
+                                                       (eap_constructor_t)eap_ttls_create_peer);
+
+       return &this->plugin;
+}
diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_plugin.h b/src/libcharon/plugins/eap_ttls/eap_ttls_plugin.h
new file mode 100644 (file)
index 0000000..2abc829
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 Andreas Steffen
+ * Copyright (C) 2010 HSR Hochschule fuer 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.
+ */
+
+/**
+ * @defgroup eap_ttls eap_ttls
+ * @ingroup cplugins
+ *
+ * @defgroup eap_ttls_plugin eap_ttls_plugin
+ * @{ @ingroup eap_ttls
+ */
+
+#ifndef EAP_TTLS_PLUGIN_H_
+#define EAP_TTLS_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct eap_ttls_plugin_t eap_ttls_plugin_t;
+
+/**
+ * EAP-TTLS plugin
+ */
+struct eap_ttls_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+/**
+ * Create a eap_ttls_plugin instance.
+ */
+plugin_t *eap_ttls_plugin_create();
+
+#endif /** EAP_TTLS_PLUGIN_H_ @}*/