diff options
27 files changed, 3089 insertions, 1 deletions
diff --git a/configure.in b/configure.in index 60298b19b..bc0fffc79 100644 --- a/configure.in +++ b/configure.in @@ -132,6 +132,8 @@ ARG_ENABL_SET([tnc-imv], [enable TNC IMV module.]) ARG_ENABL_SET([tnccs-11], [enable TNCCS 1.1 protocol module.]) 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.]) +ARG_ENABL_SET([imv-test], [enable IMV test module.]) ARG_DISBL_SET([kernel-netlink], [disable the netlink kernel interface.]) ARG_ENABL_SET([kernel-pfkey], [enable the PF_KEY kernel interface.]) ARG_ENABL_SET([kernel-pfroute], [enable the PF_ROUTE kernel interface.]) @@ -240,6 +242,10 @@ if test x$eap_tls = xtrue -o x$eap_ttls = xtrue -o x$eap_peap = xtrue; then tls=true; fi +if test x$imc_test = xtrue -o x$imv_test = xtrue; then + imcv=true; +fi + if test x$fips_prf = xtrue; then if test x$openssl = xfalse; then sha1=true; @@ -802,6 +808,8 @@ ADD_PLUGIN([maemo], [c libcharon]) ADD_PLUGIN([uci], [c libcharon]) ADD_PLUGIN([addrblock], [c libcharon]) ADD_PLUGIN([unit-tester], [c libcharon]) +ADD_PLUGIN([imc-test], [c]) +ADD_PLUGIN([imv-test], [c]) AC_SUBST(libcharon_plugins) AC_SUBST(pluto_plugins) @@ -902,6 +910,8 @@ AM_CONDITIONAL(USE_TNC_IMV, test x$tnc_imv = xtrue) AM_CONDITIONAL(USE_TNCCS_11, test x$tnccs_11 = xtrue) AM_CONDITIONAL(USE_TNCCS_20, test x$tnccs_20 = xtrue) AM_CONDITIONAL(USE_TNCCS_DYNAMIC, test x$tnccs_dynamic = xtrue) +AM_CONDITIONAL(USE_IMC_TEST, test x$imc_test = xtrue) +AM_CONDITIONAL(USE_IMV_TEST, test x$imv_test = xtrue) AM_CONDITIONAL(USE_SOCKET_DEFAULT, test x$socket_default = xtrue) AM_CONDITIONAL(USE_SOCKET_RAW, test x$socket_raw = xtrue) AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue) @@ -952,6 +962,7 @@ AM_CONDITIONAL(USE_LIBCAP, test x$capabilities = xlibcap) AM_CONDITIONAL(USE_VSTR, test x$vstr = xtrue) AM_CONDITIONAL(USE_SIMAKA, test x$simaka = xtrue) AM_CONDITIONAL(USE_TLS, test x$tls = xtrue) +AM_CONDITIONAL(USE_IMCV, test x$imcv = xtrue) AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue) dnl ============================== @@ -1027,6 +1038,7 @@ AC_OUTPUT( src/libfreeswan/Makefile src/libsimaka/Makefile src/libtls/Makefile + src/libimcv/Makefile src/pluto/Makefile src/pluto/plugins/xauth/Makefile src/whack/Makefile @@ -1054,6 +1066,8 @@ AC_OUTPUT( src/libcharon/plugins/tnccs_11/Makefile src/libcharon/plugins/tnccs_20/Makefile src/libcharon/plugins/tnccs_dynamic/Makefile + src/libcharon/plugins/imc_test/Makefile + src/libcharon/plugins/imv_test/Makefile src/libcharon/plugins/socket_default/Makefile src/libcharon/plugins/socket_raw/Makefile src/libcharon/plugins/socket_dynamic/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index cd75de5e9..4bafcbd06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,10 @@ if USE_TLS SUBDIRS += libtls endif +if USE_IMCV + SUBDIRS += libimcv +endif + if USE_LIBCHARON SUBDIRS += libcharon endif diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 9a4b28c3a..23c57cbab 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -90,10 +90,11 @@ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/task.c sa/tasks/task.h \ -tnc/tncif.h tnc/tncifimc.h tnc/tncifimv.h tnc/tncifimv.c \ +tnc/tncif.h tnc/tncif.c tnc/tncifimc.h tnc/tncifimv.h tnc/tncifimv.c \ tnc/imc/imc.h tnc/imc/imc_manager.h \ tnc/imv/imv.h tnc/imv/imv_manager.h \ tnc/imv/imv_recommendations.c tnc/imv/imv_recommendations.h \ +tnc/pen/pen.h tnc/pen/pen.c \ tnc/tnccs/tnccs.c tnc/tnccs/tnccs.h \ tnc/tnccs/tnccs_manager.c tnc/tnccs/tnccs_manager.h @@ -370,6 +371,14 @@ if MONOLITHIC endif endif +if USE_IMC_TEST + SUBDIRS += plugins/imc_test +endif + +if USE_IMV_TEST + SUBDIRS += plugins/imv_test +endif + if USE_MEDSRV SUBDIRS += plugins/medsrv if MONOLITHIC diff --git a/src/libcharon/plugins/imc_test/Makefile.am b/src/libcharon/plugins/imc_test/Makefile.am new file mode 100644 index 000000000..ffad4e445 --- /dev/null +++ b/src/libcharon/plugins/imc_test/Makefile.am @@ -0,0 +1,15 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libimcv + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-imc-test.la + +libstrongswan_imc_test_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la + +libstrongswan_imc_test_la_SOURCES = imc_test.c \ + imc_test_state.h imc_test_state.c + +libstrongswan_imc_test_la_LDFLAGS = -module -avoid-version + diff --git a/src/libcharon/plugins/imc_test/imc_test.c b/src/libcharon/plugins/imc_test/imc_test.c new file mode 100644 index 000000000..8390aad59 --- /dev/null +++ b/src/libcharon/plugins/imc_test/imc_test.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "imc_test_state.h" + +#include <imc/imc_agent.h> +#include <pa_tnc/pa_tnc_msg.h> +#include <ita/ita_attr_command.h> +#include <tnc/pen/pen.h> +#include <debug.h> + +/* IMC definitions */ + +static const char imc_name[] = "Test"; + +#define IMC_VENDOR_ID PEN_ITA +#define IMC_SUBTYPE 0x01 + +static imc_agent_t *imc_test; + +/** + * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2 + */ +TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, + TNC_Version min_version, + TNC_Version max_version, + TNC_Version *actual_version) +{ + if (imc_test) + { + DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name); + return TNC_RESULT_ALREADY_INITIALIZED; + } + if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1) + { + DBG1(DBG_IMC, "no common IF-IMC version"); + return TNC_RESULT_NO_COMMON_VERSION; + } + imc_test = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE, + imc_id, actual_version); + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2 + */ +TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imc_state_t *state; + + if (!imc_test) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imc_test_state_create(connection_id); + return imc_test->create_state(imc_test, state); + case TNC_CONNECTION_STATE_DELETE: + return imc_test->delete_state(imc_test, connection_id); + default: + return imc_test->change_state(imc_test, connection_id, new_state); + } +} + +static TNC_Result send_message(TNC_ConnectionID connection_id) +{ + pa_tnc_msg_t *msg; + pa_tnc_attr_t *attr; + char *command; + TNC_Result result; + + command = lib->settings->get_str(lib->settings, "imc-test.command", "none"); + attr = ita_attr_command_create(command); + attr->set_noskip_flag(attr, TRUE); + msg = pa_tnc_msg_create(); + msg->add_attribute(msg, attr); + msg->build(msg); + result = imc_test->send_message(imc_test, connection_id, + msg->get_encoding(msg)); + msg->destroy(msg); + + return result; +} + +/** + * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2 + */ +TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + TNC_Result result; + + if (!imc_test) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return send_message(connection_id); +} + +/** + * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2 + */ +TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + pa_tnc_msg_t *pa_tnc_msg; + status_t status; + TNC_Result result; + + if (!imc_test) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + + /* process received message */ + DBG2(DBG_IMC, "IMC %u \"%s\" received message type 0x%08x for Connection ID %u", + imc_id, imc_name, msg_type, connection_id); + pa_tnc_msg = pa_tnc_msg_create_from_data(chunk_create(msg, msg_len)); + status = pa_tnc_msg->process(pa_tnc_msg); + pa_tnc_msg->destroy(pa_tnc_msg); + if (status != SUCCESS) + { + return TNC_RESULT_FATAL; + } + + /* always return the same response */ + return send_message(connection_id); +} + +/** + * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2 + */ +TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + if (!imc_test) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2 + */ +TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) +{ + if (!imc_test) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + imc_test->destroy(imc_test); + imc_test = NULL; + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2 + */ +TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, + TNC_TNCC_BindFunctionPointer bind_function) +{ + if (!imc_test) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imc_test->bind_functions(imc_test, bind_function); +} diff --git a/src/libcharon/plugins/imc_test/imc_test_state.c b/src/libcharon/plugins/imc_test/imc_test_state.c new file mode 100644 index 000000000..1b60f3260 --- /dev/null +++ b/src/libcharon/plugins/imc_test/imc_test_state.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "imc_test_state.h" + +#include <debug.h> + +typedef struct private_imc_test_state_t private_imc_test_state_t; + +/** + * Private data of an imc_test_state_t object. + */ +struct private_imc_test_state_t { + + /** + * Public members of imc_test_state_t + */ + imc_test_state_t public; + + /** + * TNCCS connection ID + */ + TNC_ConnectionID connection_id; + + /** + * TNCCS connection state + */ + TNC_ConnectionState state; + +}; + +METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, + private_imc_test_state_t *this) +{ + return this->connection_id; +} + +METHOD(imc_state_t, change_state, void, + private_imc_test_state_t *this, TNC_ConnectionState new_state) +{ + this->state = new_state; +} + +METHOD(imc_state_t, destroy, void, + private_imc_test_state_t *this) +{ + free(this); +} + +/** + * Described in header. + */ +imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id) +{ + private_imc_test_state_t *this; + + INIT(this, + .public = { + .interface = { + .get_connection_id = _get_connection_id, + .change_state = _change_state, + .destroy = _destroy, + }, + }, + .state = TNC_CONNECTION_STATE_CREATE, + .connection_id = connection_id, + ); + + return &this->public.interface; +} + + diff --git a/src/libcharon/plugins/imc_test/imc_test_state.h b/src/libcharon/plugins/imc_test/imc_test_state.h new file mode 100644 index 000000000..6d2dc5e7a --- /dev/null +++ b/src/libcharon/plugins/imc_test/imc_test_state.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 imc_test_state_t imc_test_state + * @{ @ingroup imc_test_state + */ + +#ifndef IMC_TEST_STATE_H_ +#define IMC_TEST_STATE_H_ + +#include <imc/imc_state.h> +#include <library.h> + +typedef struct imc_test_state_t imc_test_state_t; + +/** + * Internal state of an imc_test_t connection instance + */ +struct imc_test_state_t { + + /** + * imc_state_t interface + */ + imc_state_t interface; +}; + +/** + * Create an imc_test_state_t instance + * + * @param id connection ID + * @param rounds total number of IMC re-measurements + */ +imc_state_t* imc_test_state_create(TNC_ConnectionID id); + +#endif /** IMC_TEST_STATE_H_ @}*/ diff --git a/src/libcharon/plugins/imv_test/Makefile.am b/src/libcharon/plugins/imv_test/Makefile.am new file mode 100644 index 000000000..59a6cc806 --- /dev/null +++ b/src/libcharon/plugins/imv_test/Makefile.am @@ -0,0 +1,15 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon -I$(top_srcdir)/src/libimcv + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-imv-test.la + +libstrongswan_imv_test_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la + +libstrongswan_imv_test_la_SOURCES = imv_test.c \ + imv_test_state.h imv_test_state.c + +libstrongswan_imv_test_la_LDFLAGS = -module -avoid-version + diff --git a/src/libcharon/plugins/imv_test/imv_test.c b/src/libcharon/plugins/imv_test/imv_test.c new file mode 100644 index 000000000..92605d136 --- /dev/null +++ b/src/libcharon/plugins/imv_test/imv_test.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "imv_test_state.h" + +#include <imv/imv_agent.h> +#include <pa_tnc/pa_tnc_msg.h> +#include <ita/ita_attr_command.h> +#include <tnc/pen/pen.h> +#include <debug.h> + +/* IMV definitions */ + +static const char imv_name[] = "Test"; + +#define IMV_VENDOR_ID PEN_ITA +#define IMV_SUBTYPE 0x01 + +static imv_agent_t *imv_test; + +/** + * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2 + */ +TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, + TNC_Version min_version, + TNC_Version max_version, + TNC_Version *actual_version) +{ + if (imv_test) + { + DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); + return TNC_RESULT_ALREADY_INITIALIZED; + } + if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1) + { + DBG1(DBG_IMV, "no common IF-IMV version"); + return TNC_RESULT_NO_COMMON_VERSION; + } + imv_test = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE, + imv_id, actual_version); + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2 + */ +TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imv_state_t *state; + int rounds; + + if (!imv_test) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + rounds = lib->settings->get_int(lib->settings, "imv-test.rounds", 0); + state = imv_test_state_create(connection_id, rounds); + return imv_test->create_state(imv_test, state); + case TNC_CONNECTION_STATE_DELETE: + return imv_test->delete_state(imv_test, connection_id); + default: + return imv_test->change_state(imv_test, connection_id, new_state); + } +} + +static TNC_Result send_message(TNC_ConnectionID connection_id) +{ + pa_tnc_msg_t *msg; + pa_tnc_attr_t *attr; + TNC_Result result; + + attr = ita_attr_command_create("repeat"); + msg = pa_tnc_msg_create(); + msg->add_attribute(msg, attr); + msg->build(msg); + result = imv_test->send_message(imv_test, connection_id, + msg->get_encoding(msg)); + msg->destroy(msg); + + return result; +} + +/** + * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2 + */ +TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + pa_tnc_msg_t *pa_tnc_msg; + pa_tnc_attr_t *attr; + imv_state_t *state; + imv_test_state_t *imv_test_state; + TNC_Result result = TNC_RESULT_SUCCESS; + enumerator_t *enumerator; + + if (!imv_test) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + + /* process received message */ + DBG2(DBG_IMV, "IMV %u \"%s\" received message type 0x%08x for Connection ID %u", + imv_id, imv_name, msg_type, connection_id); + pa_tnc_msg = pa_tnc_msg_create_from_data(chunk_create(msg, msg_len)); + + if (pa_tnc_msg->process(pa_tnc_msg) != SUCCESS) + { + pa_tnc_msg->destroy(pa_tnc_msg); + return TNC_RESULT_FATAL; + } + + /* get current IMV state */ + if (!imv_test->get_state(imv_test, connection_id, &state)) + { + pa_tnc_msg->destroy(pa_tnc_msg); + return TNC_RESULT_FATAL; + } + + enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->get_vendor_id(attr) == PEN_ITA && + attr->get_type(attr) == ITA_ATTR_COMMAND) + { + ita_attr_command_t *ita_attr; + char *command; + + ita_attr = (ita_attr_command_t*)attr; + command = ita_attr->get_command(ita_attr); + + if (streq(command, "allow")) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_COMPLIANT); + } + else if (streq(command, "isolate")) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, + TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR); + } + else if (streq(command, "none")) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, + TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); + } + else + { + result = TNC_RESULT_FATAL; + } + break; + } + } + enumerator->destroy(enumerator); + pa_tnc_msg->destroy(pa_tnc_msg); + + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + + /* repeat the measurement ? */ + imv_test_state = (imv_test_state_t*)state; + if (imv_test_state->another_round(imv_test_state)) + { + return send_message(connection_id); + } + + return imv_test->provide_recommendation(imv_test, connection_id); +} + +/** + * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2 + */ +TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, + TNC_ConnectionID connection_id) +{ + if (!imv_test) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_test->provide_recommendation(imv_test, connection_id); +} + +/** + * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2 + */ +TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, + TNC_ConnectionID connection_id) +{ + if (!imv_test) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2 + */ +TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) +{ + if (!imv_test) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + imv_test->destroy(imv_test); + imv_test = NULL; + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2 + */ +TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, + TNC_TNCS_BindFunctionPointer bind_function) +{ + if (!imv_test) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_test->bind_functions(imv_test, bind_function); +} diff --git a/src/libcharon/plugins/imv_test/imv_test_state.c b/src/libcharon/plugins/imv_test/imv_test_state.c new file mode 100644 index 000000000..fe1d6d38d --- /dev/null +++ b/src/libcharon/plugins/imv_test/imv_test_state.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "imv_test_state.h" + +#include <debug.h> + +typedef struct private_imv_test_state_t private_imv_test_state_t; + +/** + * Private data of an imv_test_state_t object. + */ +struct private_imv_test_state_t { + + /** + * Public members of imv_test_state_t + */ + imv_test_state_t public; + + /** + * TNCCS connection ID + */ + TNC_ConnectionID connection_id; + + /** + * TNCCS connection state + */ + TNC_ConnectionState state; + + /** + * IMV action recommendation + */ + TNC_IMV_Action_Recommendation rec; + + /** + * IMV evaluation result + */ + TNC_IMV_Evaluation_Result eval; + + /** + * IMC-IMV round-trip count + */ + int rounds; + +}; + +METHOD(imv_state_t, get_connection_id, TNC_ConnectionID, + private_imv_test_state_t *this) +{ + return this->connection_id; +} + +METHOD(imv_state_t, change_state, void, + private_imv_test_state_t *this, TNC_ConnectionState new_state) +{ + this->state = new_state; +} + +METHOD(imv_state_t, get_recommendation, void, + private_imv_test_state_t *this, TNC_IMV_Action_Recommendation *rec, + TNC_IMV_Evaluation_Result *eval) +{ + *rec = this->rec; + *eval = this->eval; +} + +METHOD(imv_state_t, set_recommendation, void, + private_imv_test_state_t *this, TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval) +{ + this->rec = rec; + this->eval = eval; +} + +METHOD(imv_state_t, destroy, void, + private_imv_test_state_t *this) +{ + free(this); +} + +METHOD(imv_state_t, another_round, bool, + private_imv_test_state_t *this) +{ + return (this->rounds-- > 0); +} + +/** + * Described in header. + */ +imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id, int rounds) +{ + private_imv_test_state_t *this; + + INIT(this, + .public = { + .interface = { + .get_connection_id = _get_connection_id, + .change_state = _change_state, + .get_recommendation = _get_recommendation, + .set_recommendation = _set_recommendation, + .destroy = _destroy, + }, + .another_round = _another_round, + }, + .state = TNC_CONNECTION_STATE_CREATE, + .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, + .connection_id = connection_id, + .rounds = rounds, + ); + + return &this->public.interface; +} + + diff --git a/src/libcharon/plugins/imv_test/imv_test_state.h b/src/libcharon/plugins/imv_test/imv_test_state.h new file mode 100644 index 000000000..164aca9b1 --- /dev/null +++ b/src/libcharon/plugins/imv_test/imv_test_state.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 imv_test_state_t imv_test_state + * @{ @ingroup imv_test_state + */ + +#ifndef IMV_TEST_STATE_H_ +#define IMV_TEST_STATE_H_ + +#include <imv/imv_state.h> +#include <library.h> + +typedef struct imv_test_state_t imv_test_state_t; + +/** + * Internal state of an imv_test_t connection instance + */ +struct imv_test_state_t { + + /** + * imv_state_t interface + */ + imv_state_t interface; + + /** + * Check and decrease IMC-IMV round-trip count + * + * @return new connection state + */ + bool (*another_round)(imv_test_state_t *this); + +}; + +/** + * Create an imv_test_state_t instance + * + * @param id connection ID + * @param rounds total number of IMC re-measurements + */ +imv_state_t* imv_test_state_create(TNC_ConnectionID id, int rounds); + +#endif /** IMV_TEST_STATE_H_ @}*/ diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am new file mode 100644 index 000000000..9a0f6be88 --- /dev/null +++ b/src/libimcv/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libcharon \ + -I$(top_srcdir)/src/libtls + +noinst_LTLIBRARIES = libimcv.la + +libimcv_la_LIBADD = $(top_builddir)/src/libtls/libtls.la + +libimcv_la_SOURCES = \ + imc/imc_agent.h imc/imc_agent.c imc/imc_state.h \ + imv/imv_agent.h imv/imv_agent.c imv/imv_state.h \ + ietf/ietf_attr.h \ + ietf/ietf_attr_pa_tnc_error.h ietf/ietf_attr_pa_tnc_error.c \ + ita/ita_attr_command.h ita/ita_attr_command.c \ + pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \ + pa_tnc/pa_tnc_attr.h pa_tnc/pa_tnc_attr.c diff --git a/src/libimcv/ietf/ietf_attr.h b/src/libimcv/ietf/ietf_attr.h new file mode 100644 index 000000000..35e006e90 --- /dev/null +++ b/src/libimcv/ietf/ietf_attr.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * 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 ietf_attrt ietf_attr + * @{ @ingroup ietf_attr + */ + +#ifndef IETF_ATTR_H_ +#define IETF_ATTR_H_ + +typedef enum ietf_attr_t ietf_attr_t; + +/** + * IETF standard PA-TNC attribute types defined by RFC 5792 + */ +enum ietf_attr_t { + IETF_ATTR_TESTING = 0, + IETF_ATTR_ATTRIBUTE_REQUEST = 1, + IETF_ATTR_PRODUCT_INFORMATION = 2, + IETF_ATTR_NUMERIC_VERSION = 3, + IETF_ATTR_STRING_VERSION = 4, + IETF_ATTR_OPERATIONAL_STATUS = 5, + IETF_ATTR_PORT_FILTER = 6, + IETF_ATTR_INSTALLED_PACKAGES = 7, + IETF_ATTR_PA_TNC_ERROR = 8, + IETF_ATTR_ASSESSMENT_RESULT = 9, + IETF_ATTR_REMEDIATION_INSTRUCTIONS = 10, + IETF_ATTR_FORWARDING_ENABLED = 11, + IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED = 12, + IETF_ATTR_RESERVED = 0xffffffff, +}; + +#endif /** IETF_ATTR_H_ @}*/ diff --git a/src/libimcv/ietf/ietf_attr_pa_tnc_error.c b/src/libimcv/ietf/ietf_attr_pa_tnc_error.c new file mode 100644 index 000000000..ccd097a2c --- /dev/null +++ b/src/libimcv/ietf/ietf_attr_pa_tnc_error.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "ietf_attr_pa_tnc_error.h" + +#include <debug.h> + +ENUM(pa_tnc_error_code_names, PA_ERROR_RESERVED, + PA_ERROR_ATTR_TYPE_NOT_SUPPORTED, + "Reserved", + "Invalid Parameter", + "Version Not Supported", + "Attribute Type Not Supported" +); + +/** + * PA-TNC Error Attribute Type (see section 4.2.8 of RFC 5792) + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | PA-TNC Error Code Vendor ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PA-TNC Error Code | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Error Information (Variable Length) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +typedef struct private_ietf_attr_pa_tnc_error_t private_ietf_attr_pa_tnc_error_t; + +/** + * Private data of an ietf_attr_pa_tnc_error_t object. + */ +struct private_ietf_attr_pa_tnc_error_t { + + /** + * Public members of ietf_attr_pa_tnc_error_t + */ + ietf_attr_pa_tnc_error_t public; + + /** + * Attribute vendor ID + */ + pen_t vendor_id; + + /** + * Attribute type + */ + u_int32_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Error code vendor ID + */ + pen_t error_vendor_id; + + /** + * Error code + */ + u_int32_t error_code; + +}; + +METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, + private_ietf_attr_pa_tnc_error_t *this) +{ + return this->vendor_id; +} + +METHOD(pa_tnc_attr_t, get_type, u_int32_t, + private_ietf_attr_pa_tnc_error_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_ietf_attr_pa_tnc_error_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_ietf_attr_pa_tnc_error_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_ietf_attr_pa_tnc_error_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_ietf_attr_pa_tnc_error_t *this) +{ + +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_ietf_attr_pa_tnc_error_t *this) +{ + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_ietf_attr_pa_tnc_error_t *this) +{ + free(this); +} + +METHOD(ietf_attr_pa_tnc_error_t, get_error_vendor_id, pen_t, + private_ietf_attr_pa_tnc_error_t *this) +{ + return this->error_vendor_id; +} + +METHOD(ietf_attr_pa_tnc_error_t, get_error_code, u_int32_t, + private_ietf_attr_pa_tnc_error_t *this) +{ + return this->error_code; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id, + u_int32_t error_code) +{ + private_ietf_attr_pa_tnc_error_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .destroy = _destroy, + }, + .get_vendor_id = _get_error_vendor_id, + .get_error_code = _get_error_code, + }, + .vendor_id = PEN_IETF, + .type = IETF_ATTR_PA_TNC_ERROR, + .error_vendor_id = vendor_id, + .error_code = error_code, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_from_data(chunk_t data) +{ + private_ietf_attr_pa_tnc_error_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .build = _build, + .process = _process, + .destroy = _destroy, + }, + .get_vendor_id = _get_error_vendor_id, + .get_error_code = _get_error_code, + }, + .vendor_id = PEN_IETF, + .type = IETF_ATTR_PA_TNC_ERROR, + .value = chunk_clone(data), + ); + + return &this->public.pa_tnc_attribute; +} + + diff --git a/src/libimcv/ietf/ietf_attr_pa_tnc_error.h b/src/libimcv/ietf/ietf_attr_pa_tnc_error.h new file mode 100644 index 000000000..7d09a8e1a --- /dev/null +++ b/src/libimcv/ietf/ietf_attr_pa_tnc_error.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * 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 ietf_attr_pa_tnc_errort ietf_attr_pa_tnc_error + * @{ @ingroup ietf_attr_pa_tnc_error + */ + +#ifndef IETF_ATTR_PA_TNC_ERROR_H_ +#define IETF_ATTR_PA_TNC_ERROR_H_ + +typedef struct ietf_attr_pa_tnc_error_t ietf_attr_pa_tnc_error_t; + +#include "ietf_attr.h" +#include "pa_tnc/pa_tnc_attr.h" + + +/** + * IETF Standard PA-TNC Error Codes as defined in section 4.2.8 of RFC 5792 + */ +enum pa_tnc_error_code_t { + PA_ERROR_RESERVED = 0, + PA_ERROR_INVALID_PARAMETER = 1, + PA_ERROR_VERSION_NOT_SUPPORTED = 2, + PA_ERROR_ATTR_TYPE_NOT_SUPPORTED = 3, +}; + +/** + * enum name for pa_tnc_error_code_t. + */ +extern enum_name_t *pa_tnc_error_code_names; + +/** + * Class implementing the IETF PA-TNC Error attribute. + * + */ +struct ietf_attr_pa_tnc_error_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get PA-TNC error code vendor ID + * + * @return error code vendor ID + */ + pen_t (*get_vendor_id)(ietf_attr_pa_tnc_error_t *this); + + /** + * Get PA-TNC error code + * + * @return error code + */ + pen_t (*get_error_code)(ietf_attr_pa_tnc_error_t *this); +}; + +/** + * Creates an ietf_attr_pa_tnc_error_t object from an error code + * + * @param vendor_id PA-TNC error code vendor ID + * @param error_code PA-TNC error code + * + */ +pa_tnc_attr_t* ietf_attr_pa_tnc_error_create(pen_t vendor_id, + u_int32_t error_code); + +/** + * Creates an ietf_attr_pa_tnc_error_t object from received data + * + * @param value unparsed attribute value + */ +pa_tnc_attr_t* ietf_attr_pa_tnc_error_create_from_data(chunk_t value); + +#endif /** IETF_ATTR_PA_TNC_ERROR_H_ @}*/ diff --git a/src/libimcv/imc/imc_agent.c b/src/libimcv/imc/imc_agent.c new file mode 100644 index 000000000..8edd59ac3 --- /dev/null +++ b/src/libimcv/imc/imc_agent.c @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "imc_agent.h" + +#include <debug.h> +#include <utils/linked_list.h> +#include <threading/rwlock.h> + +typedef struct private_imc_agent_t private_imc_agent_t; + +/** + * Private data of an imc_agent_t object. + */ +struct private_imc_agent_t { + + /** + * Public members of imc_agent_t + */ + imc_agent_t public; + + /** + * name of IMC + */ + const char *name; + + /** + * message type of IMC + */ + TNC_MessageType type; + + /** + * ID of IMC as assigned by TNCC + */ + TNC_IMCID id; + + /** + * list of TNCC connection entries + */ + linked_list_t *connections; + + /** + * rwlock to lock TNCS connection entries + */ + rwlock_t *connection_lock; + + /** + * Inform a TNCS about the set of message types the IMC is able to receive + * + * @param imc_id IMC ID assigned by TNCC + * @param supported_types list of supported message types + * @param type_count number of list elements + * @return TNC result code + */ + TNC_Result (*report_message_types)(TNC_IMCID imc_id, + TNC_MessageTypeList supported_types, + TNC_UInt32 type_count); + + /** + * Call when an IMC-IMC message is to be sent + * + * @param imc_id IMC ID assigned by TNCC + * @param connection_id network connection ID assigned by TNCC + * @param msg message to send + * @param msg_len message length in bytes + * @param msg_type message type + * @return TNC result code + */ + TNC_Result (*send_message)(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type); +}; + +METHOD(imc_agent_t, bind_functions, TNC_Result, + private_imc_agent_t *this, TNC_TNCC_BindFunctionPointer bind_function) +{ + if (!bind_function) + { + DBG1(DBG_IMC, "TNC client failed to provide bind function"); + return TNC_RESULT_INVALID_PARAMETER; + } + if (bind_function(this->id, "TNC_TNCC_ReportMessageTypes", + (void**)&this->report_message_types) != TNC_RESULT_SUCCESS) + { + this->report_message_types = NULL; + } + if (bind_function(this->id, "TNC_TNCC_RequestHandshakeRetry", + (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS) + { + this->public.request_handshake_retry = NULL; + } + if (bind_function(this->id, "TNC_TNCC_SendMessage", + (void**)&this->send_message) != TNC_RESULT_SUCCESS) + { + this->send_message = NULL; + } + DBG2(DBG_IMC, "IMC %u \"%s\" provided with bind function", + this->id, this->name); + + if (this->report_message_types) + { + this->report_message_types(this->id, &this->type, 1); + } + return TNC_RESULT_SUCCESS; +} + +/** + * finds a connection state based on its Connection ID + */ +static imc_state_t* find_connection(private_imc_agent_t *this, + TNC_ConnectionID id) +{ + enumerator_t *enumerator; + imc_state_t *state, *found = NULL; + + this->connection_lock->read_lock(this->connection_lock); + enumerator = this->connections->create_enumerator(this->connections); + while (enumerator->enumerate(enumerator, &state)) + { + if (id == state->get_connection_id(state)) + { + found = state; + break; + } + } + enumerator->destroy(enumerator); + this->connection_lock->unlock(this->connection_lock); + + return found; +} + +/** + * delete a connection state with a given Connection ID + */ +static bool delete_connection(private_imc_agent_t *this, TNC_ConnectionID id) +{ + enumerator_t *enumerator; + imc_state_t *state; + bool found = FALSE; + + this->connection_lock->write_lock(this->connection_lock); + enumerator = this->connections->create_enumerator(this->connections); + while (enumerator->enumerate(enumerator, &state)) + { + if (id == state->get_connection_id(state)) + { + found = TRUE; + state->destroy(state); + this->connections->remove_at(this->connections, enumerator); + break; + } + } + enumerator->destroy(enumerator); + this->connection_lock->unlock(this->connection_lock); + + return found; +} + +METHOD(imc_agent_t, create_state, TNC_Result, + private_imc_agent_t *this, imc_state_t *state) +{ + TNC_ConnectionID connection_id; + + connection_id = state->get_connection_id(state); + if (find_connection(this, connection_id)) + { + DBG1(DBG_IMC, "IMC %u \"%s\" already created a state for Connection ID %u", + this->id, this->name, connection_id); + state->destroy(state); + return TNC_RESULT_OTHER; + } + this->connection_lock->write_lock(this->connection_lock); + this->connections->insert_last(this->connections, state); + this->connection_lock->unlock(this->connection_lock); + DBG2(DBG_IMC, "IMC %u \"%s\" created a state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_SUCCESS; +} + +METHOD(imc_agent_t, delete_state, TNC_Result, + private_imc_agent_t *this, TNC_ConnectionID connection_id) +{ + if (!delete_connection(this, connection_id)) + { + DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_FATAL; + } + DBG2(DBG_IMC, "IMC %u \"%s\" deleted the state of Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_SUCCESS; +} + +METHOD(imc_agent_t, change_state, TNC_Result, + private_imc_agent_t *this, TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imc_state_t *state; + + switch (new_state) + { + case TNC_CONNECTION_STATE_HANDSHAKE: + case TNC_CONNECTION_STATE_ACCESS_ALLOWED: + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + case TNC_CONNECTION_STATE_ACCESS_NONE: + state = find_connection(this, connection_id); + if (!state) + { + DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_FATAL; + } + state->change_state(state, new_state); + DBG2(DBG_IMC, "IMC %u \"%s\" changed state of Connection ID %u to '%N'", + this->id, this->name, connection_id, + TNC_Connection_State_names, new_state); + break; + case TNC_CONNECTION_STATE_CREATE: + DBG1(DBG_IMC, "state '%N' should be handled by create_state()", + TNC_Connection_State_names, new_state); + return TNC_RESULT_FATAL; + case TNC_CONNECTION_STATE_DELETE: + DBG1(DBG_IMC, "state '%N' should be handled by delete_state()", + TNC_Connection_State_names, new_state); + return TNC_RESULT_FATAL; + default: + DBG1(DBG_IMC, "IMC %u \"%s\" was notified of unknown state %u " + "for Connection ID %u", + this->id, this->name, new_state, connection_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return TNC_RESULT_SUCCESS; +} + +METHOD(imc_agent_t, get_state, bool, + private_imc_agent_t *this, TNC_ConnectionID connection_id, + imc_state_t **state) +{ + *state = find_connection(this, connection_id); + if (!*state) + { + DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return FALSE; + } + return TRUE; +} + +METHOD(imc_agent_t, send_message, TNC_Result, + private_imc_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg) +{ + if (!this->send_message) + { + return TNC_RESULT_FATAL; + } + return this->send_message(this->id, connection_id, msg.ptr, msg.len, + this->type); +} + +METHOD(imc_agent_t, destroy, void, + private_imc_agent_t *this) +{ + DBG1(DBG_IMC, "IMC %u \"%s\" terminated", this->id, this->name); + this->connections->destroy_function(this->connections, free); + this->connection_lock->destroy(this->connection_lock); + free(this); +} + +/** + * Described in header. + */ +imc_agent_t *imc_agent_create(const char *name, + pen_t vendor_id, u_int32_t subtype, + TNC_IMCID id, TNC_Version *actual_version) +{ + private_imc_agent_t *this; + + INIT(this, + .public = { + .bind_functions = _bind_functions, + .create_state = _create_state, + .delete_state = _delete_state, + .change_state = _change_state, + .get_state = _get_state, + .send_message = _send_message, + .destroy = _destroy, + }, + .name = name, + .type = (vendor_id << 8) | (subtype && 0xff), + .id = id, + .connections = linked_list_create(), + .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + *actual_version = TNC_IFIMC_VERSION_1; + DBG1(DBG_IMC, "IMC %u \"%s\" initialized", this->id, this->name); + + return &this->public; +} + diff --git a/src/libimcv/imc/imc_agent.h b/src/libimcv/imc/imc_agent.h new file mode 100644 index 000000000..1112fb37f --- /dev/null +++ b/src/libimcv/imc/imc_agent.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 imc_agent_t imc_agent + * @{ @ingroup imc_agent + */ + +#ifndef IMC_AGENT_H_ +#define IMC_AGENT_H_ + +#include "imc_state.h" + +#include <tnc/tncifimc.h> +#include <tnc/pen/pen.h> +#include <library.h> + +typedef struct imc_agent_t imc_agent_t; + +/** + * Core functions of an Integrity Measurement Verifier (IMC) + */ +struct imc_agent_t { + + /** + * Ask a TNCC to retry an Integrity Check Handshake + * + * @param imc_id IMC ID assigned by TNCC + * @param connection_id network connection ID assigned by TNCC + * @param reason IMC retry reason + * @return TNC result code + */ + TNC_Result (*request_handshake_retry)(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_RetryReason reason); + + /** + * Bind TNCC functions + * + * @param bind_function function offered by the TNCC + * @return TNC result code + */ + TNC_Result (*bind_functions)(imc_agent_t *this, + TNC_TNCC_BindFunctionPointer bind_function); + + /** + * Create the IMC state for a TNCCS connection instance + * + * @param state internal IMC state instance + * @return TNC result code + */ + TNC_Result (*create_state)(imc_agent_t *this, imc_state_t *state); + + /** + * Delete the IMC state for a TNCCS connection instance + * + * @param connection_id network connection ID assigned by TNCS + * @return TNC result code + */ + TNC_Result (*delete_state)(imc_agent_t *this, + TNC_ConnectionID connection_id); + + /** + * Change the current state of a TNCCS connection + * + * @param connection_id network connection ID assigned by TNCS + * @param new_state new state of TNCCS connection + * @return TNC result code + */ + TNC_Result (*change_state)(imc_agent_t *this, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state); + + /** + * Get the IMC state for a TNCCS connection instance + * + * @param connection_id network connection ID assigned by TNCS + * @param state internal IMC state instance + * @return TRUE if the state was found + */ + bool (*get_state)(imc_agent_t *this, + TNC_ConnectionID connection_id, imc_state_t **state); + + /** + * Call when an IMC-IMV message is to be sent + * + * @param connection_id network connection ID assigned by TNCC + * @param msg message to send + * @return TNC result code + */ + TNC_Result (*send_message)(imc_agent_t *this, + TNC_ConnectionID connection_id, + chunk_t msg); + + /** + * Destroys an imc_agent_t object + */ + void (*destroy)(imc_agent_t *this); +}; + +/** + * Create an imc_agent_t object + * + * @param name name of the IMC + * @param vendor_id vendor ID of the IMC + * @param subtype message subtype of the IMC + * @param id ID of the IMC as assigned by the TNCS + * @param actual_version actual version of the IF-IMC API + * + */ +imc_agent_t *imc_agent_create(const char *name, + pen_t vendor_id, u_int32_t subtype, + TNC_IMCID id, TNC_Version *actual_version); + +#endif /** IMC_AGENT_H_ @}*/ diff --git a/src/libimcv/imc/imc_state.h b/src/libimcv/imc/imc_state.h new file mode 100644 index 000000000..9d46a57b2 --- /dev/null +++ b/src/libimcv/imc/imc_state.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 imc_state_t imc_state + * @{ @ingroup imc_state + */ + +#ifndef IMC_STATE_H_ +#define IMC_STATE_H_ + +#include <tnc/tncif.h> +#include <library.h> + +typedef struct imc_state_t imc_state_t; + +/** + * Internal state of an IMC connection instance + */ +struct imc_state_t { + + /** + * Get the TNCS connection ID attached to the state + * + * @return TNCS connection ID of the state + */ + TNC_ConnectionID (*get_connection_id)(imc_state_t *this); + + /** + * Change the connection state + * + * @param new_state new connection state + */ + void (*change_state)(imc_state_t *this, TNC_ConnectionState new_state); + + /** + * Destroys an imc_state_t object + */ + void (*destroy)(imc_state_t *this); +}; + +#endif /** IMC_STATE_H_ @}*/ diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c new file mode 100644 index 000000000..70a7e9fc9 --- /dev/null +++ b/src/libimcv/imv/imv_agent.c @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "imv_agent.h" +#include "imv_state.h" + +#include <debug.h> +#include <utils/linked_list.h> +#include <threading/rwlock.h> + +typedef struct private_imv_agent_t private_imv_agent_t; + +/** + * Private data of an imv_agent_t object. + */ +struct private_imv_agent_t { + + /** + * Public members of imv_agent_t + */ + imv_agent_t public; + + /** + * name of IMV + */ + const char *name; + + /** + * message type of IMV + */ + TNC_MessageType type; + + /** + * ID of IMV as assigned by TNCS + */ + TNC_IMVID id; + + /** + * list of TNCS connection entries + */ + linked_list_t *connections; + + /** + * rwlock to lock TNCS connection entries + */ + rwlock_t *connection_lock; + + /** + * Inform a TNCS about the set of message types the IMV is able to receive + * + * @param imv_id IMV ID assigned by TNCS + * @param supported_types list of supported message types + * @param type_count number of list elements + * @return TNC result code + */ + TNC_Result (*report_message_types)(TNC_IMVID imv_id, + TNC_MessageTypeList supported_types, + TNC_UInt32 type_count); + + /** + * Call when an IMV-IMC message is to be sent + * + * @param imv_id IMV ID assigned by TNCS + * @param connection_id network connection ID assigned by TNCS + * @param msg message to send + * @param msg_len message length in bytes + * @param msg_type message type + * @return TNC result code + */ + TNC_Result (*send_message)(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type); + + /** + * Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS + * + * @param imv_id IMV ID assigned by TNCS + # @param connection_id network connection ID assigned by TNCS + * @param rec IMV action recommendation + * @param eval IMV evaluation result + * @return TNC result code + */ + TNC_Result (*provide_recommendation)(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval); + +}; + +METHOD(imv_agent_t, bind_functions, TNC_Result, + private_imv_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function) +{ + if (!bind_function) + { + DBG1(DBG_IMV, "TNC server failed to provide bind function"); + return TNC_RESULT_INVALID_PARAMETER; + } + if (bind_function(this->id, "TNC_TNCS_ReportMessageTypes", + (void**)&this->report_message_types) != TNC_RESULT_SUCCESS) + { + this->report_message_types = NULL; + } + if (bind_function(this->id, "TNC_TNCS_RequestHandshakeRetry", + (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS) + { + this->public.request_handshake_retry = NULL; + } + if (bind_function(this->id, "TNC_TNCS_SendMessage", + (void**)&this->send_message) != TNC_RESULT_SUCCESS) + { + this->send_message = NULL; + } + if (bind_function(this->id, "TNC_TNCS_ProvideRecommendation", + (void**)&this->provide_recommendation) != TNC_RESULT_SUCCESS) + { + this->provide_recommendation = NULL; + } + if (bind_function(this->id, "TNC_TNCS_GetAttribute", + (void**)&this->public.get_attribute) != TNC_RESULT_SUCCESS) + { + this->public.get_attribute = NULL; + } + if (bind_function(this->id, "TNC_TNCS_SetAttribute", + (void**)&this->public.set_attribute) != TNC_RESULT_SUCCESS) + { + this->public.set_attribute = NULL; + } + DBG2(DBG_IMV, "IMV %u \"%s\" provided with bind function", + this->id, this->name); + + if (this->report_message_types) + { + this->report_message_types(this->id, &this->type, 1); + } + return TNC_RESULT_SUCCESS; +} + +/** + * finds a connection state based on its Connection ID + */ +static imv_state_t* find_connection(private_imv_agent_t *this, + TNC_ConnectionID id) +{ + enumerator_t *enumerator; + imv_state_t *state, *found = NULL; + + this->connection_lock->read_lock(this->connection_lock); + enumerator = this->connections->create_enumerator(this->connections); + while (enumerator->enumerate(enumerator, &state)) + { + if (id == state->get_connection_id(state)) + { + found = state; + break; + } + } + enumerator->destroy(enumerator); + this->connection_lock->unlock(this->connection_lock); + + return found; +} + +/** + * delete a connection state with a given Connection ID + */ +static bool delete_connection(private_imv_agent_t *this, TNC_ConnectionID id) +{ + enumerator_t *enumerator; + imv_state_t *state; + bool found = FALSE; + + this->connection_lock->write_lock(this->connection_lock); + enumerator = this->connections->create_enumerator(this->connections); + while (enumerator->enumerate(enumerator, &state)) + { + if (id == state->get_connection_id(state)) + { + found = TRUE; + state->destroy(state); + this->connections->remove_at(this->connections, enumerator); + break; + } + } + enumerator->destroy(enumerator); + this->connection_lock->unlock(this->connection_lock); + + return found; +} + +METHOD(imv_agent_t, create_state, TNC_Result, + private_imv_agent_t *this, imv_state_t *state) +{ + TNC_ConnectionID connection_id; + + connection_id = state->get_connection_id(state); + if (find_connection(this, connection_id)) + { + DBG1(DBG_IMV, "IMV %u \"%s\" already created a state for Connection ID %u", + this->id, this->name, connection_id); + state->destroy(state); + return TNC_RESULT_OTHER; + } + this->connection_lock->write_lock(this->connection_lock); + this->connections->insert_last(this->connections, state); + this->connection_lock->unlock(this->connection_lock); + DBG2(DBG_IMV, "IMV %u \"%s\" created a state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_SUCCESS; +} + +METHOD(imv_agent_t, delete_state, TNC_Result, + private_imv_agent_t *this, TNC_ConnectionID connection_id) +{ + if (!delete_connection(this, connection_id)) + { + DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_FATAL; + } + DBG2(DBG_IMV, "IMV %u \"%s\" deleted the state of Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_SUCCESS; +} + +METHOD(imv_agent_t, change_state, TNC_Result, + private_imv_agent_t *this, TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imv_state_t *state; + + switch (new_state) + { + case TNC_CONNECTION_STATE_HANDSHAKE: + case TNC_CONNECTION_STATE_ACCESS_ALLOWED: + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + case TNC_CONNECTION_STATE_ACCESS_NONE: + state = find_connection(this, connection_id); + if (!state) + { + DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_FATAL; + } + state->change_state(state, new_state); + DBG2(DBG_IMV, "IMV %u \"%s\" changed state of Connection ID %u to '%N'", + this->id, this->name, connection_id, + TNC_Connection_State_names, new_state); + break; + case TNC_CONNECTION_STATE_CREATE: + DBG1(DBG_IMV, "state '%N' should be handled by create_state()", + TNC_Connection_State_names, new_state); + return TNC_RESULT_FATAL; + case TNC_CONNECTION_STATE_DELETE: + DBG1(DBG_IMV, "state '%N' should be handled by delete_state()", + TNC_Connection_State_names, new_state); + return TNC_RESULT_FATAL; + default: + DBG1(DBG_IMV, "IMV %u \"%s\" was notified of unknown state %u " + "for Connection ID %u", + this->id, this->name, new_state, connection_id); + return TNC_RESULT_INVALID_PARAMETER; + } + return TNC_RESULT_SUCCESS; +} + +METHOD(imv_agent_t, get_state, bool, + private_imv_agent_t *this, TNC_ConnectionID connection_id, + imv_state_t **state) +{ + *state = find_connection(this, connection_id); + if (!*state) + { + DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return FALSE; + } + return TRUE; +} + +METHOD(imv_agent_t, send_message, TNC_Result, + private_imv_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg) +{ + if (!this->send_message) + { + return TNC_RESULT_FATAL; + } + return this->send_message(this->id, connection_id, msg.ptr, msg.len, + this->type); +} + +METHOD(imv_agent_t, set_recommendation, TNC_Result, + private_imv_agent_t *this, TNC_ConnectionID connection_id, + TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval) +{ + imv_state_t *state; + + state = find_connection(this, connection_id); + if (!state) + { + DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_FATAL; + } + state->set_recommendation(state, rec, eval); + return this->provide_recommendation(this->id, connection_id, rec, eval); +} + +METHOD(imv_agent_t, provide_recommendation, TNC_Result, + private_imv_agent_t *this, TNC_ConnectionID connection_id) +{ + imv_state_t *state; + TNC_IMV_Action_Recommendation rec; + TNC_IMV_Evaluation_Result eval; + + state = find_connection(this, connection_id); + if (!state) + { + DBG1(DBG_IMV, "IMV %u \"%s\" has no state for Connection ID %u", + this->id, this->name, connection_id); + return TNC_RESULT_FATAL; + } + state->get_recommendation(state, &rec, &eval); + return this->provide_recommendation(this->id, connection_id, rec, eval); +} + +METHOD(imv_agent_t, destroy, void, + private_imv_agent_t *this) +{ + DBG1(DBG_IMC, "IMV %u \"%s\" terminated", this->id, this->name); + this->connections->destroy_offset(this->connections, + offsetof(imv_state_t, destroy)); + this->connection_lock->destroy(this->connection_lock); + free(this); +} + +/** + * Described in header. + */ +imv_agent_t *imv_agent_create(const char *name, + pen_t vendor_id, u_int32_t subtype, + TNC_IMVID id, TNC_Version *actual_version) +{ + private_imv_agent_t *this; + + INIT(this, + .public = { + .bind_functions = _bind_functions, + .create_state = _create_state, + .delete_state = _delete_state, + .change_state = _change_state, + .get_state = _get_state, + .send_message = _send_message, + .set_recommendation = _set_recommendation, + .provide_recommendation = _provide_recommendation, + .destroy = _destroy, + }, + .name = name, + .type = (vendor_id << 8) | (subtype && 0xff), + .id = id, + .connections = linked_list_create(), + .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + *actual_version = TNC_IFIMV_VERSION_1; + DBG1(DBG_IMV, "IMV %u \"%s\" initialized", this->id, this->name); + + return &this->public; +} + + diff --git a/src/libimcv/imv/imv_agent.h b/src/libimcv/imv/imv_agent.h new file mode 100644 index 000000000..04f113474 --- /dev/null +++ b/src/libimcv/imv/imv_agent.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 imv_agent_t imv_agent + * @{ @ingroup imv_agent + */ + +#ifndef IMV_AGENT_H_ +#define IMV_AGENT_H_ + +#include "imv_state.h" + +#include <tnc/tncifimv.h> +#include <tnc/pen/pen.h> +#include <library.h> + +typedef struct imv_agent_t imv_agent_t; + +/** + * Core functions of an Integrity Measurement Verifier (IMV) + */ +struct imv_agent_t { + + /** + * Ask a TNCS to retry an Integrity Check Handshake + * + * @param imv_id IMV ID assigned by TNCS + * @param connection_id network connection ID assigned by TNCS + * @param reason IMV retry reason + * @return TNC result code + */ + TNC_Result (*request_handshake_retry)(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_RetryReason reason); + + /** + * Get the value of an attribute associated with a connection + * or with the TNCS as a whole. + * + * @param imv_id IMV ID assigned by TNCS + * @param connection_id network connection ID assigned by TNCS + * @param attribute_id attribute ID + * @param buffer_len length of buffer in bytes + * @param buffer buffer + * @param out_value_len size in bytes of attribute stored in buffer + * @return TNC result code + */ + TNC_Result (*get_attribute)(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_AttributeID attribute_id, + TNC_UInt32 buffer_len, + TNC_BufferReference buffer, + TNC_UInt32 *out_value_len); + + /** + * Set the value of an attribute associated with a connection + * or with the TNCS as a whole. + * + * @param imv_id IMV ID assigned by TNCS + * @param connection_id network connection ID assigned by TNCS + * @param attribute_id attribute ID + * @param buffer_len length of buffer in bytes + * @param buffer buffer + * @return TNC result code + */ + TNC_Result (*set_attribute)(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_AttributeID attribute_id, + TNC_UInt32 buffer_len, + TNC_BufferReference buffer); + + /** + * Bind TNCS functions + * + * @param bind_function function offered by the TNCS + * @return TNC result code + */ + TNC_Result (*bind_functions)(imv_agent_t *this, + TNC_TNCS_BindFunctionPointer bind_function); + + /** + * Create the IMV state for a TNCCS connection instance + * + * @param state internal IMV state instance + * @return TNC result code + */ + TNC_Result (*create_state)(imv_agent_t *this, imv_state_t *state); + + /** + * Delete the IMV state for a TNCCS connection instance + * + * @param connection_id network connection ID assigned by TNCS + * @return TNC result code + */ + TNC_Result (*delete_state)(imv_agent_t *this, + TNC_ConnectionID connection_id); + + /** + * Change the current state of a TNCCS connection + * + * @param connection_id network connection ID assigned by TNCS + * @param new_state new state of TNCCS connection + * @return TNC result code + */ + TNC_Result (*change_state)(imv_agent_t *this, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state); + + /** + * Get the IMV state for a TNCCS connection instance + * + * @param connection_id network connection ID assigned by TNCS + * @param state internal IMV state instance + * @return TRUE if the state was found + */ + bool (*get_state)(imv_agent_t *this, + TNC_ConnectionID connection_id, imv_state_t **state); + + /** + * Call when an IMV-IMC message is to be sent + * + * @param connection_id network connection ID assigned by TNCS + * @param msg message to send + * @return TNC result code + */ + TNC_Result (*send_message)(imv_agent_t *this, + TNC_ConnectionID connection_id, chunk_t msg); + + /** + * Set Action Recommendation and Evaluation Result in the IMV state + * + # @param connection_id network connection ID assigned by TNCS + * @param rec IMV action recommendation + * @param eval IMV evaluation result + * @return TNC result code + */ + TNC_Result (*set_recommendation)(imv_agent_t *this, + TNC_ConnectionID connection_id, + TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval); + + /** + * Deliver IMV Action Recommendation and IMV Evaluation Result to the TNCS + * + # @param connection_id network connection ID assigned by TNCS + * @return TNC result code + */ + TNC_Result (*provide_recommendation)(imv_agent_t *this, + TNC_ConnectionID connection_id); + + /** + * Destroys an imv_agent_t object + */ + void (*destroy)(imv_agent_t *this); +}; + +/** + * Create an imv_agent_t object + * + * @param name name of the IMV + * @param vendor_id vendor ID of the IMV + * @param subtype message subtype of the IMV + * @param id ID of the IMV as assigned by the TNCS + * @param actual_version actual version of the IF-IMV API + * + */ +imv_agent_t *imv_agent_create(const char *name, + pen_t vendor_id, u_int32_t subtype, + TNC_IMVID id, TNC_Version *actual_version); + +#endif /** IMV_AGENT_H_ @}*/ diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h new file mode 100644 index 000000000..dcf7af6bb --- /dev/null +++ b/src/libimcv/imv/imv_state.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 imv_state_t imv_state + * @{ @ingroup imv_state + */ + +#ifndef IMV_STATE_H_ +#define IMV_STATE_H_ + +#include <tnc/tncifimv.h> +#include <library.h> + +typedef struct imv_state_t imv_state_t; + +/** + * Internal state of an IMV connection instance + */ +struct imv_state_t { + + /** + * Get the TNCS connection ID attached to the state + * + * @return TNCS connection ID of the state + */ + TNC_ConnectionID (*get_connection_id)(imv_state_t *this); + + /** + * Change the connection state + * + * @param new_state new connection state + */ + void (*change_state)(imv_state_t *this, TNC_ConnectionState new_state); + + /** + * Get IMV action recommendation and evaluation result + * + * @param rec IMV action recommendation + * @param eval IMV evaluation result + * + */ + void (*get_recommendation)(imv_state_t *this, + TNC_IMV_Action_Recommendation *rec, + TNC_IMV_Evaluation_Result *eval); + + /** + * Set IMV action recommendation and evaluation result + * + * @param rec IMV action recommendation + * @param eval IMV evaluation result + * + */ + void (*set_recommendation)(imv_state_t *this, + TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval); + + /** + * Destroys an imv_state_t object + */ + void (*destroy)(imv_state_t *this); +}; + +#endif /** IMV_STATE_H_ @}*/ diff --git a/src/libimcv/ita/ita_attr_command.c b/src/libimcv/ita/ita_attr_command.c new file mode 100644 index 000000000..33f97a1a9 --- /dev/null +++ b/src/libimcv/ita/ita_attr_command.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2011 Andreas Steffen, 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 "ita_attr_command.h" + +#include <tnc/pen/pen.h> +#include <debug.h> + +typedef struct private_ita_attr_command_t private_ita_attr_command_t; + +/** + * Private data of an ita_attr_command_t object. + */ +struct private_ita_attr_command_t { + + /** + * Public members of ita_attr_command_t + */ + ita_attr_command_t public; + + /** + * Attribute vendor ID + */ + pen_t vendor_id; + + /** + * Attribute type + */ + u_int32_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Command string + */ + char *command; +}; + +METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, + private_ita_attr_command_t *this) +{ + return this->vendor_id; +} + +METHOD(pa_tnc_attr_t, get_type, u_int32_t, + private_ita_attr_command_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_ita_attr_command_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_ita_attr_command_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_ita_attr_command_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_ita_attr_command_t *this) +{ + this->value = chunk_create(this->command, strlen(this->command)); + this->value = chunk_clone(this->value); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_ita_attr_command_t *this) +{ + this->command = malloc(this->value.len + 1); + memcpy(this->command, this->value.ptr, this->value.len); + this->command[this->value.len] = '\0'; + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_ita_attr_command_t *this) +{ + free(this->value.ptr); + free(this->command); + free(this); +} + +METHOD(ita_attr_command_t, get_command, char*, + private_ita_attr_command_t *this) +{ + return this->command; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ita_attr_command_create(char *command) +{ + private_ita_attr_command_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .destroy = _destroy, + }, + .get_command = _get_command, + }, + .vendor_id = PEN_ITA, + .type = ITA_ATTR_COMMAND, + .command = strdup(command), + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ita_attr_command_create_from_data(chunk_t data) +{ + private_ita_attr_command_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_vendor_id = _get_vendor_id, + .get_type = _get_type, + .get_value = _get_value, + .build = _build, + .process = _process, + .destroy = _destroy, + }, + .get_command = _get_command, + }, + .vendor_id = PEN_ITA, + .type = ITA_ATTR_COMMAND, + .value = chunk_clone(data), + ); + + return &this->public.pa_tnc_attribute; +} + + diff --git a/src/libimcv/ita/ita_attr_command.h b/src/libimcv/ita/ita_attr_command.h new file mode 100644 index 000000000..0e0b74e60 --- /dev/null +++ b/src/libimcv/ita/ita_attr_command.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * 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 ita_attr_commandt ita_attr_command + * @{ @ingroup ita_attr_command + */ + +#ifndef ITA_ATTR_COMMAND_H_ +#define ITA_ATTR_COMMAND_H_ + +typedef struct ita_attr_command_t ita_attr_command_t; + +#include "pa_tnc/pa_tnc_attr.h" + +#define ITA_ATTR_COMMAND 0x01 + +/** + * Class implementing the ITA Command PA-TNC attribute. + * + */ +struct ita_attr_command_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get the ITA command string + * + * @return ITA command string + */ + char* (*get_command)(ita_attr_command_t *this); +}; + +/** + * Creates an ita_attr_command_t object from a command string + * + * @param command ITA command string + */ +pa_tnc_attr_t* ita_attr_command_create(char *command); + +/** + * Creates an ita_attr_command_t object from received data + * + * @param command ITA command string + */ +pa_tnc_attr_t* ita_attr_command_create_from_data(chunk_t value); + +#endif /** ITA_ATTR_COMMAND_H_ @}*/ diff --git a/src/libimcv/pa_tnc/pa_tnc_attr.c b/src/libimcv/pa_tnc/pa_tnc_attr.c new file mode 100644 index 000000000..f5c2f7bcb --- /dev/null +++ b/src/libimcv/pa_tnc/pa_tnc_attr.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * 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 "pa_tnc_attr.h" +#include "ietf/ietf_attr.h" +#include "ietf/ietf_attr_pa_tnc_error.h" +#include "ita/ita_attr_command.h" + +/** + * See header + */ +pa_tnc_attr_t* pa_tnc_attr_create_from_data(pen_t vendor_id, u_int32_t type, + chunk_t value) +{ + switch (vendor_id) + { + case PEN_IETF: + switch (type) + { + case IETF_ATTR_PA_TNC_ERROR: + return ietf_attr_pa_tnc_error_create_from_data(value); + case IETF_ATTR_TESTING: + case IETF_ATTR_ATTRIBUTE_REQUEST: + case IETF_ATTR_PRODUCT_INFORMATION: + case IETF_ATTR_NUMERIC_VERSION: + case IETF_ATTR_STRING_VERSION: + case IETF_ATTR_OPERATIONAL_STATUS: + case IETF_ATTR_PORT_FILTER: + case IETF_ATTR_INSTALLED_PACKAGES: + case IETF_ATTR_ASSESSMENT_RESULT: + case IETF_ATTR_REMEDIATION_INSTRUCTIONS: + case IETF_ATTR_FORWARDING_ENABLED: + case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED: + case IETF_ATTR_RESERVED: + default: + break; + } + break; + case PEN_ITA: + switch (type) + { + case ITA_ATTR_COMMAND: + return ita_attr_command_create_from_data(value); + default: + break; + } + break; + default: + break; + } + return NULL; +} diff --git a/src/libimcv/pa_tnc/pa_tnc_attr.h b/src/libimcv/pa_tnc/pa_tnc_attr.h new file mode 100644 index 000000000..b594a4608 --- /dev/null +++ b/src/libimcv/pa_tnc/pa_tnc_attr.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * 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 pa_tnc_attr pa_tnc_attr + * @{ @ingroup libimcv + */ + +#ifndef PA_TNC_ATTR_H_ +#define PA_TNC_ATTR_H_ + +typedef struct pa_tnc_attr_t pa_tnc_attr_t; + +#include <library.h> +#include <tnc/pen/pen.h> + +/** + * Interface for an RFC 5792 PA-TNC Posture Attribute. + * + */ +struct pa_tnc_attr_t { + + /** + * Get the vendor ID of an PA-TNC attribute + * + * @return attribute vendor ID + */ + u_int32_t (*get_vendor_id)(pa_tnc_attr_t *this); + + /** + * Get the type of an PA-TNC attribute + * + * @return attribute type + */ + u_int32_t (*get_type)(pa_tnc_attr_t *this); + + /** + * Get the value of an PA-TNC attribute + * + * @return attribute value + */ + chunk_t (*get_value)(pa_tnc_attr_t *this); + + /** + * Get the noskip flag + * + * @return TRUE if the noskip flag is set + */ + bool (*get_noskip_flag)(pa_tnc_attr_t *this); + + /** + * Set the noskip flag + * + * @param noskip_flag TRUE if the noskip flag is to be set + */ + void (*set_noskip_flag)(pa_tnc_attr_t *this, bool noskip); + + /** + * Build value of an PA-TNC attribute from its parameters + */ + void (*build)(pa_tnc_attr_t *this); + + /** + * Process the value of an PA-TNC attribute to extract its parameters + * + * @return result status + */ + status_t (*process)(pa_tnc_attr_t *this); + + /** + * Destroys a pa_tnc_attr_t object. + */ + void (*destroy)(pa_tnc_attr_t *this); +}; + +/** + * Create a PA-TNC attribute from data + * + * @param vendor_id attribute vendor ID + * @param type attribute type + * @param value attribute value + * + */ +pa_tnc_attr_t* pa_tnc_attr_create_from_data(pen_t vendor_id, u_int32_t type, + chunk_t value); + +#endif /** PA_TNC_ATTR_H_ @}*/ diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.c b/src/libimcv/pa_tnc/pa_tnc_msg.c new file mode 100644 index 000000000..f182f92bb --- /dev/null +++ b/src/libimcv/pa_tnc/pa_tnc_msg.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * + * 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 "pa_tnc_msg.h" + +#include <tls_writer.h> +#include <tls_reader.h> +#include <utils/linked_list.h> +#include <tnc/pen/pen.h> +#include <debug.h> + + +typedef struct private_pa_tnc_msg_t private_pa_tnc_msg_t; + +/** + * PA-TNC message header + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Version | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Message Identifier | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#define PA_TNC_HEADER_SIZE 8 +#define PA_TNC_VERSION 0x01 +#define PA_TNC_RESERVED 0x000000 + +/** + * PA-TNC attribute + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Flags | PA-TNC Attribute Vendor ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PA-TNC Attribute Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PA-TNC Attribute Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Attribute Value (Variable Length) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#define PA_TNC_ATTR_FLAG_NONE 0x00 +#define PA_TNC_ATTR_FLAG_NOSKIP (1<<7) +#define PA_TNC_ATTR_HEADER_SIZE 12 + +/** + * Private data of a pa_tnc_msg_t object. + * + */ +struct private_pa_tnc_msg_t { + + /** + * Public pa_tnc_msg_t interface. + */ + pa_tnc_msg_t public; + + /** + * List of PA-TNC attributes + */ + linked_list_t *attributes; + + /** + * Message identifier + */ + u_int32_t identifier; + + /** + * Encoded message + */ + chunk_t encoding; +}; + +METHOD(pa_tnc_msg_t, get_encoding, chunk_t, + private_pa_tnc_msg_t *this) +{ + return this->encoding; +} + +METHOD(pa_tnc_msg_t, add_attribute, void, + private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr) +{ + this->attributes->insert_last(this->attributes, attr); +} + +METHOD(pa_tnc_msg_t, build, void, + private_pa_tnc_msg_t *this) +{ + tls_writer_t *writer; + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + pen_t vendor_id; + u_int32_t type; + u_int8_t flags; + chunk_t value; + rng_t *rng; + + /* create a random message identifier */ + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + rng->get_bytes(rng, sizeof(this->identifier), (u_int8_t*)&this->identifier); + rng->destroy(rng); + DBG2(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier); + + /* build message header */ + writer = tls_writer_create(PA_TNC_HEADER_SIZE); + writer->write_uint8 (writer, PA_TNC_VERSION); + writer->write_uint24(writer, PA_TNC_RESERVED); + writer->write_uint32(writer, this->identifier); + + /* build and append encoding of PA-TNC attributes */ + enumerator = this->attributes->create_enumerator(this->attributes); + while (enumerator->enumerate(enumerator, &attr)) + { + attr->build(attr); + vendor_id = attr->get_vendor_id(attr); + type = attr->get_type(attr); + value = attr->get_value(attr); + flags = attr->get_noskip_flag(attr) ? PA_TNC_ATTR_FLAG_NOSKIP : + PA_TNC_ATTR_FLAG_NONE; + DBG2(DBG_TNC, "creating PA-TNC attribute type 0x%06x(%N)/0x%08x", + vendor_id, pen_names, vendor_id, type); + DBG3(DBG_TNC, "%B", &value); + + writer->write_uint8 (writer, flags); + writer->write_uint24(writer, vendor_id); + writer->write_uint32(writer, type); + writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + value.len); + writer->write_data (writer, value); + } + enumerator->destroy(enumerator); + + free(this->encoding.ptr); + this->encoding = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +METHOD(pa_tnc_msg_t, process, status_t, + private_pa_tnc_msg_t *this) +{ + u_int8_t version; + u_int32_t reserved; + tls_reader_t *reader; + status_t status = FAILED; + + reader = tls_reader_create(this->encoding); + + /* process message header */ + if (reader->remaining(reader) < PA_TNC_HEADER_SIZE) + { + DBG1(DBG_TNC, "%u bytes insufficient to parse PA-TNC message header", + this->encoding.len); + goto end; + } + reader->read_uint8 (reader, &version); + reader->read_uint24(reader, &reserved); + reader->read_uint32(reader, &this->identifier); + + if (version != PA_TNC_VERSION) + { + DBG1(DBG_TNC, "PA-TNC version %u not supported", version); + goto end; + } + DBG2(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier); + + /* pre-process PA-TNC attributes */ + while (reader->remaining(reader) >= PA_TNC_ATTR_HEADER_SIZE) + { + pen_t vendor_id; + u_int8_t flags; + u_int32_t type, length; + chunk_t value; + pa_tnc_attr_t *attr; + + reader->read_uint8 (reader, &flags); + reader->read_uint24(reader, &vendor_id); + reader->read_uint32(reader, &type); + reader->read_uint32(reader, &length); + DBG2(DBG_TNC, "processing PA-TNC attribute type 0x%06x(%N)/0x%08x", + vendor_id, pen_names, vendor_id, type); + + if (length < PA_TNC_ATTR_HEADER_SIZE) + { + DBG1(DBG_TNC, "%u bytes too small for PA-TNC attribute length", + length); + goto end; + } + length -= PA_TNC_ATTR_HEADER_SIZE; + + if (!reader->read_data(reader, length , &value)) + { + DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value"); + goto end; + } + DBG3(DBG_TNC, "%B", &value); + + attr = pa_tnc_attr_create_from_data(vendor_id, type, value); + if (!attr) + { + if (flags & PA_TNC_ATTR_FLAG_NOSKIP) + { + DBG1(DBG_TNC, "unsupported PA-TNC attribute with NOSKIP flag"); + goto end; + } + else + { + DBG1(DBG_TNC, "skipping unsupported PA-TNC attribute"); + } + } + + if (attr->process(attr) != SUCCESS) + { + attr->destroy(attr); + goto end; + } + add_attribute(this, attr); + } + + if (reader->remaining(reader) == 0) + { + status = SUCCESS; + } + +end: + reader->destroy(reader); + return status; +} + +METHOD(pa_tnc_msg_t, create_attribute_enumerator, enumerator_t*, + private_pa_tnc_msg_t *this) +{ + return this->attributes->create_enumerator(this->attributes); +} + +METHOD(pa_tnc_msg_t, destroy, void, + private_pa_tnc_msg_t *this) +{ + this->attributes->destroy_offset(this->attributes, + offsetof(pa_tnc_attr_t, destroy)); + free(this->encoding.ptr); + free(this); +} + + +/** + * See header + */ +pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) +{ + private_pa_tnc_msg_t *this; + + INIT(this, + .public = { + .get_encoding = _get_encoding, + .add_attribute = _add_attribute, + .build = _build, + .process = _process, + .create_attribute_enumerator = _create_attribute_enumerator, + .destroy = _destroy, + }, + .encoding = chunk_clone(data), + .attributes = linked_list_create(), + ); + + return &this->public; +} + +/** + * See header + */ +pa_tnc_msg_t *pa_tnc_msg_create(void) +{ + return pa_tnc_msg_create_from_data(chunk_empty); +} + + diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.h b/src/libimcv/pa_tnc/pa_tnc_msg.h new file mode 100644 index 000000000..9e1e0a639 --- /dev/null +++ b/src/libimcv/pa_tnc/pa_tnc_msg.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * 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 pa_tnc_msg pa_tnc_msg + * @{ @ingroup libimcv + */ + +#ifndef PA_TNC_MSG_H_ +#define PA_TNC_MSG_H_ + +typedef struct pa_tnc_msg_t pa_tnc_msg_t; + +#include "pa_tnc_attr.h" + +#include <library.h> + +/** + * Interface for the RFC 5792 PA-TNC Posture Attribute protocol. + * + */ +struct pa_tnc_msg_t { + + /** + * Get the encoding of the PA-TNC message + * + * @return encoded PA-TNC message + */ + chunk_t (*get_encoding)(pa_tnc_msg_t *this); + + /** + * Add a PA-TNC attribute + * + * @param attr PA-TNC attribute to be addedd + */ + void (*add_attribute)(pa_tnc_msg_t *this, pa_tnc_attr_t* attr); + + /** + * Build the PA-TNC message + */ + void (*build)(pa_tnc_msg_t *this); + + /** + * Process the PA-TNC message + * + * @return return processing status + */ + status_t (*process)(pa_tnc_msg_t *this); + + /** + * Enumerates over all PA-TNC attributes + * + * @return return attribute enumerator + */ + enumerator_t* (*create_attribute_enumerator)(pa_tnc_msg_t *this); + + /** + * Destroys a pa_tnc_msg_t object. + */ + void (*destroy)(pa_tnc_msg_t *this); +}; + +/** + * Create an empty PA-TNC message + */ +pa_tnc_msg_t* pa_tnc_msg_create(void); + +/** + * Create an unprocessed PA-TNC message from received data + * + * @param data PA-TNC message data + */ +pa_tnc_msg_t* pa_tnc_msg_create_from_data(chunk_t data); + +#endif /** PA_TNC_MSG_H_ @}*/ |