From: Andreas Steffen Date: Thu, 30 May 2013 16:02:00 +0000 (+0200) Subject: Converted all IMVs to use generic IF-IMV API X-Git-Tag: 5.1.0dr1~59 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c174c116fe2b7be407499d13fe67f568c14d47d0;p=thirdparty%2Fstrongswan.git Converted all IMVs to use generic IF-IMV API --- diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index cf257c04bf..3a9f323691 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -9,7 +9,8 @@ libimcv_la_SOURCES = \ imcv.h imcv.c \ imc/imc_agent.h imc/imc_agent.c imc/imc_state.h \ imc/imc_msg.h imc/imc_msg.c \ - imv/imv_agent.h imv/imv_agent.c imv/imv_agent_if.h imv/imv_state.h \ + imv/imv_agent.h imv/imv_agent.c imv/imv_state.h \ + imv/imv_agent_if.h imv/imv_if.h \ imv/imv_database.h imv/imv_database.c \ imv/imv_msg.h imv/imv_msg.c \ imv/imv_lang_string.h imv/imv_lang_string.c \ diff --git a/src/libimcv/imv/imv_agent_if.h b/src/libimcv/imv/imv_agent_if.h index 2668afa8f1..db188793a2 100644 --- a/src/libimcv/imv/imv_agent_if.h +++ b/src/libimcv/imv/imv_agent_if.h @@ -106,4 +106,10 @@ struct imv_agent_if_t { }; +/** + * Constructor template + */ +typedef imv_agent_if_t* (*imv_agent_create_t)(const char* name, TNC_IMVID id, + TNC_Version *actual_version); + #endif /** IMV_AGENT_IF_H_ @}*/ diff --git a/src/libimcv/imv/imv_if.h b/src/libimcv/imv/imv_if.h new file mode 100644 index 0000000000..fa9765b119 --- /dev/null +++ b/src/libimcv/imv/imv_if.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2012-2013 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 . + * + * 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. + */ + +/** + * Define the following two static constants externally: + * static const char imv_name[] = "xx"; + * static const imv_agent_create_t imv_agent_create = imv_xx_agent_create; + */ + +#include + +static imv_agent_if_t *imv_agent; + +/* + * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, + TNC_Version min_version, + TNC_Version max_version, + TNC_Version *actual_version) +{ + if (imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); + return TNC_RESULT_ALREADY_INITIALIZED; + } + + imv_agent = imv_agent_create(imv_name, imv_id, actual_version); + + if (!imv_agent) + { + return TNC_RESULT_FATAL; + } + 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; + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + if (!imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_agent->notify_connection_change(imv_agent, connection_id, + new_state); +} + +/** + * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + if (!imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_agent->receive_message(imv_agent, connection_id, msg_type, + chunk_create(msg, msg_len)); +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id, + TNC_ConnectionID connection_id, + TNC_UInt32 msg_flags, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imc_id, + TNC_UInt32 dst_imv_id) +{ + if (!imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_agent->receive_message_long(imv_agent, connection_id, + src_imc_id, dst_imv_id, + msg_vid, msg_subtype, chunk_create(msg, msg_len)); +} + +/** + * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, + TNC_ConnectionID connection_id) +{ + + if (!imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_agent->solicit_recommendation(imv_agent, connection_id); +} + +/** + * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, TNC_ConnectionID connection_id) +{ + if (!imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_agent->batch_ending(imv_agent, connection_id); +} + +/** + * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) +{ + if (!imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + imv_agent->destroy(imv_agent); + imv_agent = NULL; + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, + TNC_TNCS_BindFunctionPointer bind_function) +{ + if (!imv_agent) + { + DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imv_agent->bind_functions(imv_agent, bind_function); +} diff --git a/src/libimcv/plugins/imv_os/imv_os.c b/src/libimcv/plugins/imv_os/imv_os.c index ad80976e44..ba0fa81537 100644 --- a/src/libimcv/plugins/imv_os/imv_os.c +++ b/src/libimcv/plugins/imv_os/imv_os.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Andreas Steffen + * Copyright (C) 2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,153 +15,10 @@ #include "imv_os_agent.h" -#include - -/* IMV definitions */ - static const char imv_name[] = "OS"; +static const imv_agent_create_t imv_agent_create = imv_os_agent_create; -static imv_agent_if_t *imv_agent; - -/* - * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, - TNC_Version min_version, - TNC_Version max_version, - TNC_Version *actual_version) -{ - if (imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); - return TNC_RESULT_ALREADY_INITIALIZED; - } - - imv_agent = imv_os_agent_create(imv_name, imv_id, actual_version); +/* include generic TGC TNC IF-IMV API code below */ - if (!imv_agent) - { - return TNC_RESULT_FATAL; - } - 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; - } - return TNC_RESULT_SUCCESS; -} +#include -/** - * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_ConnectionState new_state) -{ - if (!imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_agent->notify_connection_change(imv_agent, connection_id, - new_state); -} - -/** - * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) -{ - if (!imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_agent->receive_message(imv_agent, connection_id, msg_type, - chunk_create(msg, msg_len)); -} - -/** - * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_UInt32 msg_flags, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_VendorID msg_vid, - TNC_MessageSubtype msg_subtype, - TNC_UInt32 src_imc_id, - TNC_UInt32 dst_imv_id) -{ - if (!imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_agent->receive_message_long(imv_agent, connection_id, - src_imc_id, dst_imv_id, - msg_vid, msg_subtype, chunk_create(msg, msg_len)); -} - -/** - * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - - if (!imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_agent->solicit_recommendation(imv_agent, connection_id); -} - -/** - * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, TNC_ConnectionID connection_id) -{ - if (!imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_agent->batch_ending(imv_agent, connection_id); -} - -/** - * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) -{ - if (!imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - imv_agent->destroy(imv_agent); - imv_agent = NULL; - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, - TNC_TNCS_BindFunctionPointer bind_function) -{ - if (!imv_agent) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_agent->bind_functions(imv_agent, bind_function); -} diff --git a/src/libimcv/plugins/imv_scanner/Makefile.am b/src/libimcv/plugins/imv_scanner/Makefile.am index df2158e724..72d90c71a1 100644 --- a/src/libimcv/plugins/imv_scanner/Makefile.am +++ b/src/libimcv/plugins/imv_scanner/Makefile.am @@ -9,7 +9,9 @@ imcv_LTLIBRARIES = imv-scanner.la imv_scanner_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \ $(top_builddir)/src/libstrongswan/libstrongswan.la -imv_scanner_la_SOURCES = imv_scanner.c imv_scanner_state.h imv_scanner_state.c +imv_scanner_la_SOURCES = \ + imv_scanner.c imv_scanner_state.h imv_scanner_state.c \ + imv_scanner_agent.h imv_scanner_agent.c imv_scanner_la_LDFLAGS = -module -avoid-version diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner.c b/src/libimcv/plugins/imv_scanner/imv_scanner.c index 5557bbc6b1..6f5e823553 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Andreas Steffen + * Copyright (C) 2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -13,443 +13,12 @@ * for more details. */ -#include "imv_scanner_state.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -/* IMV definitions */ +#include "imv_scanner_agent.h" static const char imv_name[] = "Scanner"; +static const imv_agent_create_t imv_agent_create = imv_scanner_agent_create; -static pen_type_t msg_types[] = { - { PEN_IETF, PA_SUBTYPE_IETF_VPN } -}; - -static imv_agent_t *imv_scanner; - -/** - * Flag set when corresponding attribute has been received - */ -typedef enum imv_scanner_attr_t imv_scanner_attr_t; - -enum imv_scanner_attr_t { - IMV_SCANNER_ATTR_PORT_FILTER = (1<<0) -}; - -typedef struct port_range_t port_range_t; - -struct port_range_t { - u_int16_t start, stop; -}; - - -/** - * Default port policy - * - * TRUE: all server ports on the TNC client must be closed - * FALSE: any server port on the TNC client is allowed to be open - */ -static bool closed_port_policy = TRUE; - -/** - * List of TCP and UDP port ranges - * - * TRUE: server ports on the TNC client that are allowed to be open - * FALSE: server ports on the TNC client that must be closed - */ -static linked_list_t *tcp_ports, *udp_ports; - -/** - * Get a TCP or UDP port list from strongswan.conf - */ -static linked_list_t* get_port_list(char *label) -{ - char key[40], *value; - linked_list_t *list; - chunk_t port_list, port_item, port_start; - port_range_t *port_range; - - list = linked_list_create(); - - snprintf(key, sizeof(key), "libimcv.plugins.imv-scanner.%s_ports", label); - value = lib->settings->get_str(lib->settings, key, NULL); - if (!value) - { - DBG1(DBG_IMV, "%s not defined", key); - return list; - } - port_list = chunk_create(value, strlen(value)); - DBG2(DBG_IMV, "list of %s ports that %s:", label, - closed_port_policy ? "are allowed to be open" : "must be closed"); - - while (eat_whitespace(&port_list)) - { - if (!extract_token(&port_item, ' ', &port_list)) - { - /* reached last port item */ - port_item = port_list; - port_list = chunk_empty; - } - port_range = malloc_thing(port_range_t); - port_range->start = atoi(port_item.ptr); - - if (extract_token(&port_start, '-', &port_item) && port_item.len) - { - port_range->stop = atoi(port_item.ptr); - } - else - { - port_range->stop = port_range->start; - } - DBG2(DBG_IMV, "%5u - %5u", port_range->start, port_range->stop); - list->insert_last(list, port_range); - } - - return list; -} - - -/* - * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, - TNC_Version min_version, - TNC_Version max_version, - TNC_Version *actual_version) -{ - if (imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); - return TNC_RESULT_ALREADY_INITIALIZED; - } - imv_scanner = imv_agent_create(imv_name, msg_types, countof(msg_types), - imv_id, actual_version); - if (!imv_scanner) - { - return TNC_RESULT_FATAL; - } - 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; - } - - /* set the default port policy to closed (TRUE) or open (FALSE) */ - closed_port_policy = lib->settings->get_bool(lib->settings, - "libimcv.plugins.imv-scanner.closed_port_policy", TRUE); - DBG2(DBG_IMV, "default port policy is %s ports", - closed_port_policy ? "closed" : "open"); - - /* get the list of open|closed ports */ - tcp_ports = get_port_list("tcp"); - udp_ports = get_port_list("udp"); - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_ConnectionState new_state) -{ - imv_state_t *state; - - if (!imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - switch (new_state) - { - case TNC_CONNECTION_STATE_CREATE: - state = imv_scanner_state_create(connection_id); - return imv_scanner->create_state(imv_scanner, state); - case TNC_CONNECTION_STATE_DELETE: - return imv_scanner->delete_state(imv_scanner, connection_id); - default: - return imv_scanner->change_state(imv_scanner, connection_id, - new_state, NULL); - } -} +/* include generic TGC TNC IF-IMV API code below */ -static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) -{ - imv_msg_t *out_msg; - enumerator_t *enumerator; - pa_tnc_attr_t *attr; - pen_type_t type; - TNC_Result result; - bool fatal_error = FALSE; +#include - /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - - /* analyze PA-TNC attributes */ - enumerator = in_msg->create_attribute_enumerator(in_msg); - while (enumerator->enumerate(enumerator, &attr)) - { - type = attr->get_type(attr); - - if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PORT_FILTER) - { - imv_scanner_state_t *scanner_state; - ietf_attr_port_filter_t *attr_port_filter; - enumerator_t *enumerator; - u_int8_t protocol; - u_int16_t port; - bool blocked, compliant = TRUE; - - - scanner_state = (imv_scanner_state_t*)state; - scanner_state->set_received(scanner_state, - IMV_SCANNER_ATTR_PORT_FILTER); - attr_port_filter = (ietf_attr_port_filter_t*)attr; - - enumerator = attr_port_filter->create_port_enumerator(attr_port_filter); - while (enumerator->enumerate(enumerator, &blocked, &protocol, &port)) - { - enumerator_t *e; - port_range_t *port_range; - bool passed, found = FALSE; - char buf[20]; - - if (blocked) - { - /* ignore closed ports */ - continue; - } - - e = (protocol == IPPROTO_TCP) ? - tcp_ports->create_enumerator(tcp_ports) : - udp_ports->create_enumerator(udp_ports); - while (e->enumerate(e, &port_range)) - { - if (port >= port_range->start && port <= port_range->stop) - { - found = TRUE; - break; - } - } - e->destroy(e); - - passed = (closed_port_policy == found); - DBG2(DBG_IMV, "%s port %5u %s: %s", - (protocol == IPPROTO_TCP) ? "tcp" : "udp", port, - blocked ? "closed" : "open", passed ? "ok" : "fatal"); - if (!passed) - { - compliant = FALSE; - snprintf(buf, sizeof(buf), "%s/%u", - (protocol == IPPROTO_TCP) ? "tcp" : "udp", port); - scanner_state->add_violating_port(scanner_state, strdup(buf)); - } - } - enumerator->destroy(enumerator); - - if (compliant) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_ALLOW, - TNC_IMV_EVALUATION_RESULT_COMPLIANT); - } - else - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, - TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); - } - } - } - enumerator->destroy(enumerator); - - if (fatal_error) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, - TNC_IMV_EVALUATION_RESULT_ERROR); - } - - out_msg = imv_msg_create_as_reply(in_msg); - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return imv_scanner->provide_recommendation(imv_scanner, state); - } - -/** - * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) -{ - imv_state_t *state; - imv_msg_t *in_msg; - TNC_Result result; - - if (!imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_scanner->get_state(imv_scanner, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - - in_msg = imv_msg_create_from_data(imv_scanner, state, connection_id, msg_type, - chunk_create(msg, msg_len)); - result = receive_message(state, in_msg); - in_msg->destroy(in_msg); - - return result; -} - -/** - * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_UInt32 msg_flags, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_VendorID msg_vid, - TNC_MessageSubtype msg_subtype, - TNC_UInt32 src_imc_id, - TNC_UInt32 dst_imv_id) -{ - imv_state_t *state; - imv_msg_t *in_msg; - TNC_Result result; - - if (!imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_scanner->get_state(imv_scanner, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - in_msg = imv_msg_create_from_long_data(imv_scanner, state, connection_id, - src_imc_id, dst_imv_id, msg_vid, msg_subtype, - chunk_create(msg, msg_len)); - result =receive_message(state, in_msg); - in_msg->destroy(in_msg); - - return result; -} - -/** - * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - imv_state_t *state; - - if (!imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_scanner->get_state(imv_scanner, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - return imv_scanner->provide_recommendation(imv_scanner, state); -} - -/** - * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - imv_state_t *state; - imv_msg_t *out_msg; - pa_tnc_attr_t *attr; - TNC_IMV_Action_Recommendation rec; - TNC_IMV_Evaluation_Result eval; - TNC_Result result = TNC_RESULT_SUCCESS; - - if (!imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_scanner->get_state(imv_scanner, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - state->get_recommendation(state, &rec, &eval); - if (rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION) - { - out_msg = imv_msg_create(imv_scanner, state, connection_id, imv_id, - TNC_IMCID_ANY, msg_types[0]); - attr = ietf_attr_attr_request_create(PEN_IETF, IETF_ATTR_PORT_FILTER); - out_msg->add_attribute(out_msg, attr); - - /* send PA-TNC message with excl flag not set */ - result = out_msg->send(out_msg, FALSE); - out_msg->destroy(out_msg); - - } - return result; -} - -/** - * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) -{ - if (!imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - tcp_ports->destroy_function(tcp_ports, free); - udp_ports->destroy_function(udp_ports, free); - imv_scanner->destroy(imv_scanner); - imv_scanner = NULL; - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, - TNC_TNCS_BindFunctionPointer bind_function) -{ - if (!imv_scanner) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_scanner->bind_functions(imv_scanner, bind_function); -} diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c b/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c new file mode 100644 index 0000000000..977d657979 --- /dev/null +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2013 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 . + * + * 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_scanner_agent.h" +#include "imv_scanner_state.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +typedef struct private_imv_scanner_agent_t private_imv_scanner_agent_t; + +/* Subscribed PA-TNC message subtypes */ +static pen_type_t msg_types[] = { + { PEN_IETF, PA_SUBTYPE_IETF_VPN } +}; + +/** + * Flag set when corresponding attribute has been received + */ +typedef enum imv_scanner_attr_t imv_scanner_attr_t; + +enum imv_scanner_attr_t { + IMV_SCANNER_ATTR_PORT_FILTER = (1<<0) +}; + +typedef struct port_range_t port_range_t; + +struct port_range_t { + u_int16_t start, stop; +}; + +/** + * Default port policy + * + * TRUE: all server ports on the TNC client must be closed + * FALSE: any server port on the TNC client is allowed to be open + */ +static bool closed_port_policy = TRUE; + +/** + * List of TCP and UDP port ranges + * + * TRUE: server ports on the TNC client that are allowed to be open + * FALSE: server ports on the TNC client that must be closed + */ +static linked_list_t *tcp_ports, *udp_ports; + +/** + * Get a TCP or UDP port list from strongswan.conf + */ +static linked_list_t* get_port_list(char *label) +{ + char key[40], *value; + linked_list_t *list; + chunk_t port_list, port_item, port_start; + port_range_t *port_range; + + list = linked_list_create(); + + snprintf(key, sizeof(key), "libimcv.plugins.imv-scanner.%s_ports", label); + value = lib->settings->get_str(lib->settings, key, NULL); + if (!value) + { + DBG1(DBG_IMV, "%s not defined", key); + return list; + } + port_list = chunk_create(value, strlen(value)); + DBG2(DBG_IMV, "list of %s ports that %s:", label, + closed_port_policy ? "are allowed to be open" : "must be closed"); + + while (eat_whitespace(&port_list)) + { + if (!extract_token(&port_item, ' ', &port_list)) + { + /* reached last port item */ + port_item = port_list; + port_list = chunk_empty; + } + port_range = malloc_thing(port_range_t); + port_range->start = atoi(port_item.ptr); + + if (extract_token(&port_start, '-', &port_item) && port_item.len) + { + port_range->stop = atoi(port_item.ptr); + } + else + { + port_range->stop = port_range->start; + } + DBG2(DBG_IMV, "%5u - %5u", port_range->start, port_range->stop); + list->insert_last(list, port_range); + } + + return list; +} + +/** + * Private data of an imv_scanner_agent_t object. + */ +struct private_imv_scanner_agent_t { + + /** + * Public members of imv_scanner_agent_t + */ + imv_agent_if_t public; + + /** + * IMV agent responsible for generic functions + */ + imv_agent_t *agent; + +}; + +METHOD(imv_agent_if_t, bind_functions, TNC_Result, + private_imv_scanner_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function) +{ + return this->agent->bind_functions(this->agent, bind_function); +} + +METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, + private_imv_scanner_agent_t *this, TNC_ConnectionID id, + TNC_ConnectionState new_state) +{ + imv_state_t *state; + + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imv_scanner_state_create(id); + return this->agent->create_state(this->agent, state); + case TNC_CONNECTION_STATE_DELETE: + return this->agent->delete_state(this->agent, id); + default: + return this->agent->change_state(this->agent, id, new_state, NULL); + } +} + +/** + * Process a received message + */ +static TNC_Result receive_msg(private_imv_scanner_agent_t *this, + imv_state_t *state, imv_msg_t *in_msg) +{ + imv_msg_t *out_msg; + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + pen_type_t type; + TNC_Result result; + bool fatal_error = FALSE; + + /* parse received PA-TNC message and handle local and remote errors */ + result = in_msg->receive(in_msg, &fatal_error); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + + /* analyze PA-TNC attributes */ + enumerator = in_msg->create_attribute_enumerator(in_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PORT_FILTER) + { + imv_scanner_state_t *scanner_state; + ietf_attr_port_filter_t *attr_port_filter; + enumerator_t *enumerator; + u_int8_t protocol; + u_int16_t port; + bool blocked, compliant = TRUE; + + + scanner_state = (imv_scanner_state_t*)state; + scanner_state->set_received(scanner_state, + IMV_SCANNER_ATTR_PORT_FILTER); + attr_port_filter = (ietf_attr_port_filter_t*)attr; + + enumerator = attr_port_filter->create_port_enumerator(attr_port_filter); + while (enumerator->enumerate(enumerator, &blocked, &protocol, &port)) + { + enumerator_t *e; + port_range_t *port_range; + bool passed, found = FALSE; + char buf[20]; + + if (blocked) + { + /* ignore closed ports */ + continue; + } + + e = (protocol == IPPROTO_TCP) ? + tcp_ports->create_enumerator(tcp_ports) : + udp_ports->create_enumerator(udp_ports); + while (e->enumerate(e, &port_range)) + { + if (port >= port_range->start && port <= port_range->stop) + { + found = TRUE; + break; + } + } + e->destroy(e); + + passed = (closed_port_policy == found); + DBG2(DBG_IMV, "%s port %5u %s: %s", + (protocol == IPPROTO_TCP) ? "tcp" : "udp", port, + blocked ? "closed" : "open", passed ? "ok" : "fatal"); + if (!passed) + { + compliant = FALSE; + snprintf(buf, sizeof(buf), "%s/%u", + (protocol == IPPROTO_TCP) ? "tcp" : "udp", port); + scanner_state->add_violating_port(scanner_state, strdup(buf)); + } + } + enumerator->destroy(enumerator); + + if (compliant) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_COMPLIANT); + } + else + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, + TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); + } + } + } + enumerator->destroy(enumerator); + + if (fatal_error) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + } + + out_msg = imv_msg_create_as_reply(in_msg); + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); +} + +METHOD(imv_agent_if_t, receive_message, TNC_Result, + private_imv_scanner_agent_t *this, TNC_ConnectionID id, + TNC_MessageType msg_type, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +METHOD(imv_agent_if_t, receive_message_long, TNC_Result, + private_imv_scanner_agent_t *this, TNC_ConnectionID id, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, + TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_long_data(this->agent, state, id, + src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; + +} + +METHOD(imv_agent_if_t, batch_ending, TNC_Result, + private_imv_scanner_agent_t *this, TNC_ConnectionID id) +{ + imv_state_t *state; + imv_msg_t *out_msg; + pa_tnc_attr_t *attr; + TNC_IMV_Action_Recommendation rec; + TNC_IMV_Evaluation_Result eval; + TNC_Result result = TNC_RESULT_SUCCESS; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + state->get_recommendation(state, &rec, &eval); + if (rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION) + { + out_msg = imv_msg_create(this->agent, state, id, + this->agent->get_id(this->agent), + TNC_IMCID_ANY, msg_types[0]); + attr = ietf_attr_attr_request_create(PEN_IETF, IETF_ATTR_PORT_FILTER); + out_msg->add_attribute(out_msg, attr); + + /* send PA-TNC message with excl flag not set */ + result = out_msg->send(out_msg, FALSE); + out_msg->destroy(out_msg); + } + return result; +} + +METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, + private_imv_scanner_agent_t *this, TNC_ConnectionID id) +{ + imv_state_t *state; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + return this->agent->provide_recommendation(this->agent, state); +} + +METHOD(imv_agent_if_t, destroy, void, + private_imv_scanner_agent_t *this) +{ + tcp_ports->destroy_function(tcp_ports, free); + udp_ports->destroy_function(udp_ports, free); + this->agent->destroy(this->agent); + free(this); +} + +/** + * Described in header. + */ +imv_agent_if_t *imv_scanner_agent_create(const char *name, TNC_IMVID id, + TNC_Version *actual_version) +{ + private_imv_scanner_agent_t *this; + imv_agent_t *agent; + + agent = imv_agent_create(name, msg_types, countof(msg_types), id, + actual_version); + if (!agent) + { + return NULL; + } + + INIT(this, + .public = { + .bind_functions = _bind_functions, + .notify_connection_change = _notify_connection_change, + .receive_message = _receive_message, + .receive_message_long = _receive_message_long, + .batch_ending = _batch_ending, + .solicit_recommendation = _solicit_recommendation, + .destroy = _destroy, + }, + .agent = agent, + ); + + /* set the default port policy to closed (TRUE) or open (FALSE) */ + closed_port_policy = lib->settings->get_bool(lib->settings, + "libimcv.plugins.imv-scanner.closed_port_policy", TRUE); + DBG2(DBG_IMV, "default port policy is %s ports", + closed_port_policy ? "closed" : "open"); + + /* get the list of open|closed ports */ + tcp_ports = get_port_list("tcp"); + udp_ports = get_port_list("udp"); + + return &this->public; +} + diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_agent.h b/src/libimcv/plugins/imv_scanner/imv_scanner_agent.h new file mode 100644 index 0000000000..1554533639 --- /dev/null +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_agent.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 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 . + * + * 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_scanner_agent_t imv_scanner_agent + * @{ @ingroup imv_scanner + */ + +#ifndef IMV_SCANNER_AGENT_H_ +#define IMV_SCANNER_AGENT_H_ + +#include + +/** + * Creates a Scanner IMV agent + * + * @param name Name of the IMV + * @param id ID of the IMV + * @param actual_version TNC IF-IMV version + */ +imv_agent_if_t* imv_scanner_agent_create(const char* name, TNC_IMVID id, + TNC_Version *actual_version); + +#endif /** IMV_SCANNER_AGENT_H_ @}*/ diff --git a/src/libimcv/plugins/imv_test/Makefile.am b/src/libimcv/plugins/imv_test/Makefile.am index 4ca5b852b2..9e6f161e38 100644 --- a/src/libimcv/plugins/imv_test/Makefile.am +++ b/src/libimcv/plugins/imv_test/Makefile.am @@ -9,7 +9,9 @@ imcv_LTLIBRARIES = imv-test.la imv_test_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \ $(top_builddir)/src/libstrongswan/libstrongswan.la -imv_test_la_SOURCES = imv_test.c imv_test_state.h imv_test_state.c +imv_test_la_SOURCES = \ + imv_test.c imv_test_state.h imv_test_state.c \ + imv_test_agent.h imv_test_agent.c imv_test_la_LDFLAGS = -module -avoid-version diff --git a/src/libimcv/plugins/imv_test/imv_test.c b/src/libimcv/plugins/imv_test/imv_test.c index df45ce69a7..964faef658 100644 --- a/src/libimcv/plugins/imv_test/imv_test.c +++ b/src/libimcv/plugins/imv_test/imv_test.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Andreas Steffen + * Copyright (C) 2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -13,350 +13,12 @@ * for more details. */ -#include "imv_test_state.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -/* IMV definitions */ +#include "imv_test_agent.h" static const char imv_name[] = "Test"; +static const imv_agent_create_t imv_agent_create = imv_test_agent_create; -static pen_type_t msg_types[] = { - { PEN_ITA, PA_SUBTYPE_ITA_TEST } -}; - -static imv_agent_t *imv_test; - -/** - * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 - */ -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; - } - imv_test = imv_agent_create(imv_name, msg_types, countof(msg_types), - imv_id, actual_version); - if (!imv_test) - { - return TNC_RESULT_FATAL; - } - 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; - } - return TNC_RESULT_SUCCESS; -} - -/** - * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_ConnectionState new_state) -{ - imv_state_t *state; - - 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: - state = imv_test_state_create(connection_id); - 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, NULL); - } -} - -static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) -{ - imv_msg_t *out_msg; - imv_test_state_t *test_state; - enumerator_t *enumerator; - pa_tnc_attr_t *attr; - pen_type_t attr_type; - TNC_Result result; - int rounds; - bool fatal_error = FALSE, received_command = FALSE, retry = FALSE; - - /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - - /* add any new IMC and set its number of rounds */ - rounds = lib->settings->get_int(lib->settings, - "libimcv.plugins.imv-test.rounds", 0); - test_state = (imv_test_state_t*)state; - test_state->add_imc(test_state, in_msg->get_src_id(in_msg), rounds); - - /* analyze PA-TNC attributes */ - enumerator = in_msg->create_attribute_enumerator(in_msg); - while (enumerator->enumerate(enumerator, &attr)) - { - attr_type = attr->get_type(attr); - - if (attr_type.vendor_id != PEN_ITA) - { - continue; - } - if (attr_type.type == ITA_ATTR_COMMAND) - { - ita_attr_command_t *ita_attr; - char *command; - - received_command = TRUE; - 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, "block") || streq(command, "none")) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, - TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); - } - else if (streq(command, "retry")) - { - retry = TRUE; - } - else - { - DBG1(DBG_IMV, "unsupported ITA Command '%s'", command); - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, - TNC_IMV_EVALUATION_RESULT_ERROR); - } - } - else if (attr_type.type == ITA_ATTR_DUMMY) - { - ita_attr_dummy_t *ita_attr; - - ita_attr = (ita_attr_dummy_t*)attr; - DBG1(DBG_IMV, "received dummy attribute value (%d bytes)", - ita_attr->get_size(ita_attr)); - } - } - enumerator->destroy(enumerator); - - if (fatal_error) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, - TNC_IMV_EVALUATION_RESULT_ERROR); - out_msg = imv_msg_create_as_reply(in_msg); - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return imv_test->provide_recommendation(imv_test, state); - } - - /* request a handshake retry ? */ - if (retry) - { - test_state->set_rounds(test_state, rounds); - return imv_test->request_handshake_retry(imv_test->get_id(imv_test), - state->get_connection_id(state), - TNC_RETRY_REASON_IMV_SERIOUS_EVENT); - } +/* include generic TGC TNC IF-IMV API code below */ - /* repeat the measurement ? */ - if (test_state->another_round(test_state, in_msg->get_src_id(in_msg))) - { - out_msg = imv_msg_create_as_reply(in_msg); - attr = ita_attr_command_create("repeat"); - out_msg->add_attribute(out_msg, attr); +#include - /* send PA-TNC message with excl flag set */ - result = out_msg->send(out_msg, TRUE); - out_msg->destroy(out_msg); - - return result; - } - - if (received_command) - { - out_msg = imv_msg_create_as_reply(in_msg); - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return imv_test->provide_recommendation(imv_test, state); - } - else - { - return TNC_RESULT_SUCCESS; - } -} - -/** - * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) -{ - imv_state_t *state; - imv_msg_t *in_msg; - TNC_Result result; - - if (!imv_test) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_test->get_state(imv_test, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - in_msg = imv_msg_create_from_data(imv_test, state, connection_id, msg_type, - chunk_create(msg, msg_len)); - result = receive_message(state, in_msg); - in_msg->destroy(in_msg); - - return result; -} - -/** - * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_UInt32 msg_flags, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_VendorID msg_vid, - TNC_MessageSubtype msg_subtype, - TNC_UInt32 src_imc_id, - TNC_UInt32 dst_imv_id) -{ - imv_state_t *state; - imv_msg_t *in_msg; - TNC_Result result; - - if (!imv_test) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_test->get_state(imv_test, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - in_msg = imv_msg_create_from_long_data(imv_test, state, connection_id, - src_imc_id, dst_imv_id, msg_vid, msg_subtype, - chunk_create(msg, msg_len)); - result =receive_message(state, in_msg); - in_msg->destroy(in_msg); - - return result; -} - -/** - * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - imv_state_t *state; - - if (!imv_test) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_test->get_state(imv_test, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - return imv_test->provide_recommendation(imv_test, state); -} - -/** - * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 - */ -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.8.9 of TCG TNC IF-IMV Specification 1.3 - */ -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.3 - */ -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/libimcv/plugins/imv_test/imv_test_agent.c b/src/libimcv/plugins/imv_test/imv_test_agent.c new file mode 100644 index 0000000000..87d69373f5 --- /dev/null +++ b/src/libimcv/plugins/imv_test/imv_test_agent.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2013 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 . + * + * 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_agent.h" +#include "imv_test_state.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +typedef struct private_imv_test_agent_t private_imv_test_agent_t; + +/* Subscribed PA-TNC message subtypes */ +static pen_type_t msg_types[] = { + { PEN_ITA, PA_SUBTYPE_ITA_TEST } +}; + +/** + * Private data of an imv_test_agent_t object. + */ +struct private_imv_test_agent_t { + + /** + * Public members of imv_test_agent_t + */ + imv_agent_if_t public; + + /** + * IMV agent responsible for generic functions + */ + imv_agent_t *agent; + +}; + +METHOD(imv_agent_if_t, bind_functions, TNC_Result, + private_imv_test_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function) +{ + return this->agent->bind_functions(this->agent, bind_function); +} + +METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, + private_imv_test_agent_t *this, TNC_ConnectionID id, + TNC_ConnectionState new_state) +{ + imv_state_t *state; + + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imv_test_state_create(id); + return this->agent->create_state(this->agent, state); + case TNC_CONNECTION_STATE_DELETE: + return this->agent->delete_state(this->agent, id); + default: + return this->agent->change_state(this->agent, id, new_state, NULL); + } +} + +/** + * Process a received message + */ +static TNC_Result receive_msg(private_imv_test_agent_t *this, imv_state_t *state, + imv_msg_t *in_msg) +{ + imv_msg_t *out_msg; + imv_test_state_t *test_state; + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + pen_type_t attr_type; + TNC_Result result; + int rounds; + bool fatal_error = FALSE, received_command = FALSE, retry = FALSE; + + /* parse received PA-TNC message and handle local and remote errors */ + result = in_msg->receive(in_msg, &fatal_error); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + + /* add any new IMC and set its number of rounds */ + rounds = lib->settings->get_int(lib->settings, + "libimcv.plugins.imv-test.rounds", 0); + test_state = (imv_test_state_t*)state; + test_state->add_imc(test_state, in_msg->get_src_id(in_msg), rounds); + + /* analyze PA-TNC attributes */ + enumerator = in_msg->create_attribute_enumerator(in_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + attr_type = attr->get_type(attr); + + if (attr_type.vendor_id != PEN_ITA) + { + continue; + } + if (attr_type.type == ITA_ATTR_COMMAND) + { + ita_attr_command_t *ita_attr; + char *command; + + received_command = TRUE; + 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, "block") || streq(command, "none")) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, + TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); + } + else if (streq(command, "retry")) + { + retry = TRUE; + } + else + { + DBG1(DBG_IMV, "unsupported ITA Command '%s'", command); + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + } + } + else if (attr_type.type == ITA_ATTR_DUMMY) + { + ita_attr_dummy_t *ita_attr; + + ita_attr = (ita_attr_dummy_t*)attr; + DBG1(DBG_IMV, "received dummy attribute value (%d bytes)", + ita_attr->get_size(ita_attr)); + } + } + enumerator->destroy(enumerator); + + if (fatal_error) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + out_msg = imv_msg_create_as_reply(in_msg); + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + /* request a handshake retry ? */ + if (retry) + { + test_state->set_rounds(test_state, rounds); + return this->agent->request_handshake_retry( + this->agent->get_id(this->agent), + state->get_connection_id(state), + TNC_RETRY_REASON_IMV_SERIOUS_EVENT); + } + + /* repeat the measurement ? */ + if (test_state->another_round(test_state, in_msg->get_src_id(in_msg))) + { + out_msg = imv_msg_create_as_reply(in_msg); + attr = ita_attr_command_create("repeat"); + out_msg->add_attribute(out_msg, attr); + + /* send PA-TNC message with excl flag set */ + result = out_msg->send(out_msg, TRUE); + out_msg->destroy(out_msg); + + return result; + } + + if (received_command) + { + out_msg = imv_msg_create_as_reply(in_msg); + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + else + { + return TNC_RESULT_SUCCESS; + } + } + +METHOD(imv_agent_if_t, receive_message, TNC_Result, + private_imv_test_agent_t *this, TNC_ConnectionID id, + TNC_MessageType msg_type, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +METHOD(imv_agent_if_t, receive_message_long, TNC_Result, + private_imv_test_agent_t *this, TNC_ConnectionID id, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, + TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_long_data(this->agent, state, id, + src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; + +} + +METHOD(imv_agent_if_t, batch_ending, TNC_Result, + private_imv_test_agent_t *this, TNC_ConnectionID id) +{ + return TNC_RESULT_SUCCESS; +} + +METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, + private_imv_test_agent_t *this, TNC_ConnectionID id) +{ + imv_state_t *state; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + return this->agent->provide_recommendation(this->agent, state); +} + +METHOD(imv_agent_if_t, destroy, void, + private_imv_test_agent_t *this) +{ + DESTROY_IF(this->agent); + free(this); +} + +/** + * Described in header. + */ +imv_agent_if_t *imv_test_agent_create(const char *name, TNC_IMVID id, + TNC_Version *actual_version) +{ + private_imv_test_agent_t *this; + + INIT(this, + .public = { + .bind_functions = _bind_functions, + .notify_connection_change = _notify_connection_change, + .receive_message = _receive_message, + .receive_message_long = _receive_message_long, + .batch_ending = _batch_ending, + .solicit_recommendation = _solicit_recommendation, + .destroy = _destroy, + }, + .agent = imv_agent_create(name, msg_types, countof(msg_types), id, + actual_version), + ); + + if (!this->agent) + { + destroy(this); + return NULL; + } + return &this->public; +} + diff --git a/src/libimcv/plugins/imv_test/imv_test_agent.h b/src/libimcv/plugins/imv_test/imv_test_agent.h new file mode 100644 index 0000000000..15508d3750 --- /dev/null +++ b/src/libimcv/plugins/imv_test/imv_test_agent.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 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 . + * + * 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_agent_t imv_test_agent + * @{ @ingroup imv_test + */ + +#ifndef IMV_TEST_AGENT_H_ +#define IMV_TEST_AGENT_H_ + +#include + +/** + * Creates a Test IMV agent + * + * @param name Name of the IMV + * @param id ID of the IMV + * @param actual_version TNC IF-IMV version + */ +imv_agent_if_t* imv_test_agent_create(const char* name, TNC_IMVID id, + TNC_Version *actual_version); + +#endif /** IMV_TEST_AGENT_H_ @}*/ diff --git a/src/libpts/plugins/imv_attestation/Makefile.am b/src/libpts/plugins/imv_attestation/Makefile.am index 1d1c651dac..d01bc50d23 100644 --- a/src/libpts/plugins/imv_attestation/Makefile.am +++ b/src/libpts/plugins/imv_attestation/Makefile.am @@ -16,6 +16,7 @@ imv_attestation_la_LIBADD = \ imv_attestation_la_SOURCES = imv_attestation.c \ imv_attestation_state.h imv_attestation_state.c \ + imv_attestation_agent.h imv_attestation_agent.c \ imv_attestation_process.h imv_attestation_process.c \ imv_attestation_build.h imv_attestation_build.c diff --git a/src/libpts/plugins/imv_attestation/imv_attestation.c b/src/libpts/plugins/imv_attestation/imv_attestation.c index 74eee8117d..542a561aa3 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * Copyright (C) 2013 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -13,487 +13,12 @@ * for more details. */ -#include "imv_attestation_state.h" -#include "imv_attestation_process.h" -#include "imv_attestation_build.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -/* IMV definitions */ +#include "imv_attestation_agent.h" static const char imv_name[] = "Attestation"; +static const imv_agent_create_t imv_agent_create = imv_attestation_agent_create; -static pen_type_t msg_types[] = { - { PEN_TCG, PA_SUBTYPE_TCG_PTS }, - { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM } -}; - -static imv_agent_t *imv_attestation; - -/** - * Supported PTS measurement algorithms - */ -static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE; - -/** - * Supported PTS Diffie Hellman Groups - */ -static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE; - -/** - * PTS file measurement database - */ -static pts_database_t *pts_db; - -/** - * PTS credentials - */ -static pts_creds_t *pts_creds; - -/** - * PTS credential manager - */ -static credential_manager_t *pts_credmgr; - -/** - * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, - TNC_Version min_version, - TNC_Version max_version, - TNC_Version *actual_version) -{ - char *hash_alg, *dh_group, *cadir; - - if (imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); - return TNC_RESULT_ALREADY_INITIALIZED; - } - if (!pts_meas_algo_probe(&supported_algorithms) || - !pts_dh_group_probe(&supported_dh_groups)) - { - return TNC_RESULT_FATAL; - } - imv_attestation = imv_agent_create(imv_name, msg_types, countof(msg_types), - imv_id, actual_version); - if (!imv_attestation) - { - return TNC_RESULT_FATAL; - } - - libpts_init(); - - 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; - } - - hash_alg = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-attestation.hash_algorithm", "sha256"); - dh_group = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-attestation.dh_group", "ecp256"); - - if (!pts_meas_algo_update(hash_alg, &supported_algorithms) || - !pts_dh_group_update(dh_group, &supported_dh_groups)) - { - return TNC_RESULT_FATAL; - } - - /* create a PTS credential manager */ - pts_credmgr = credential_manager_create(); - - /* create PTS credential set */ - cadir = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-attestation.cadir", NULL); - pts_creds = pts_creds_create(cadir); - if (pts_creds) - { - pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds)); - } - - /* attach PTS database co-located with IMV database */ - pts_db = pts_database_create(imcv_db); - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_ConnectionState new_state) -{ - imv_state_t *state; - - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - switch (new_state) - { - case TNC_CONNECTION_STATE_CREATE: - state = imv_attestation_state_create(connection_id); - return imv_attestation->create_state(imv_attestation, state); - case TNC_CONNECTION_STATE_DELETE: - return imv_attestation->delete_state(imv_attestation, connection_id); - case TNC_CONNECTION_STATE_HANDSHAKE: - default: - return imv_attestation->change_state(imv_attestation, connection_id, - new_state, NULL); - } -} - -static TNC_Result send_message(imv_state_t *state, imv_msg_t *out_msg) -{ - imv_attestation_state_t *attestation_state; - TNC_Result result; - - attestation_state = (imv_attestation_state_t*)state; - - if (imv_attestation_build(out_msg, attestation_state, supported_algorithms, - supported_dh_groups, pts_db)) - { - result = out_msg->send(out_msg, TRUE); - } - else - { - result = TNC_RESULT_FATAL; - } - - return result; -} - -static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) -{ - imv_attestation_state_t *attestation_state; - imv_msg_t *out_msg; - enumerator_t *enumerator; - pa_tnc_attr_t *attr; - pen_type_t type; - TNC_Result result; - pts_t *pts; - chunk_t os_name = chunk_empty; - chunk_t os_version = chunk_empty; - bool fatal_error = FALSE; +/* include generic TGC TNC IF-IMV API code below */ - /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } +#include - attestation_state = (imv_attestation_state_t*)state; - pts = attestation_state->get_pts(attestation_state); - - out_msg = imv_msg_create_as_reply(in_msg); - out_msg->set_msg_type(out_msg, msg_types[0]); - - /* analyze PA-TNC attributes */ - enumerator = in_msg->create_attribute_enumerator(in_msg); - while (enumerator->enumerate(enumerator, &attr)) - { - type = attr->get_type(attr); - - if (type.vendor_id == PEN_IETF) - { - switch (type.type) - { - case IETF_ATTR_PA_TNC_ERROR: - { - ietf_attr_pa_tnc_error_t *error_attr; - pen_type_t error_code; - chunk_t msg_info; - - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_code = error_attr->get_error_code(error_attr); - - if (error_code.vendor_id == PEN_TCG) - { - msg_info = error_attr->get_msg_info(error_attr); - - DBG1(DBG_IMV, "received TCG-PTS error '%N'", - pts_error_code_names, error_code.type); - DBG1(DBG_IMV, "error information: %B", &msg_info); - - result = TNC_RESULT_FATAL; - } - break; - } - case IETF_ATTR_PRODUCT_INFORMATION: - { - ietf_attr_product_info_t *attr_cast; - - attr_cast = (ietf_attr_product_info_t*)attr; - os_name = attr_cast->get_info(attr_cast, NULL, NULL); - break; - } - case IETF_ATTR_STRING_VERSION: - { - ietf_attr_string_version_t *attr_cast; - - attr_cast = (ietf_attr_string_version_t*)attr; - os_version = attr_cast->get_version(attr_cast, NULL, NULL); - break; - } - default: - break; - } - } - else if (type.vendor_id == PEN_TCG) - { - if (!imv_attestation_process(attr, out_msg, attestation_state, - supported_algorithms,supported_dh_groups, pts_db, pts_credmgr)) - { - result = TNC_RESULT_FATAL; - break; - } - } - } - enumerator->destroy(enumerator); - - if (os_name.len && os_version.len) - { - pts->set_platform_info(pts, os_name, os_version); - } - - if (fatal_error || result != TNC_RESULT_SUCCESS) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, - TNC_IMV_EVALUATION_RESULT_ERROR); - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return imv_attestation->provide_recommendation(imv_attestation, state); - } - - /* send PA-TNC message with excl flag set */ - result = out_msg->send(out_msg, TRUE); - - if (result != TNC_RESULT_SUCCESS) - { - out_msg->destroy(out_msg); - return result; - } - - /* check the IMV state for the next PA-TNC attributes to send */ - result = send_message(state, out_msg); - - if (result != TNC_RESULT_SUCCESS) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, - TNC_IMV_EVALUATION_RESULT_ERROR); - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return imv_attestation->provide_recommendation(imv_attestation, state); - } - - if (attestation_state->get_handshake_state(attestation_state) == - IMV_ATTESTATION_STATE_END) - { - if (attestation_state->get_file_meas_request_count(attestation_state)) - { - DBG1(DBG_IMV, "failure due to %d pending file measurements", - attestation_state->get_file_meas_request_count(attestation_state)); - attestation_state->set_measurement_error(attestation_state, - IMV_ATTESTATION_ERROR_FILE_MEAS_PEND); - } - if (attestation_state->get_measurement_error(attestation_state)) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, - TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); - } - else - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_ALLOW, - TNC_IMV_EVALUATION_RESULT_COMPLIANT); - } - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return imv_attestation->provide_recommendation(imv_attestation, state); - } - out_msg->destroy(out_msg); - - return result; -} - -/** - * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_MessageType msg_type) -{ - imv_state_t *state; - imv_msg_t *in_msg; - TNC_Result result; - - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - in_msg = imv_msg_create_from_data(imv_attestation, state, connection_id, - msg_type, chunk_create(msg, msg_len)); - result = receive_message(state, in_msg); - in_msg->destroy(in_msg); - - return result; -} - -/** - * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id, - TNC_ConnectionID connection_id, - TNC_UInt32 msg_flags, - TNC_BufferReference msg, - TNC_UInt32 msg_len, - TNC_VendorID msg_vid, - TNC_MessageSubtype msg_subtype, - TNC_UInt32 src_imc_id, - TNC_UInt32 dst_imv_id) -{ - imv_state_t *state; - imv_msg_t *in_msg; - TNC_Result result; - - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - in_msg = imv_msg_create_from_long_data(imv_attestation, state, connection_id, - src_imc_id, dst_imv_id, msg_vid, msg_subtype, - chunk_create(msg, msg_len)); - result =receive_message(state, in_msg); - in_msg->destroy(in_msg); - - return result; -} - -/** - * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - imv_state_t *state; - - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) - { - return TNC_RESULT_FATAL; - } - return imv_attestation->provide_recommendation(imv_attestation, state); -} - -/** - * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, - TNC_ConnectionID connection_id) -{ - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return TNC_RESULT_SUCCESS; -} - -/** - * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) -{ - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - if (pts_creds) - { - pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds)); - pts_creds->destroy(pts_creds); - } - DESTROY_IF(pts_db); - pts_db = NULL; - DESTROY_IF(pts_credmgr); - pts_credmgr = NULL; - - libpts_deinit(); - - imv_attestation->destroy(imv_attestation); - imv_attestation = NULL; - - return TNC_RESULT_SUCCESS; -} - -/** - * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3 - */ -TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id, - TNC_TNCS_BindFunctionPointer bind_function) -{ - if (!imv_attestation) - { - DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); - return TNC_RESULT_NOT_INITIALIZED; - } - return imv_attestation->bind_functions(imv_attestation, bind_function); -} diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_agent.c b/src/libpts/plugins/imv_attestation/imv_attestation_agent.c new file mode 100644 index 0000000000..5eabf7b362 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/imv_attestation_agent.c @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2011-2013 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 . + * + * 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_attestation_agent.h" +#include "imv_attestation_state.h" +#include "imv_attestation_process.h" +#include "imv_attestation_build.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +typedef struct private_imv_attestation_agent_t private_imv_attestation_agent_t; + +/* Subscribed PA-TNC message subtypes */ +static pen_type_t msg_types[] = { + { PEN_TCG, PA_SUBTYPE_TCG_PTS }, + { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM } +}; + +/** + * Private data of an imv_attestation_agent_t object. + */ +struct private_imv_attestation_agent_t { + + /** + * Public members of imv_attestation_agent_t + */ + imv_agent_if_t public; + + /** + * IMV agent responsible for generic functions + */ + imv_agent_t *agent; + + /** + * Supported PTS measurement algorithms + */ + pts_meas_algorithms_t supported_algorithms; + + /** + * Supported PTS Diffie Hellman Groups + */ + pts_dh_group_t supported_dh_groups; + + /** + * PTS file measurement database + */ + pts_database_t *pts_db; + + /** + * PTS credentials + */ + pts_creds_t *pts_creds; + + /** + * PTS credential manager + */ + credential_manager_t *pts_credmgr; + +}; + +METHOD(imv_agent_if_t, bind_functions, TNC_Result, + private_imv_attestation_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function) +{ + return this->agent->bind_functions(this->agent, bind_function); +} + +METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id, + TNC_ConnectionState new_state) +{ + imv_state_t *state; + + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imv_attestation_state_create(id); + return this->agent->create_state(this->agent, state); + case TNC_CONNECTION_STATE_DELETE: + return this->agent->delete_state(this->agent, id); + default: + return this->agent->change_state(this->agent, id, new_state, NULL); + } +} + +/** + * Build a message to be sent + */ +static TNC_Result send_message(private_imv_attestation_agent_t *this, + imv_state_t *state, imv_msg_t *out_msg) +{ + imv_attestation_state_t *attestation_state; + TNC_Result result; + + attestation_state = (imv_attestation_state_t*)state; + + if (imv_attestation_build(out_msg, attestation_state, + this->supported_algorithms, + this->supported_dh_groups, this->pts_db)) + { + result = out_msg->send(out_msg, TRUE); + } + else + { + result = TNC_RESULT_FATAL; + } + + return result; +} + +/** + * Process a received message + */ +static TNC_Result receive_msg(private_imv_attestation_agent_t *this, + imv_state_t *state, imv_msg_t *in_msg) +{ + imv_attestation_state_t *attestation_state; + imv_msg_t *out_msg; + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + pen_type_t type; + TNC_Result result; + pts_t *pts; + chunk_t os_name = chunk_empty; + chunk_t os_version = chunk_empty; + bool fatal_error = FALSE; + + /* parse received PA-TNC message and handle local and remote errors */ + result = in_msg->receive(in_msg, &fatal_error); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + + attestation_state = (imv_attestation_state_t*)state; + pts = attestation_state->get_pts(attestation_state); + + out_msg = imv_msg_create_as_reply(in_msg); + out_msg->set_msg_type(out_msg, msg_types[0]); + + /* analyze PA-TNC attributes */ + enumerator = in_msg->create_attribute_enumerator(in_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF) + { + switch (type.type) + { + case IETF_ATTR_PA_TNC_ERROR: + { + ietf_attr_pa_tnc_error_t *error_attr; + pen_type_t error_code; + chunk_t msg_info; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; + error_code = error_attr->get_error_code(error_attr); + + if (error_code.vendor_id == PEN_TCG) + { + msg_info = error_attr->get_msg_info(error_attr); + + DBG1(DBG_IMV, "received TCG-PTS error '%N'", + pts_error_code_names, error_code.type); + DBG1(DBG_IMV, "error information: %B", &msg_info); + + result = TNC_RESULT_FATAL; + } + break; + } + case IETF_ATTR_PRODUCT_INFORMATION: + { + ietf_attr_product_info_t *attr_cast; + + attr_cast = (ietf_attr_product_info_t*)attr; + os_name = attr_cast->get_info(attr_cast, NULL, NULL); + break; + } + case IETF_ATTR_STRING_VERSION: + { + ietf_attr_string_version_t *attr_cast; + + attr_cast = (ietf_attr_string_version_t*)attr; + os_version = attr_cast->get_version(attr_cast, NULL, NULL); + break; + } + default: + break; + } + } + else if (type.vendor_id == PEN_TCG) + { + if (!imv_attestation_process(attr, out_msg, attestation_state, + this->supported_algorithms, this->supported_dh_groups, + this->pts_db, this->pts_credmgr)) + { + result = TNC_RESULT_FATAL; + break; + } + } + } + enumerator->destroy(enumerator); + + if (os_name.len && os_version.len) + { + pts->set_platform_info(pts, os_name, os_version); + } + + if (fatal_error || result != TNC_RESULT_SUCCESS) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + /* send PA-TNC message with excl flag set */ + result = out_msg->send(out_msg, TRUE); + + if (result != TNC_RESULT_SUCCESS) + { + out_msg->destroy(out_msg); + return result; + } + + /* check the IMV state for the next PA-TNC attributes to send */ + result = send_message(this, state, out_msg); + + if (result != TNC_RESULT_SUCCESS) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + if (attestation_state->get_handshake_state(attestation_state) == + IMV_ATTESTATION_STATE_END) + { + if (attestation_state->get_file_meas_request_count(attestation_state)) + { + DBG1(DBG_IMV, "failure due to %d pending file measurements", + attestation_state->get_file_meas_request_count(attestation_state)); + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_FILE_MEAS_PEND); + } + if (attestation_state->get_measurement_error(attestation_state)) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, + TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); + } + else + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_COMPLIANT); + } + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + out_msg->destroy(out_msg); + + return result; + +} + +METHOD(imv_agent_if_t, receive_message, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id, + TNC_MessageType msg_type, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +METHOD(imv_agent_if_t, receive_message_long, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, + TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_long_data(this->agent, state, id, + src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; + +} + +METHOD(imv_agent_if_t, batch_ending, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id) +{ + return TNC_RESULT_SUCCESS; +} + +METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id) +{ + imv_state_t *state; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + return this->agent->provide_recommendation(this->agent, state); +} + +METHOD(imv_agent_if_t, destroy, void, + private_imv_attestation_agent_t *this) +{ + if (this->pts_creds) + { + this->pts_credmgr->remove_set(this->pts_credmgr, + this->pts_creds->get_set(this->pts_creds)); + this->pts_creds->destroy(this->pts_creds); + } + DESTROY_IF(this->pts_db); + DESTROY_IF(this->pts_credmgr); + this->agent->destroy(this->agent); + free(this); + libpts_deinit(); +} + +/** + * Described in header. + */ +imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id, + TNC_Version *actual_version) +{ + private_imv_attestation_agent_t *this; + char *hash_alg, *dh_group, *cadir; + + hash_alg = lib->settings->get_str(lib->settings, + "libimcv.plugins.imv-attestation.hash_algorithm", "sha256"); + dh_group = lib->settings->get_str(lib->settings, + "libimcv.plugins.imv-attestation.dh_group", "ecp256"); + cadir = lib->settings->get_str(lib->settings, + "libimcv.plugins.imv-attestation.cadir", NULL); + libpts_init(); + + INIT(this, + .public = { + .bind_functions = _bind_functions, + .notify_connection_change = _notify_connection_change, + .receive_message = _receive_message, + .receive_message_long = _receive_message_long, + .batch_ending = _batch_ending, + .solicit_recommendation = _solicit_recommendation, + .destroy = _destroy, + }, + .agent = imv_agent_create(name, msg_types, countof(msg_types), id, + actual_version), + .supported_algorithms = PTS_MEAS_ALGO_NONE, + .supported_dh_groups = PTS_DH_GROUP_NONE, + .pts_credmgr = credential_manager_create(), + .pts_creds = pts_creds_create(cadir), + .pts_db = pts_database_create(imcv_db), + ); + + if (!this->agent || + !pts_meas_algo_update(hash_alg, &this->supported_algorithms) || + !pts_dh_group_update(dh_group, &this->supported_dh_groups)) + { + destroy(this); + return NULL; + } + + if (this->pts_creds) + { + this->pts_credmgr->add_set(this->pts_credmgr, + this->pts_creds->get_set(this->pts_creds)); + } + + return &this->public; +} + diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_agent.h b/src/libpts/plugins/imv_attestation/imv_attestation_agent.h new file mode 100644 index 0000000000..cc421a29a4 --- /dev/null +++ b/src/libpts/plugins/imv_attestation/imv_attestation_agent.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 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 . + * + * 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_attestation_agent_t imv_attestation_agent + * @{ @ingroup imv_attestation + */ + +#ifndef IMV_ATTESTATION_AGENT_H_ +#define IMV_ATTESTATION_AGENT_H_ + +#include + +/** + * Creates a Attestation IMV agent + * + * @param name Name of the IMV + * @param id ID of the IMV + * @param actual_version TNC IF-IMV version + */ +imv_agent_if_t* imv_attestation_agent_create(const char* name, TNC_IMVID id, + TNC_Version *actual_version); + +#endif /** IMV_ATTESTATION_AGENT_H_ @}*/