diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2015-04-11 22:03:59 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2015-04-11 22:30:17 +0200 |
commit | 8404fb0212f9fb77bc53b23004b829b488430700 (patch) | |
tree | 23876c7540d138f58a6a7d90793ccf9004f6afd2 /src/libtnccs | |
parent | 1b7c683a32c62b6e08ad7bf5af39b9f4edd634f3 (diff) | |
download | vyos-strongswan-8404fb0212f9fb77bc53b23004b829b488430700.tar.gz vyos-strongswan-8404fb0212f9fb77bc53b23004b829b488430700.zip |
Imported Upstream version 5.3.0
Diffstat (limited to 'src/libtnccs')
41 files changed, 2714 insertions, 882 deletions
diff --git a/src/libtnccs/Android.mk b/src/libtnccs/Android.mk index 68f85c252..e37973202 100644 --- a/src/libtnccs/Android.mk +++ b/src/libtnccs/Android.mk @@ -22,7 +22,7 @@ endif LOCAL_SRC_FILES += $(call add_plugin, tnc-tnccs) LOCAL_SRC_FILES += $(call add_plugin, tnccs-20) -LOCAL_SRC_FILES += $(call add_plugin_subdirs, tnccs-20, batch messages messages/ietf messages/tcg state_machine) +LOCAL_SRC_FILES += $(call add_plugin_subdirs, tnccs-20, batch messages messages/ietf messages/ita messages/tcg state_machine) ifneq ($(call plugin_enabled, tnccs-20),) LOCAL_C_INCLUDES += $(LOCAL_PATH)/plugins/tnccs_20/ endif diff --git a/src/libtnccs/Makefile.in b/src/libtnccs/Makefile.in index b0bfdf20d..dc8c1b8cc 100644 --- a/src/libtnccs/Makefile.in +++ b/src/libtnccs/Makefile.in @@ -283,6 +283,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -343,10 +344,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -420,6 +423,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ diff --git a/src/libtnccs/plugins/tnc_imc/Makefile.in b/src/libtnccs/plugins/tnc_imc/Makefile.in index 2b76aabe6..3641bdf5b 100644 --- a/src/libtnccs/plugins/tnc_imc/Makefile.in +++ b/src/libtnccs/plugins/tnc_imc/Makefile.in @@ -231,6 +231,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -291,10 +292,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -368,6 +371,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c index 859dded79..ce5b48133 100644 --- a/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c +++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.c @@ -44,6 +44,7 @@ METHOD(plugin_t, get_features, int, PLUGIN_CALLBACK(tnc_manager_register, tnc_imc_manager_create), PLUGIN_PROVIDE(CUSTOM, "imc-manager"), PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), + PLUGIN_SDEPEND(CUSTOM, "imv-manager"), PLUGIN_SDEPEND(CERT_DECODE, CERT_X509), PLUGIN_SDEPEND(CERT_DECODE, CERT_TRUSTED_PUBKEY), }; diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h index 8c5521cb2..8cbc70367 100644 --- a/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h +++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_plugin.h @@ -15,7 +15,7 @@ /** * @defgroup tnc_imc tnc_imc - * @ingroup cplugins + * @ingroup tplugins * * @defgroup tnc_imc_plugin tnc_imc_plugin * @{ @ingroup tnc_imc diff --git a/src/libtnccs/plugins/tnc_imv/Makefile.in b/src/libtnccs/plugins/tnc_imv/Makefile.in index 06e7b0480..c4b1bee23 100644 --- a/src/libtnccs/plugins/tnc_imv/Makefile.in +++ b/src/libtnccs/plugins/tnc_imv/Makefile.in @@ -232,6 +232,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -292,10 +293,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -369,6 +372,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ diff --git a/src/libtnccs/plugins/tnc_imv/tnc_imv_plugin.h b/src/libtnccs/plugins/tnc_imv/tnc_imv_plugin.h index afeee2ea2..5786bbaab 100644 --- a/src/libtnccs/plugins/tnc_imv/tnc_imv_plugin.h +++ b/src/libtnccs/plugins/tnc_imv/tnc_imv_plugin.h @@ -15,7 +15,7 @@ /** * @defgroup tnc_imv tnc_imv - * @ingroup cplugins + * @ingroup tplugins * * @defgroup tnc_imv_plugin tnc_imv_plugin * @{ @ingroup tnc_imv diff --git a/src/libtnccs/plugins/tnc_tnccs/Makefile.in b/src/libtnccs/plugins/tnc_tnccs/Makefile.in index 8910fe761..5b01e317a 100644 --- a/src/libtnccs/plugins/tnc_tnccs/Makefile.in +++ b/src/libtnccs/plugins/tnc_tnccs/Makefile.in @@ -231,6 +231,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -291,10 +292,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -368,6 +371,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ diff --git a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c index b8683f78c..30e505246 100644 --- a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c +++ b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -169,8 +169,8 @@ METHOD(tnccs_manager_t, remove_method, void, METHOD(tnccs_manager_t, create_instance, tnccs_t*, private_tnc_tnccs_manager_t *this, tnccs_type_t type, bool is_server, - identification_t *server, identification_t *peer, tnc_ift_type_t transport, - tnccs_cb_t cb) + identification_t *server_id, identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, tnccs_cb_t cb) { enumerator_t *enumerator; tnccs_entry_t *entry; @@ -182,7 +182,8 @@ METHOD(tnccs_manager_t, create_instance, tnccs_t*, { if (type == entry->type) { - protocol = entry->constructor(is_server, server, peer, transport, cb); + protocol = entry->constructor(is_server, server_id, peer_id, + server_ip, peer_ip, transport, cb); if (protocol) { break; @@ -716,7 +717,8 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, case TNC_ATTRIBUTEID_AR_IDENTITIES: { linked_list_t *list; - identification_t *peer; + identification_t *peer_id; + host_t *peer_ip; tnccs_t *tnccs; tncif_identity_t *tnc_id; u_int32_t id_type, subject_type; @@ -726,10 +728,11 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, list = linked_list_create(); tnccs = entry->tnccs; - peer = tnccs->tls.get_peer_id(&tnccs->tls); - if (peer) + + peer_id = tnccs->tls.get_peer_id(&tnccs->tls); + if (peer_id) { - switch (peer->get_type(peer)) + switch (peer_id->get_type(peer_id)) { case ID_IPV4_ADDR: id_type = TNC_ID_IPV4_ADDR; @@ -756,7 +759,7 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, subject_type = TNC_SUBJECT_UNKNOWN; } if (id_type != TNC_ID_UNKNOWN && - asprintf(&id_str, "%Y", peer) >= 0) + asprintf(&id_str, "%Y", peer_id) >= 0) { id_value = chunk_from_str(id_str); tnc_id = tncif_identity_create( @@ -767,6 +770,33 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, list->insert_last(list, tnc_id); } } + + peer_ip = tnccs->get_peer_ip(tnccs); + if (peer_ip) + { + switch (peer_ip->get_family(peer_ip)) + { + case AF_INET: + id_type = TNC_ID_IPV4_ADDR; + break; + case AF_INET6: + id_type = TNC_ID_IPV6_ADDR; + break; + default: + id_type = TNC_ID_UNKNOWN; + } + + if (id_type != TNC_ID_UNKNOWN && + asprintf(&id_str, "%H", peer_ip) >= 0) + { + id_value = chunk_from_str(id_str); + tnc_id = tncif_identity_create( + pen_type_create(PEN_TCG, id_type), id_value, + pen_type_create(PEN_TCG, TNC_SUBJECT_MACHINE), + pen_type_create(PEN_TCG, TNC_AUTH_UNKNOWN)); + list->insert_last(list, tnc_id); + } + } result = identity_attribute(buffer_len, buffer, value_len, list); list->destroy_offset(list, offsetof(tncif_identity_t, destroy)); return result; diff --git a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h index f935fa462..c99d5e7c8 100644 --- a/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h +++ b/src/libtnccs/plugins/tnc_tnccs/tnc_tnccs_plugin.h @@ -15,7 +15,7 @@ /** * @defgroup tnc_tnccs tnc_tnccs - * @ingroup cplugins + * @ingroup tplugins * * @defgroup tnc_tnccs_plugin tnc_tnccs_plugin * @{ @ingroup tnc_tnccs diff --git a/src/libtnccs/plugins/tnccs_11/Makefile.in b/src/libtnccs/plugins/tnccs_11/Makefile.in index ea6ac5546..e0c039af9 100644 --- a/src/libtnccs/plugins/tnccs_11/Makefile.in +++ b/src/libtnccs/plugins/tnccs_11/Makefile.in @@ -241,6 +241,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -301,10 +302,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -378,6 +381,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11.c b/src/libtnccs/plugins/tnccs_11/tnccs_11.c index 28c5e52b7..0918a2bad 100644 --- a/src/libtnccs/plugins/tnccs_11/tnccs_11.c +++ b/src/libtnccs/plugins/tnccs_11/tnccs_11.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -54,12 +54,22 @@ struct private_tnccs_11_t { /** * Server identity */ - identification_t *server; + identification_t *server_id; /** * Client identity */ - identification_t *peer; + identification_t *peer_id; + + /** + * Server IP address + */ + host_t *server_ip; + + /** + * Client IP address + */ + host_t *peer_ip; /** * Underlying TNC IF-T transport protocol @@ -527,20 +537,20 @@ METHOD(tls_t, is_server, bool, METHOD(tls_t, get_server_id, identification_t*, private_tnccs_11_t *this) { - return this->server; + return this->server_id; } METHOD(tls_t, set_peer_id, void, private_tnccs_11_t *this, identification_t *id) { - DESTROY_IF(this->peer); - this->peer = id->clone(id); + DESTROY_IF(this->peer_id); + this->peer_id = id->clone(id); } METHOD(tls_t, get_peer_id, identification_t*, private_tnccs_11_t *this) { - return this->peer; + return this->peer_id; } METHOD(tls_t, get_purpose, tls_purpose_t, @@ -578,14 +588,28 @@ METHOD(tls_t, destroy, void, { tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, this->is_server); - this->server->destroy(this->server); - this->peer->destroy(this->peer); + this->server_id->destroy(this->server_id); + this->peer_id->destroy(this->peer_id); + this->server_ip->destroy(this->server_ip); + this->peer_ip->destroy(this->peer_ip); this->mutex->destroy(this->mutex); DESTROY_IF(this->batch); free(this); } } +METHOD(tnccs_t, get_server_ip, host_t*, + private_tnccs_11_t *this) +{ + return this->server_ip; +} + +METHOD(tnccs_t, get_peer_ip, host_t*, + private_tnccs_11_t *this) +{ + return this->peer_ip; +} + METHOD(tnccs_t, get_transport, tnc_ift_type_t, private_tnccs_11_t *this) { @@ -628,9 +652,10 @@ METHOD(tnccs_t, get_ref, tnccs_t*, /** * See header */ -tnccs_t* tnccs_11_create(bool is_server, - identification_t *server, identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb) +tnccs_t* tnccs_11_create(bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb) { private_tnccs_11_t *this; @@ -648,6 +673,8 @@ tnccs_t* tnccs_11_create(bool is_server, .get_eap_msk = _get_eap_msk, .destroy = _destroy, }, + .get_server_ip = _get_server_ip, + .get_peer_ip = _get_peer_ip, .get_transport = _get_transport, .set_transport = _set_transport, .get_auth_type = _get_auth_type, @@ -656,8 +683,10 @@ tnccs_t* tnccs_11_create(bool is_server, .get_ref = _get_ref, }, .is_server = is_server, - .server = server->clone(server), - .peer = peer->clone(peer), + .server_id = server_id->clone(server_id), + .peer_id = peer_id->clone(peer_id), + .server_ip = server_ip->clone(server_ip), + .peer_ip = peer_ip->clone(peer_ip), .transport = transport, .callback = cb, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11.h b/src/libtnccs/plugins/tnccs_11/tnccs_11.h index e805df8bb..60d5518bc 100644 --- a/src/libtnccs/plugins/tnccs_11/tnccs_11.h +++ b/src/libtnccs/plugins/tnccs_11/tnccs_11.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -29,14 +29,17 @@ * Create an instance of the TNC IF-TNCCS 1.1 protocol handler. * * @param is_server TRUE to act as TNC Server, FALSE for TNC Client - * @param server Server identity - * @param peer Client identity + * @param server_id Server identity + * @param peer_id Client identity + * @param server_ip Server IP address + * @param peer_ip Client IP address * @param transport Underlying IF-T transport protocol * @param cb Callback function if TNC Server, NULL if TNC Client * @return TNC_IF_TNCCS 1.1 protocol stack */ -tnccs_t* tnccs_11_create(bool is_server, - identification_t *server, identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb); +tnccs_t* tnccs_11_create(bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb); #endif /** TNCCS_11_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h index 619a073ad..73ea5759b 100644 --- a/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h +++ b/src/libtnccs/plugins/tnccs_11/tnccs_11_plugin.h @@ -15,7 +15,7 @@ /** * @defgroup tnccs_11 tnccs_11 - * @ingroup cplugins + * @ingroup tplugins * * @defgroup tnccs_11_plugin tnccs_11_plugin * @{ @ingroup tnccs_11 diff --git a/src/libtnccs/plugins/tnccs_20/Makefile.am b/src/libtnccs/plugins/tnccs_20/Makefile.am index 2aefecd26..7d1cdded1 100644 --- a/src/libtnccs/plugins/tnccs_20/Makefile.am +++ b/src/libtnccs/plugins/tnccs_20/Makefile.am @@ -18,6 +18,8 @@ endif libstrongswan_tnccs_20_la_SOURCES = \ tnccs_20_plugin.h tnccs_20_plugin.c tnccs_20.h tnccs_20.c \ + tnccs_20_handler.h \ + tnccs_20_server.h tnccs_20_server.c tnccs_20_client.h tnccs_20_client.c \ batch/pb_tnc_batch.h batch/pb_tnc_batch.c \ messages/pb_tnc_msg.h messages/pb_tnc_msg.c \ messages/ietf/pb_experimental_msg.h messages/ietf/pb_experimental_msg.c \ @@ -28,6 +30,8 @@ libstrongswan_tnccs_20_la_SOURCES = \ messages/ietf/pb_language_preference_msg.h messages/ietf/pb_language_preference_msg.c \ messages/ietf/pb_reason_string_msg.h messages/ietf/pb_reason_string_msg.c \ messages/ietf/pb_remediation_parameters_msg.h messages/ietf/pb_remediation_parameters_msg.c \ + messages/ita/pb_mutual_capability_msg.h messages/ita/pb_mutual_capability_msg.c \ + messages/ita/pb_noskip_test_msg.h messages/ita/pb_noskip_test_msg.c \ messages/tcg/pb_pdp_referral_msg.h messages/tcg/pb_pdp_referral_msg.c \ state_machine/pb_tnc_state_machine.h state_machine/pb_tnc_state_machine.c diff --git a/src/libtnccs/plugins/tnccs_20/Makefile.in b/src/libtnccs/plugins/tnccs_20/Makefile.in index 90c804710..17d997f76 100644 --- a/src/libtnccs/plugins/tnccs_20/Makefile.in +++ b/src/libtnccs/plugins/tnccs_20/Makefile.in @@ -132,8 +132,8 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) @MONOLITHIC_FALSE@ $(top_builddir)/src/libtnccs/libtnccs.la am__dirstamp = $(am__leading_dot)dirstamp am_libstrongswan_tnccs_20_la_OBJECTS = tnccs_20_plugin.lo tnccs_20.lo \ - batch/pb_tnc_batch.lo messages/pb_tnc_msg.lo \ - messages/ietf/pb_experimental_msg.lo \ + tnccs_20_server.lo tnccs_20_client.lo batch/pb_tnc_batch.lo \ + messages/pb_tnc_msg.lo messages/ietf/pb_experimental_msg.lo \ messages/ietf/pb_pa_msg.lo \ messages/ietf/pb_assessment_result_msg.lo \ messages/ietf/pb_access_recommendation_msg.lo \ @@ -141,6 +141,8 @@ am_libstrongswan_tnccs_20_la_OBJECTS = tnccs_20_plugin.lo tnccs_20.lo \ messages/ietf/pb_language_preference_msg.lo \ messages/ietf/pb_reason_string_msg.lo \ messages/ietf/pb_remediation_parameters_msg.lo \ + messages/ita/pb_mutual_capability_msg.lo \ + messages/ita/pb_noskip_test_msg.lo \ messages/tcg/pb_pdp_referral_msg.lo \ state_machine/pb_tnc_state_machine.lo libstrongswan_tnccs_20_la_OBJECTS = \ @@ -242,6 +244,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -302,10 +305,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -379,6 +384,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ @@ -454,6 +461,8 @@ AM_CFLAGS = \ libstrongswan_tnccs_20_la_SOURCES = \ tnccs_20_plugin.h tnccs_20_plugin.c tnccs_20.h tnccs_20.c \ + tnccs_20_handler.h \ + tnccs_20_server.h tnccs_20_server.c tnccs_20_client.h tnccs_20_client.c \ batch/pb_tnc_batch.h batch/pb_tnc_batch.c \ messages/pb_tnc_msg.h messages/pb_tnc_msg.c \ messages/ietf/pb_experimental_msg.h messages/ietf/pb_experimental_msg.c \ @@ -464,6 +473,8 @@ libstrongswan_tnccs_20_la_SOURCES = \ messages/ietf/pb_language_preference_msg.h messages/ietf/pb_language_preference_msg.c \ messages/ietf/pb_reason_string_msg.h messages/ietf/pb_reason_string_msg.c \ messages/ietf/pb_remediation_parameters_msg.h messages/ietf/pb_remediation_parameters_msg.c \ + messages/ita/pb_mutual_capability_msg.h messages/ita/pb_mutual_capability_msg.c \ + messages/ita/pb_noskip_test_msg.h messages/ita/pb_noskip_test_msg.c \ messages/tcg/pb_pdp_referral_msg.h messages/tcg/pb_pdp_referral_msg.c \ state_machine/pb_tnc_state_machine.h state_machine/pb_tnc_state_machine.c @@ -590,6 +601,17 @@ messages/ietf/pb_reason_string_msg.lo: messages/ietf/$(am__dirstamp) \ messages/ietf/pb_remediation_parameters_msg.lo: \ messages/ietf/$(am__dirstamp) \ messages/ietf/$(DEPDIR)/$(am__dirstamp) +messages/ita/$(am__dirstamp): + @$(MKDIR_P) messages/ita + @: > messages/ita/$(am__dirstamp) +messages/ita/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) messages/ita/$(DEPDIR) + @: > messages/ita/$(DEPDIR)/$(am__dirstamp) +messages/ita/pb_mutual_capability_msg.lo: \ + messages/ita/$(am__dirstamp) \ + messages/ita/$(DEPDIR)/$(am__dirstamp) +messages/ita/pb_noskip_test_msg.lo: messages/ita/$(am__dirstamp) \ + messages/ita/$(DEPDIR)/$(am__dirstamp) messages/tcg/$(am__dirstamp): @$(MKDIR_P) messages/tcg @: > messages/tcg/$(am__dirstamp) @@ -618,6 +640,8 @@ mostlyclean-compile: -rm -f messages/*.lo -rm -f messages/ietf/*.$(OBJEXT) -rm -f messages/ietf/*.lo + -rm -f messages/ita/*.$(OBJEXT) + -rm -f messages/ita/*.lo -rm -f messages/tcg/*.$(OBJEXT) -rm -f messages/tcg/*.lo -rm -f state_machine/*.$(OBJEXT) @@ -627,7 +651,9 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnccs_20.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnccs_20_client.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnccs_20_plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tnccs_20_server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@batch/$(DEPDIR)/pb_tnc_batch.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@messages/$(DEPDIR)/pb_tnc_msg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@messages/ietf/$(DEPDIR)/pb_access_recommendation_msg.Plo@am__quote@ @@ -638,6 +664,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@messages/ietf/$(DEPDIR)/pb_pa_msg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@messages/ietf/$(DEPDIR)/pb_reason_string_msg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@messages/ietf/$(DEPDIR)/pb_remediation_parameters_msg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@messages/ita/$(DEPDIR)/pb_mutual_capability_msg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@messages/ita/$(DEPDIR)/pb_noskip_test_msg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@messages/tcg/$(DEPDIR)/pb_pdp_referral_msg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@state_machine/$(DEPDIR)/pb_tnc_state_machine.Plo@am__quote@ @@ -673,6 +701,7 @@ clean-libtool: -rm -rf batch/.libs batch/_libs -rm -rf messages/.libs messages/_libs -rm -rf messages/ietf/.libs messages/ietf/_libs + -rm -rf messages/ita/.libs messages/ita/_libs -rm -rf messages/tcg/.libs messages/tcg/_libs -rm -rf state_machine/.libs state_machine/_libs @@ -797,6 +826,8 @@ distclean-generic: -rm -f messages/$(am__dirstamp) -rm -f messages/ietf/$(DEPDIR)/$(am__dirstamp) -rm -f messages/ietf/$(am__dirstamp) + -rm -f messages/ita/$(DEPDIR)/$(am__dirstamp) + -rm -f messages/ita/$(am__dirstamp) -rm -f messages/tcg/$(DEPDIR)/$(am__dirstamp) -rm -f messages/tcg/$(am__dirstamp) -rm -f state_machine/$(DEPDIR)/$(am__dirstamp) @@ -811,7 +842,7 @@ clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ clean-pluginLTLIBRARIES mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) batch/$(DEPDIR) messages/$(DEPDIR) messages/ietf/$(DEPDIR) messages/tcg/$(DEPDIR) state_machine/$(DEPDIR) + -rm -rf ./$(DEPDIR) batch/$(DEPDIR) messages/$(DEPDIR) messages/ietf/$(DEPDIR) messages/ita/$(DEPDIR) messages/tcg/$(DEPDIR) state_machine/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -857,7 +888,7 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) batch/$(DEPDIR) messages/$(DEPDIR) messages/ietf/$(DEPDIR) messages/tcg/$(DEPDIR) state_machine/$(DEPDIR) + -rm -rf ./$(DEPDIR) batch/$(DEPDIR) messages/$(DEPDIR) messages/ietf/$(DEPDIR) messages/ita/$(DEPDIR) messages/tcg/$(DEPDIR) state_machine/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c index 228c08255..faad02b9b 100644 --- a/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c +++ b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Sansar Choinyanbuu - * Copyright (C) 2010-2012 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -85,7 +85,7 @@ struct private_pb_tnc_batch_t { pb_tnc_batch_t public; /** - * TNCC if TRUE, TNCS if FALSE + * from TNC server if TRUE, from TNC client if FALSE */ bool is_server; @@ -166,6 +166,9 @@ METHOD(pb_tnc_batch_t, add_msg, bool, case PEN_TCG: msg_type_names = pb_tnc_tcg_msg_type_names; break; + case PEN_ITA: + msg_type_names = pb_tnc_ita_msg_type_names; + break; } DBG2(DBG_TNC, "adding %N/%N message", pen_names, msg_type.vendor_id, msg_type_names, msg_type.type); @@ -176,6 +179,7 @@ METHOD(pb_tnc_batch_t, add_msg, bool, METHOD(pb_tnc_batch_t, build, void, private_pb_tnc_batch_t *this) { + u_int8_t version; u_int32_t msg_len; chunk_t msg_value; enumerator_t *enumerator; @@ -184,9 +188,14 @@ METHOD(pb_tnc_batch_t, build, void, pb_tnc_msg_info_t *msg_infos; bio_writer_t *writer; + /* Set wrong PB-TNC version for testing purposes to force a PB-TNC error */ + version = lib->settings->get_int(lib->settings, + "%s.plugins.tnccs-20.tests.pb_tnc_version", + PB_TNC_VERSION, lib->ns); + /* build PB-TNC batch header */ writer = bio_writer_create(this->batch_len); - writer->write_uint8 (writer, PB_TNC_VERSION); + writer->write_uint8 (writer, version); writer->write_uint8 (writer, this->is_server ? PB_TNC_BATCH_FLAG_D : PB_TNC_BATCH_FLAG_NONE); writer->write_uint16(writer, this->type); @@ -211,6 +220,9 @@ METHOD(pb_tnc_batch_t, build, void, case PEN_TCG: msg_infos = pb_tnc_tcg_msg_infos; break; + case PEN_ITA: + msg_infos = pb_tnc_ita_msg_infos; + break; } if (msg_infos[msg_type.type].has_noskip_flag) { @@ -228,15 +240,15 @@ METHOD(pb_tnc_batch_t, build, void, writer->destroy(writer); } -static status_t process_batch_header(private_pb_tnc_batch_t *this, - pb_tnc_state_machine_t *state_machine) +METHOD(pb_tnc_batch_t, process_header, status_t, + private_pb_tnc_batch_t *this, bool directionality, bool is_server, + bool *from_server) { bio_reader_t *reader; pb_tnc_msg_t *msg; pb_error_msg_t *err_msg; u_int8_t version, flags, reserved, type; u_int32_t batch_len; - bool directionality; if (this->encoding.len < PB_TNC_BATCH_HEADER_SIZE) { @@ -267,13 +279,14 @@ static status_t process_batch_header(private_pb_tnc_batch_t *this, } /* Directionality */ - directionality = (flags & PB_TNC_BATCH_FLAG_D) != PB_TNC_BATCH_FLAG_NONE; - if (directionality == this->is_server) + *from_server = (flags & PB_TNC_BATCH_FLAG_D) != PB_TNC_BATCH_FLAG_NONE; + + if (directionality & (*from_server == is_server)) { DBG1(DBG_TNC, "wrong Directionality: batch is from a PB %s", - directionality ? "server" : "client"); + is_server ? "server" : "client"); msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, - PB_ERROR_INVALID_PARAMETER, 1); + PB_ERROR_INVALID_PARAMETER, 1); goto fatal; } @@ -287,17 +300,6 @@ static status_t process_batch_header(private_pb_tnc_batch_t *this, goto fatal; } - if (!state_machine->receive_batch(state_machine, this->type)) - { - DBG1(DBG_TNC, "unexpected PB-TNC batch type: %N", - pb_tnc_batch_type_names, this->type); - msg = pb_error_msg_create(TRUE, PEN_IETF, - PB_ERROR_UNEXPECTED_BATCH_TYPE); - goto fatal; - } - DBG1(DBG_TNC, "processing PB-TNC %N batch", pb_tnc_batch_type_names, - this->type); - /* Batch Length */ if (this->encoding.len != batch_len) { @@ -310,12 +312,6 @@ static status_t process_batch_header(private_pb_tnc_batch_t *this, this->offset = PB_TNC_BATCH_HEADER_SIZE; - /* Register an empty CDATA batch with the state machine */ - if (this->type == PB_BATCH_CDATA) - { - state_machine->set_empty_cdata(state_machine, - this->offset == this->encoding.len); - } return SUCCESS; fatal: @@ -395,11 +391,18 @@ static status_t process_tnc_msg(private_pb_tnc_batch_t *this) msg_type_names = pb_tnc_msg_type_names; msg_infos = pb_tnc_msg_infos; } - else if (vendor_id == PEN_TCG && msg_type <= PB_TCG_MSG_ROOF) + else if (vendor_id == PEN_TCG && msg_type <= PB_TCG_MSG_ROOF && + msg_type > PB_TCG_MSG_RESERVED) { msg_type_names = pb_tnc_tcg_msg_type_names; msg_infos = pb_tnc_tcg_msg_infos; } + else if (vendor_id == PEN_ITA && msg_type <= PB_ITA_MSG_ROOF && + msg_type > PB_ITA_MSG_NOSKIP_TEST) + { + msg_type_names = pb_tnc_ita_msg_type_names; + msg_infos = pb_tnc_ita_msg_infos; + } else { if (msg_len < PB_TNC_MSG_HEADER_SIZE) @@ -413,7 +416,7 @@ static status_t process_tnc_msg(private_pb_tnc_batch_t *this) if (noskip_flag) { - DBG1(DBG_TNC, "reject PB-TNC message 0x%06x/0x%08x)", + DBG1(DBG_TNC, "reject PB-TNC message (0x%06x/0x%08x)", vendor_id, msg_type); msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset); @@ -421,7 +424,7 @@ static status_t process_tnc_msg(private_pb_tnc_batch_t *this) } else { - DBG1(DBG_TNC, "ignore PB-TNC message 0x%06x/0x%08x)", + DBG1(DBG_TNC, "ignore PB-TNC message (0x%06x/0x%08x)", vendor_id, msg_type); this->offset += msg_len; return SUCCESS; @@ -502,14 +505,26 @@ fatal: METHOD(pb_tnc_batch_t, process, status_t, private_pb_tnc_batch_t *this, pb_tnc_state_machine_t *state_machine) { - status_t status; + pb_tnc_msg_t *msg; + status_t status = SUCCESS; - status = process_batch_header(this, state_machine); - if (status != SUCCESS) + if (!state_machine->receive_batch(state_machine, this->type)) { + DBG1(DBG_TNC, "unexpected PB-TNC batch type: %N", + pb_tnc_batch_type_names, this->type); + msg = pb_error_msg_create(TRUE, PEN_IETF, + PB_ERROR_UNEXPECTED_BATCH_TYPE); + this->errors->insert_last(this->errors, msg); return FAILED; } + /* Register an empty CDATA batch with the state machine */ + if (this->type == PB_BATCH_CDATA) + { + state_machine->set_empty_cdata(state_machine, + this->offset == this->encoding.len); + } + while (this->offset < this->encoding.len) { switch (process_tnc_msg(this)) @@ -585,7 +600,7 @@ pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type, /** * See header */ -pb_tnc_batch_t* pb_tnc_batch_create_from_data(bool is_server, chunk_t data) +pb_tnc_batch_t* pb_tnc_batch_create_from_data(chunk_t data) { private_pb_tnc_batch_t *this; @@ -595,12 +610,12 @@ pb_tnc_batch_t* pb_tnc_batch_create_from_data(bool is_server, chunk_t data) .get_encoding = _get_encoding, .add_msg = _add_msg, .build = _build, + .process_header = _process_header, .process = _process, .create_msg_enumerator = _create_msg_enumerator, .create_error_enumerator = _create_error_enumerator, .destroy = _destroy, }, - .is_server = is_server, .messages = linked_list_create(), .errors = linked_list_create(), .encoding = chunk_clone(data), diff --git a/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h index 106c5578c..6089c7d2e 100644 --- a/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h +++ b/src/libtnccs/plugins/tnccs_20/batch/pb_tnc_batch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2012 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -84,10 +84,21 @@ struct pb_tnc_batch_t { void (*build)(pb_tnc_batch_t *this); /** + * Process the PB-TNC Batch header + * + * @param directionality TRUE if no mutual TNC measurements + * @param is_server TRUE if called by TNC server + * @param from_server TRUE if sent by TNC server + * @return return processing status + */ + status_t (*process_header)(pb_tnc_batch_t *this, bool directionality, + bool is_server, bool *from_server); + + /** * Process the PB-TNC Batch * - * @param PB-TNC state machine - * @return return processing status + * @param state_machine PB-TNC state machine + * @return return processing status */ status_t (*process)(pb_tnc_batch_t *this, pb_tnc_state_machine_t *state_machine); @@ -95,14 +106,14 @@ struct pb_tnc_batch_t { /** * Enumerates over all PB-TNC Messages * - * @return return message enumerator + * @return return message enumerator */ enumerator_t* (*create_msg_enumerator)(pb_tnc_batch_t *this); /** * Enumerates over all parsing errors * - * @return return error enumerator + * @return return error enumerator */ enumerator_t* (*create_error_enumerator)(pb_tnc_batch_t *this); @@ -115,9 +126,9 @@ struct pb_tnc_batch_t { /** * Create an empty PB-TNC Batch of a given type * - * @param is_server TRUE if server, FALSE if client - * @param type PB-TNC batch type - * @param max_batch_len maximum size the PB-TNC batch + * @param is_server TRUE if server, FALSE if client + * @param type PB-TNC batch type + * @param max_batch_len maximum size the PB-TNC batch */ pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type, size_t max_batch_len); @@ -125,9 +136,8 @@ pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type, /** * Create an unprocessed PB-TNC Batch from data * - * @param is_server TRUE if server, FALSE if client * @param data encoded PB-TNC batch */ -pb_tnc_batch_t* pb_tnc_batch_create_from_data(bool is_server, chunk_t data); +pb_tnc_batch_t* pb_tnc_batch_create_from_data(chunk_t data); #endif /** PB_TNC_BATCH_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_20/messages/ita/pb_mutual_capability_msg.c b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_mutual_capability_msg.c new file mode 100644 index 000000000..1f35cae6b --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_mutual_capability_msg.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2015 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 "pb_mutual_capability_msg.h" + +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> +#include <utils/debug.h> + +ENUM(pb_tnc_mutual_protocol_type_names, PB_MUTUAL_HALF_DUPLEX, + PB_MUTUAL_FULL_DUPLEX, + "half duplex", + "full duplex" +); + +typedef struct private_pb_mutual_capability_msg_t private_pb_mutual_capability_msg_t; + +/** + * PB-Mutual-Capability message + * + * 0 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |H|F| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +# define MUTUAL_CAPABILITY_HEADER_SIZE 4 + +/** + * Private data of a pb_mutual_capability_msg_t object. + * + */ +struct private_pb_mutual_capability_msg_t { + /** + * Public pb_mutual_capability_msg_t interface. + */ + pb_mutual_capability_msg_t public; + + /** + * PB-TNC message type + */ + pen_type_t type; + + /** + * PB-TNC mutual protocols + */ + uint32_t protocols; + + /** + * Encoded message + */ + chunk_t encoding; +}; + +METHOD(pb_tnc_msg_t, get_type, pen_type_t, + private_pb_mutual_capability_msg_t *this) +{ + return this->type; +} + +METHOD(pb_tnc_msg_t, get_encoding, chunk_t, + private_pb_mutual_capability_msg_t *this) +{ + return this->encoding; +} + +METHOD(pb_tnc_msg_t, build, void, + private_pb_mutual_capability_msg_t *this) +{ + bio_writer_t *writer; + + if (this->encoding.ptr) + { + return; + } + writer = bio_writer_create(MUTUAL_CAPABILITY_HEADER_SIZE); + writer->write_uint32(writer, this->protocols); + + this->encoding = writer->get_buf(writer); + this->encoding = chunk_clone(this->encoding); + writer->destroy(writer); +} + +METHOD(pb_tnc_msg_t, process, status_t, + private_pb_mutual_capability_msg_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + + *offset = 0; + + /* process message */ + reader = bio_reader_create(this->encoding); + reader->read_uint32(reader, &this->protocols); + reader->destroy(reader); + + return SUCCESS; +} + +METHOD(pb_tnc_msg_t, destroy, void, + private_pb_mutual_capability_msg_t *this) +{ + free(this->encoding.ptr); + free(this); +} + +METHOD(pb_mutual_capability_msg_t, get_protocols, uint32_t, + private_pb_mutual_capability_msg_t *this) +{ + return this->protocols; +} + +/** + * See header + */ +pb_tnc_msg_t* pb_mutual_capability_msg_create(uint32_t protocols) +{ + private_pb_mutual_capability_msg_t *this; + + INIT(this, + .public = { + .pb_interface = { + .get_type = _get_type, + .get_encoding = _get_encoding, + .build = _build, + .process = _process, + .destroy = _destroy, + }, + .get_protocols = _get_protocols, + }, + .type = { PEN_ITA, PB_ITA_MSG_MUTUAL_CAPABILITY }, + .protocols = protocols, + ); + + return &this->public.pb_interface; +} + +/** + * See header + */ +pb_tnc_msg_t *pb_mutual_capability_msg_create_from_data(chunk_t data) +{ + private_pb_mutual_capability_msg_t *this; + + INIT(this, + .public = { + .pb_interface = { + .get_type = _get_type, + .get_encoding = _get_encoding, + .build = _build, + .process = _process, + .destroy = _destroy, + }, + .get_protocols = _get_protocols, + }, + .type = { PEN_ITA, PB_ITA_MSG_MUTUAL_CAPABILITY }, + .encoding = chunk_clone(data), + ); + + return &this->public.pb_interface; +} + diff --git a/src/libtnccs/plugins/tnccs_20/messages/ita/pb_mutual_capability_msg.h b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_mutual_capability_msg.h new file mode 100644 index 000000000..db810a012 --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_mutual_capability_msg.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 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 pb_mutual_capability_msg pb_mutual_capability_msg + * @{ @ingroup tnccs_20 + */ + +#ifndef PB_MUTUAL_CAPABILITY_MSG_H_ +#define PB_MUTUAL_CAPABILITY_MSG_H_ + +typedef enum pb_tnc_mutual_protocol_type_t pb_tnc_mutual_protocol_type_t; +typedef struct pb_mutual_capability_msg_t pb_mutual_capability_msg_t; + +#include "messages/pb_tnc_msg.h" + +/** + * PB-TNC mutual protocol types + */ +enum pb_tnc_mutual_protocol_type_t { + PB_MUTUAL_HALF_DUPLEX = (1 << 31), + PB_MUTUAL_FULL_DUPLEX = (1 << 30) +}; + +/** + * enum name for pb_mutual_protocol_type_t. + */ +extern enum_name_t *pb_tnc_mutual_protocol_type_names; + +/** + * Class representing the PB-Mutual-Capabilities message type. + */ +struct pb_mutual_capability_msg_t { + + /** + * PB-TNC Message interface + */ + pb_tnc_msg_t pb_interface; + + /** + * Get the PB-TNC mutual protocol types + * + * @return PB-TNC mutual protocol types + */ + uint32_t(*get_protocols)(pb_mutual_capability_msg_t *this); + +}; + +/** + * Create a PB-Mutual-Capability message + * + * @param protocols Supported PB-TNC mutual protocols + */ +pb_tnc_msg_t* pb_mutual_capability_msg_create(uint32_t protocols); + +/** + * Create an unprocessed PB-Mutual-Capability message from raw data + * + * @param data PB-Mutual-Capability message data + */ +pb_tnc_msg_t* pb_mutual_capability_msg_create_from_data(chunk_t data); + +#endif /** PB_MUTUAL_CAPABILITY_MSG_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_20/messages/ita/pb_noskip_test_msg.c b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_noskip_test_msg.c new file mode 100644 index 000000000..c95222e3a --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_noskip_test_msg.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015 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 "pb_noskip_test_msg.h" + +typedef struct private_pb_noskip_test_msg_t private_pb_noskip_test_msg_t; + +/** + * Private data of a pb_noskip_test_msg_t object. + * + */ +struct private_pb_noskip_test_msg_t { + /** + * Public pb_noskip_test_msg_t interface. + */ + pb_noskip_test_msg_t public; + + /** + * PB-TNC message type + */ + pen_type_t type; + + /** + * Encoded message + */ + chunk_t encoding; +}; + +METHOD(pb_tnc_msg_t, get_type, pen_type_t, + private_pb_noskip_test_msg_t *this) +{ + return this->type; +} + +METHOD(pb_tnc_msg_t, get_encoding, chunk_t, + private_pb_noskip_test_msg_t *this) +{ + return this->encoding; +} + +METHOD(pb_tnc_msg_t, build, void, + private_pb_noskip_test_msg_t *this) +{ + /* nothing to do since the message is empty */ +} + +METHOD(pb_tnc_msg_t, process, status_t, + private_pb_noskip_test_msg_t *this, u_int32_t *offset) +{ + return SUCCESS; +} + +METHOD(pb_tnc_msg_t, destroy, void, + private_pb_noskip_test_msg_t *this) +{ + free(this); +} + +/** + * See header + */ +pb_tnc_msg_t *pb_noskip_test_msg_create(void) +{ + private_pb_noskip_test_msg_t *this; + + INIT(this, + .public = { + .pb_interface = { + .get_type = _get_type, + .get_encoding = _get_encoding, + .build = _build, + .process = _process, + .destroy = _destroy, + }, + }, + .type = { PEN_ITA, PB_ITA_MSG_NOSKIP_TEST }, + ); + + return &this->public.pb_interface; +} diff --git a/src/libtnccs/plugins/tnccs_20/messages/ita/pb_noskip_test_msg.h b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_noskip_test_msg.h new file mode 100644 index 000000000..6325582da --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/messages/ita/pb_noskip_test_msg.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 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 pb_noskip_test_msg pb_noskip_test_msg + * @{ @ingroup tnccs_20 + */ + +#ifndef PB_NOSKIP_TEST_MSG_H_ +#define PB_NOSKIP_TEST_MSG_H_ + +typedef struct pb_noskip_test_msg_t pb_noskip_test_msg_t; + +#include "messages/pb_tnc_msg.h" + +/** + * Class representing the PB-Noskip-Test message type. + */ +struct pb_noskip_test_msg_t { + + /** + * PB-TNC Message interface + */ + pb_tnc_msg_t pb_interface; +}; + +/** + * Create a PB-Noskip-Test message from parameters + */ +pb_tnc_msg_t* pb_noskip_test_msg_create(void); + +#endif /** PB_NOSKIP_TEST_MSG_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c index ec43490f4..b46c776e4 100644 --- a/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c +++ b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.c @@ -22,6 +22,7 @@ #include "ietf/pb_access_recommendation_msg.h" #include "ietf/pb_remediation_parameters_msg.h" #include "ietf/pb_reason_string_msg.h" +#include "ita/pb_mutual_capability_msg.h" #include "tcg/pb_pdp_referral_msg.h" #include <library.h> @@ -37,10 +38,17 @@ ENUM(pb_tnc_msg_type_names, PB_MSG_EXPERIMENTAL, PB_MSG_REASON_STRING, "PB-Reason-String" ); -ENUM(pb_tnc_tcg_msg_type_names, PB_TCG_MSG_PDP_REFERRAL, PB_TCG_MSG_PDP_REFERRAL, +ENUM(pb_tnc_tcg_msg_type_names, PB_TCG_MSG_PDP_REFERRAL, + PB_TCG_MSG_PDP_REFERRAL, "PB-PDP-Referral" ); +ENUM(pb_tnc_ita_msg_type_names, PB_ITA_MSG_NOSKIP_TEST, + PB_ITA_MSG_MUTUAL_CAPABILITY, + "PB-Noskip-Test", + "PB-Mutual-Capability" +); + pb_tnc_msg_info_t pb_tnc_msg_infos[] = { { 12, FALSE, FALSE, TRUE_OR_FALSE }, { 24, FALSE, FALSE, TRUE }, @@ -57,6 +65,11 @@ pb_tnc_msg_info_t pb_tnc_tcg_msg_infos[] = { { 20, FALSE, FALSE, FALSE }, }; +pb_tnc_msg_info_t pb_tnc_ita_msg_infos[] = { + { 12, TRUE, FALSE, TRUE }, + { 16, FALSE, FALSE, FALSE }, +}; + /** * See header */ @@ -91,5 +104,12 @@ pb_tnc_msg_t* pb_tnc_msg_create_from_data(pen_type_t msg_type, chunk_t value) return pb_pdp_referral_msg_create_from_data(value); } } + else if (msg_type.vendor_id == PEN_ITA) + { + if (msg_type.type == PB_ITA_MSG_MUTUAL_CAPABILITY) + { + return pb_mutual_capability_msg_create_from_data(value); + } + } return NULL; } diff --git a/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h index 6eeed5156..35b0b7c26 100644 --- a/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h +++ b/src/libtnccs/plugins/tnccs_20/messages/pb_tnc_msg.h @@ -54,6 +54,7 @@ extern enum_name_t *pb_tnc_msg_type_names; * PB-TNC Message Type defined in the TCG namespace */ enum pb_tnc_tcg_msg_type_t { + PB_TCG_MSG_RESERVED = 0, PB_TCG_MSG_PDP_REFERRAL = 1, PB_TCG_MSG_ROOF = 1 }; @@ -64,6 +65,20 @@ enum pb_tnc_tcg_msg_type_t { extern enum_name_t *pb_tnc_tcg_msg_type_names; /** + * PB-TNC Message Type defined in the ITA namespace + */ +enum pb_tnc_ita_msg_type_t { + PB_ITA_MSG_NOSKIP_TEST = 0, + PB_ITA_MSG_MUTUAL_CAPABILITY = 1, + PB_ITA_MSG_ROOF = 1 +}; + +/** + * enum name for pb_tnc_tcg_msg_type_t. + */ +extern enum_name_t *pb_tnc_ita_msg_type_names; + +/** * Information entry describing a PB-TNC Message Type */ struct pb_tnc_msg_info_t { @@ -86,6 +101,11 @@ extern pb_tnc_msg_info_t pb_tnc_msg_infos[]; extern pb_tnc_msg_info_t pb_tnc_tcg_msg_infos[]; /** + * Information on PB-TNC ITA Message Types + */ +extern pb_tnc_msg_info_t pb_tnc_ita_msg_infos[]; + +/** * Generic interface for all PB-TNC message types. * * To handle all messages in a generic way, this interface diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20.c b/src/libtnccs/plugins/tnccs_20/tnccs_20.c index dc4da51c6..a1a95733f 100644 --- a/src/libtnccs/plugins/tnccs_20/tnccs_20.c +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Sansar Choinyanbuu - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,30 +15,17 @@ */ #include "tnccs_20.h" +#include "tnccs_20_handler.h" +#include "tnccs_20_server.h" +#include "tnccs_20_client.h" #include "batch/pb_tnc_batch.h" #include "messages/pb_tnc_msg.h" #include "messages/ietf/pb_pa_msg.h" -#include "messages/ietf/pb_error_msg.h" -#include "messages/ietf/pb_assessment_result_msg.h" -#include "messages/ietf/pb_access_recommendation_msg.h" -#include "messages/ietf/pb_remediation_parameters_msg.h" -#include "messages/ietf/pb_reason_string_msg.h" -#include "messages/ietf/pb_language_preference_msg.h" -#include "messages/tcg/pb_pdp_referral_msg.h" -#include "state_machine/pb_tnc_state_machine.h" #include <tncif_names.h> #include <tncif_pa_subtypes.h> -#include <tnc/tnc.h> -#include <tnc/tnccs/tnccs_manager.h> -#include <tnc/imc/imc_manager.h> -#include <tnc/imv/imv_manager.h> - -#include <threading/mutex.h> #include <utils/debug.h> -#include <collections/linked_list.h> -#include <pen/pen.h> typedef struct private_tnccs_20_t private_tnccs_20_t; @@ -60,77 +47,72 @@ struct private_tnccs_20_t { /** * Server identity */ - identification_t *server; + identification_t *server_id; /** * Client identity */ - identification_t *peer; + identification_t *peer_id; /** - * Underlying TNC IF-T transport protocol + * Server IP address */ - tnc_ift_type_t transport; + host_t *server_ip; /** - * Type of TNC client authentication + * Client IP address */ - u_int32_t auth_type; + host_t *peer_ip; /** - * PB-TNC State Machine + * Underlying TNC IF-T transport protocol */ - pb_tnc_state_machine_t *state_machine; + tnc_ift_type_t transport; /** - * Connection ID assigned to this TNCCS connection + * TNC IF-T transport protocol for EAP methods */ - TNC_ConnectionID connection_id; + bool eap_transport; /** - * PB-TNC messages to be sent + * Type of TNC client authentication */ - linked_list_t *messages; + u_int32_t auth_type; /** - * Type of PB-TNC batch being constructed + * Mutual PB-TNC protocol enabled */ - pb_tnc_batch_type_t batch_type; + bool mutual; /** - * Maximum PB-TNC batch size + * Direction the next batch will go to */ - size_t max_batch_len; + bool to_server; /** - * Maximum PA-TNC message size + * TNC Server */ - size_t max_msg_len; + tnccs_20_handler_t *tnc_server; /** - * Mutex locking the batch in construction + * TNC Client */ - mutex_t *mutex; + tnccs_20_handler_t *tnc_client; /** - * Flag set while processing + * Active TNCSS handler */ - bool fatal_error; + tnccs_20_handler_t *tnccs_handler; /** - * Flag set by IMC/IMV RequestHandshakeRetry() function + * Maximum PB-TNC batch size */ - bool request_handshake_retry; - - /** - * SendMessage() by IMC/IMV only allowed if flag is set - */ - bool send_msg; + size_t max_batch_len; /** - * Set of IMV recommendations (TNC Server only) + * Maximum PA-TNC message size */ - recommendations_t *recs; + size_t max_msg_len; /** * Callback function to communicate recommendation (TNC Server only) @@ -138,69 +120,30 @@ struct private_tnccs_20_t { tnccs_cb_t callback; /** - * Data to pass to callback function (TNC Server only) - */ - void *cb_data; - - /** - * PDP server FQDN - */ - chunk_t pdp_server; - - /** - * PDP server port - */ - u_int16_t pdp_port; - - /** * reference count */ refcount_t ref; }; -/** - * If the batch type changes then delete all accumulated PB-TNC messages - */ -void change_batch_type(private_tnccs_20_t *this, pb_tnc_batch_type_t batch_type) -{ - pb_tnc_msg_t *msg; - - if (batch_type != this->batch_type) - { - if (this->batch_type != PB_BATCH_NONE) - { - DBG1(DBG_TNC, "cancelling PB-TNC %N batch", - pb_tnc_batch_type_names, this->batch_type); - - while (this->messages->remove_last(this->messages, - (void**)&msg) == SUCCESS) - { - msg->destroy(msg); - } - } - this->batch_type = batch_type; - } -} - METHOD(tnccs_t, send_msg, TNC_Result, private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id, - TNC_UInt32 msg_flags, + TNC_UInt32 msg_flags, TNC_BufferReference msg, TNC_UInt32 msg_len, - TNC_VendorID msg_vid, - TNC_MessageSubtype msg_subtype) + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype) { pb_tnc_msg_t *pb_tnc_msg; - pb_tnc_batch_type_t batch_type; enum_name_t *pa_subtype_names; bool excl; - if (!this->send_msg) + if (!this->tnccs_handler->get_send_flag(this->tnccs_handler)) { DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()", - this->is_server ? "IMV" : "IMC", - this->is_server ? imv_id : imc_id); + this->to_server ? "IMC" : "IMV", + this->to_server ? imc_id : imv_id); + return TNC_RESULT_ILLEGAL_OPERATION; } excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0; @@ -220,698 +163,169 @@ METHOD(tnccs_t, send_msg, TNC_Result, DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x", pen_names, msg_vid, msg_vid, msg_subtype); } + this->tnccs_handler->add_msg(this->tnccs_handler, pb_tnc_msg); - /* adding PA message to SDATA or CDATA batch only */ - batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA; - this->mutex->lock(this->mutex); - if (this->batch_type == PB_BATCH_NONE) - { - this->batch_type = batch_type; - } - if (this->batch_type == batch_type) - { - this->messages->insert_last(this->messages, pb_tnc_msg); - } - else - { - pb_tnc_msg->destroy(pb_tnc_msg); - } - this->mutex->unlock(this->mutex); return TNC_RESULT_SUCCESS; } -/** - * Handle a single PB-TNC IETF standard message according to its type - */ -static void handle_ietf_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) -{ - pen_type_t msg_type = msg->get_type(msg); - - switch (msg_type.type) - { - case PB_MSG_EXPERIMENTAL: - /* nothing to do */ - break; - case PB_MSG_PA: - { - pb_pa_msg_t *pa_msg; - pen_type_t msg_subtype; - u_int16_t imc_id, imv_id; - chunk_t msg_body; - bool excl; - enum_name_t *pa_subtype_names; - - pa_msg = (pb_pa_msg_t*)msg; - msg_subtype = pa_msg->get_subtype(pa_msg); - msg_body = pa_msg->get_body(pa_msg); - imc_id = pa_msg->get_collector_id(pa_msg); - imv_id = pa_msg->get_validator_id(pa_msg); - excl = pa_msg->get_exclusive_flag(pa_msg); - - pa_subtype_names = get_pa_subtype_names(msg_subtype.vendor_id); - if (pa_subtype_names) - { - DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x", - pen_names, msg_subtype.vendor_id, pa_subtype_names, - msg_subtype.type, msg_subtype.vendor_id, msg_subtype.type); - } - else - { - DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x", - pen_names, msg_subtype.vendor_id, msg_subtype.vendor_id, - msg_subtype.type); - } - - this->send_msg = TRUE; - if (this->is_server) - { - tnc->imvs->receive_message(tnc->imvs, this->connection_id, - excl, msg_body.ptr, msg_body.len, - msg_subtype.vendor_id, - msg_subtype.type, imc_id, imv_id); - } - else - { - tnc->imcs->receive_message(tnc->imcs, this->connection_id, - excl, msg_body.ptr, msg_body.len, - msg_subtype.vendor_id, - msg_subtype.type, imv_id, imc_id); - } - this->send_msg = FALSE; - break; - } - case PB_MSG_ASSESSMENT_RESULT: - { - pb_assessment_result_msg_t *assess_msg; - u_int32_t result; - - assess_msg = (pb_assessment_result_msg_t*)msg; - result = assess_msg->get_assessment_result(assess_msg); - DBG1(DBG_TNC, "PB-TNC assessment result is '%N'", - TNC_IMV_Evaluation_Result_names, result); - break; - } - case PB_MSG_ACCESS_RECOMMENDATION: - { - pb_access_recommendation_msg_t *rec_msg; - pb_access_recommendation_code_t rec; - TNC_ConnectionState state = TNC_CONNECTION_STATE_ACCESS_NONE; - - rec_msg = (pb_access_recommendation_msg_t*)msg; - rec = rec_msg->get_access_recommendation(rec_msg); - DBG1(DBG_TNC, "PB-TNC access recommendation is '%N'", - pb_access_recommendation_code_names, rec); - switch (rec) - { - case PB_REC_ACCESS_ALLOWED: - state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; - break; - case PB_REC_ACCESS_DENIED: - state = TNC_CONNECTION_STATE_ACCESS_NONE; - break; - case PB_REC_QUARANTINED: - state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; - } - tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, - state); - break; - } - case PB_MSG_REMEDIATION_PARAMETERS: - { - pb_remediation_parameters_msg_t *rem_msg; - pen_type_t parameters_type; - chunk_t parameters, string, lang_code; - - rem_msg = (pb_remediation_parameters_msg_t*)msg; - parameters_type = rem_msg->get_parameters_type(rem_msg); - parameters = rem_msg->get_parameters(rem_msg); - - if (parameters_type.vendor_id == PEN_IETF) - { - switch (parameters_type.type) - { - case PB_REMEDIATION_URI: - DBG1(DBG_TNC, "remediation uri: %.*s", - parameters.len, parameters.ptr); - break; - case PB_REMEDIATION_STRING: - string = rem_msg->get_string(rem_msg, &lang_code); - DBG1(DBG_TNC, "remediation string: [%.*s]\n%.*s", - lang_code.len, lang_code.ptr, - string.len, string.ptr); - break; - default: - DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); - } - } - else - { - DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); - } - break; - } - case PB_MSG_ERROR: - { - pb_error_msg_t *err_msg; - bool fatal; - u_int32_t vendor_id; - u_int16_t error_code; - - err_msg = (pb_error_msg_t*)msg; - fatal = err_msg->get_fatal_flag(err_msg); - vendor_id = err_msg->get_vendor_id(err_msg); - error_code = err_msg->get_error_code(err_msg); - - if (fatal) - { - this->fatal_error = TRUE; - } - - if (vendor_id == PEN_IETF) - { - switch (error_code) - { - case PB_ERROR_INVALID_PARAMETER: - case PB_ERROR_UNSUPPORTED_MANDATORY_MSG: - DBG1(DBG_TNC, "received %s PB-TNC error '%N' " - "(offset %u bytes)", - fatal ? "fatal" : "non-fatal", - pb_tnc_error_code_names, error_code, - err_msg->get_offset(err_msg)); - break; - case PB_ERROR_VERSION_NOT_SUPPORTED: - DBG1(DBG_TNC, "received %s PB-TNC error '%N' " - "caused by bad version 0x%02x", - fatal ? "fatal" : "non-fatal", - pb_tnc_error_code_names, error_code, - err_msg->get_bad_version(err_msg)); - break; - case PB_ERROR_UNEXPECTED_BATCH_TYPE: - case PB_ERROR_LOCAL_ERROR: - default: - DBG1(DBG_TNC, "received %s PB-TNC error '%N'", - fatal ? "fatal" : "non-fatal", - pb_tnc_error_code_names, error_code); - break; - } - } - else - { - DBG1(DBG_TNC, "received %s PB-TNC error (%u) " - "with Vendor ID 0x%06x", - fatal ? "fatal" : "non-fatal", - error_code, vendor_id); - } - break; - } - case PB_MSG_LANGUAGE_PREFERENCE: - { - pb_language_preference_msg_t *lang_msg; - chunk_t lang; - - lang_msg = (pb_language_preference_msg_t*)msg; - lang = lang_msg->get_language_preference(lang_msg); - - if (this->recs) - { - DBG2(DBG_TNC, "setting language preference to '%.*s'", - (int)lang.len, lang.ptr); - this->recs->set_preferred_language(this->recs, lang); - } - break; - } - case PB_MSG_REASON_STRING: - { - pb_reason_string_msg_t *reason_msg; - chunk_t reason_string, language_code; - - reason_msg = (pb_reason_string_msg_t*)msg; - reason_string = reason_msg->get_reason_string(reason_msg); - language_code = reason_msg->get_language_code(reason_msg); - DBG1(DBG_TNC, "reason string is '%.*s' [%.*s]", - (int)reason_string.len, reason_string.ptr, - (int)language_code.len, language_code.ptr); - break; - } - default: - break; - } -} - -/** - * Handle a single PB-TNC TCG standard message according to its type - */ -static void handle_tcg_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) -{ - pen_type_t msg_type = msg->get_type(msg); - - switch (msg_type.type) - { - case PB_TCG_MSG_PDP_REFERRAL: - { - pb_pdp_referral_msg_t *pdp_msg; - pen_type_t pdp_id_type; - u_int8_t pdp_protocol; - - pdp_msg = (pb_pdp_referral_msg_t*)msg; - pdp_id_type = pdp_msg->get_identifier_type(pdp_msg); - - if (pdp_id_type.vendor_id == PEN_TCG && - pdp_id_type.type == PB_PDP_ID_FQDN) - { - this->pdp_server = chunk_clone(pdp_msg->get_fqdn(pdp_msg, - &pdp_protocol, &this->pdp_port)); - if (pdp_protocol != 0) - { - DBG1(DBG_TNC, "unsupported PDP transport protocol"); - break; - } - DBG1(DBG_TNC, "PDP server '%.*s' is listening on port %u", - this->pdp_server.len, this->pdp_server.ptr, - this->pdp_port); - } - break; - } - default: - break; - } -} - -/** - * Handle a single PB-TNC message according to its type - */ -static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) -{ - pen_type_t msg_type = msg->get_type(msg); - - switch (msg_type.vendor_id) - { - case PEN_IETF: - handle_ietf_message(this, msg); - break; - case PEN_TCG: - handle_tcg_message(this, msg); - break; - default: - break; - } -} - -/** - * Build a CRETRY or SRETRY batch - */ -static void build_retry_batch(private_tnccs_20_t *this) -{ - pb_tnc_batch_type_t batch_retry_type; - - batch_retry_type = this->is_server ? PB_BATCH_SRETRY : PB_BATCH_CRETRY; - if (this->batch_type == batch_retry_type) - { - /* retry batch has already been selected */ - return; - } - - change_batch_type(this, batch_retry_type); - - if (this->is_server) - { - this->recs->clear_recommendation(this->recs); - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - TNC_CONNECTION_STATE_HANDSHAKE); - } -} - METHOD(tls_t, process, status_t, private_tnccs_20_t *this, void *buf, size_t buflen) { - chunk_t data; pb_tnc_batch_t *batch; - pb_tnc_msg_t *msg; - enumerator_t *enumerator; - identification_t *pdp_server; - u_int16_t *pdp_port; + bool from_server, fatal_header_error = FALSE; status_t status; + chunk_t data; - if (this->is_server && !this->connection_id) + /* On arrival of first batch from TNC client create TNC server */ + if (this->is_server && !this->tnc_server) { - this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - TNCCS_2_0, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, - this->max_msg_len, &this->recs); - if (!this->connection_id) + this->tnc_server = tnccs_20_server_create(&this->public, _send_msg, + this->max_batch_len, this->max_msg_len, + this->eap_transport); + if (!this->tnc_server) { return FAILED; } - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - TNC_CONNECTION_STATE_CREATE); - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - TNC_CONNECTION_STATE_HANDSHAKE); - - /* Send a PB-TNC TCG PDP Referral message if PDP is known */ - pdp_server = (identification_t*)lib->get(lib, "pt-tls-server"); - pdp_port = (u_int16_t*)lib->get(lib, "pt-tls-port"); - - if ((this->transport == TNC_IFT_EAP_1_1 || - this->transport == TNC_IFT_EAP_2_0) && pdp_server && pdp_port) - { - msg = pb_pdp_referral_msg_create_from_fqdn( - pdp_server->get_encoding(pdp_server), *pdp_port); - this->messages->insert_last(this->messages, msg); - } - + this->tnccs_handler = this->tnc_server; + this->tnccs_handler->begin_handshake(this->tnccs_handler, FALSE); } data = chunk_create(buf, buflen); - DBG1(DBG_TNC, "received TNCCS batch (%u bytes) for Connection ID %u", - data.len, this->connection_id); + DBG1(DBG_TNC, "received TNCCS batch (%u bytes)", data.len); DBG3(DBG_TNC, "%B", &data); - batch = pb_tnc_batch_create_from_data(this->is_server, data); - status = batch->process(batch, this->state_machine); - if (status != FAILED) + /* Parse the header of the received PB-TNC batch */ + batch = pb_tnc_batch_create_from_data(data); + status = batch->process_header(batch, !this->mutual, this->is_server, + &from_server); + if (status == FAILED) { - enumerator_t *enumerator; - pb_tnc_msg_t *msg; - pb_tnc_batch_type_t batch_type; - bool empty = TRUE; - - batch_type = batch->get_type(batch); - - if (batch_type == PB_BATCH_CRETRY) - { - /* Send an SRETRY batch in response */ - this->mutex->lock(this->mutex); - build_retry_batch(this); - this->mutex->unlock(this->mutex); - } - else if (batch_type == PB_BATCH_SRETRY) - { - /* Restart the measurements */ - tnc->imcs->notify_connection_change(tnc->imcs, - this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE); - this->send_msg = TRUE; - tnc->imcs->begin_handshake(tnc->imcs, this->connection_id); - this->send_msg = FALSE; - } - - enumerator = batch->create_msg_enumerator(batch); - while (enumerator->enumerate(enumerator, &msg)) - { - handle_message(this, msg); - empty = FALSE; - } - enumerator->destroy(enumerator); + fatal_header_error = TRUE; + status = VERIFY_ERROR; + } + this->to_server = this->mutual ? from_server : !this->is_server; - /* received an empty CLOSE batch from PB-TNC client */ - if (this->is_server && batch_type == PB_BATCH_CLOSE && empty) + /* In the mutual case, first batch from TNC server requires a TNC client */ + if (this->to_server && !this->tnc_client) + { + this->tnc_client = tnccs_20_client_create(&this->public, _send_msg, + this->max_batch_len, this->max_msg_len); + if (!this->tnc_client) { batch->destroy(batch); - if (this->fatal_error) - { - DBG1(DBG_TNC, "a fatal PB-TNC error occurred, " - "terminating connection"); - return FAILED; - } - else - { - return SUCCESS; - } - } - - this->send_msg = TRUE; - if (this->is_server) - { - tnc->imvs->batch_ending(tnc->imvs, this->connection_id); - } - else - { - tnc->imcs->batch_ending(tnc->imcs, this->connection_id); + return FAILED; } - this->send_msg = FALSE; + this->tnccs_handler = this->tnc_client; + this->tnccs_handler->begin_handshake(this->tnccs_handler, this->mutual); } + else + { + /* Set active TNCCS handler for processing */ + this->tnccs_handler = this->to_server ? this->tnc_client : + this->tnc_server; + } + DBG2(DBG_TNC, "TNC %s is handling inbound connection", + this->to_server ? "client" : "server"); - switch (status) + if (status == SUCCESS) { - case FAILED: - this->fatal_error = TRUE; - this->mutex->lock(this->mutex); - change_batch_type(this, PB_BATCH_CLOSE); - this->mutex->unlock(this->mutex); - /* fall through to add error messages to outbound batch */ - case VERIFY_ERROR: - enumerator = batch->create_error_enumerator(batch); - while (enumerator->enumerate(enumerator, &msg)) - { - this->mutex->lock(this->mutex); - this->messages->insert_last(this->messages, msg->get_ref(msg)); - this->mutex->unlock(this->mutex); - } - enumerator->destroy(enumerator); - break; - case SUCCESS: - default: - break; + status = this->tnccs_handler->process(this->tnccs_handler, batch); + } + if (status == VERIFY_ERROR) + { + this->tnccs_handler->handle_errors(this->tnccs_handler, batch, + fatal_header_error); + status = NEED_MORE; } batch->destroy(batch); - return NEED_MORE; -} + /* Has a mutual connection been established? */ + this->mutual = this->is_server ? + this->tnc_server->get_mutual(this->tnc_server) : + this->tnc_client->get_mutual(this->tnc_client); -/** - * Build a RESULT batch if a final recommendation is available - */ -static void check_and_build_recommendation(private_tnccs_20_t *this) -{ - TNC_IMV_Action_Recommendation rec; - TNC_IMV_Evaluation_Result eval; - TNC_ConnectionState state; - TNC_IMVID id; - chunk_t reason, language; - enumerator_t *enumerator; - pb_tnc_msg_t *msg; - pb_access_recommendation_code_t pb_rec; - - if (!this->recs->have_recommendation(this->recs, &rec, &eval)) - { - tnc->imvs->solicit_recommendation(tnc->imvs, this->connection_id); - } - if (this->recs->have_recommendation(this->recs, &rec, &eval)) + if (this->mutual && !this->is_server) { - this->batch_type = PB_BATCH_RESULT; + pb_tnc_state_t client_state, server_state; - msg = pb_assessment_result_msg_create(eval); - this->messages->insert_last(this->messages, msg); + client_state = !this->tnc_client ? PB_STATE_INIT : + this->tnc_client->get_state(this->tnc_client); + server_state = !this->tnc_server ? PB_STATE_INIT : + this->tnc_server->get_state(this->tnc_server); - /** - * Map IMV Action Recommendation codes to PB Access Recommendation codes - * and communicate Access Recommendation to IMVs - */ - switch (rec) + /* In half-duplex mutual mode toggle the direction on the client side */ + if ((!this->to_server && client_state != PB_STATE_DECIDED) || + ( this->to_server && server_state != PB_STATE_END)) { - case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: - state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; - pb_rec = PB_REC_ACCESS_ALLOWED; - break; - case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: - state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; - pb_rec = PB_REC_QUARANTINED; - break; - case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: - case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: - default: - state = TNC_CONNECTION_STATE_ACCESS_NONE; - pb_rec = PB_REC_ACCESS_DENIED; + this->to_server = !this->to_server; + } + else if (client_state == PB_STATE_DECIDED && + server_state == PB_STATE_END) + { + /* Cause the final CLOSE batch to be sent to the TNC server */ + this->to_server = TRUE; } - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - state); - - msg = pb_access_recommendation_msg_create(pb_rec); - this->messages->insert_last(this->messages, msg); - enumerator = this->recs->create_reason_enumerator(this->recs); - while (enumerator->enumerate(enumerator, &id, &reason, &language)) + /* Suppress a successful CLOSE batch coming from the TNC server */ + if (status == SUCCESS) { - msg = pb_reason_string_msg_create(reason, language); - this->messages->insert_last(this->messages, msg); + status = NEED_MORE; } - enumerator->destroy(enumerator); } + + return status; } METHOD(tls_t, build, status_t, private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen) { - status_t status; - pb_tnc_state_t state; - - /* Initialize the connection */ - if (!this->is_server && !this->connection_id) - { - pb_tnc_msg_t *msg; - char *pref_lang; - - this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - TNCCS_2_0, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, - this->max_msg_len, NULL); - if (!this->connection_id) - { - return FAILED; - } - - /* Create PB-TNC Language Preference message */ - pref_lang = tnc->imcs->get_preferred_language(tnc->imcs); - msg = pb_language_preference_msg_create(chunk_create(pref_lang, - strlen(pref_lang))); - this->mutex->lock(this->mutex); - this->batch_type = PB_BATCH_CDATA; - this->messages->insert_last(this->messages, msg); - this->mutex->unlock(this->mutex); - - tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, - TNC_CONNECTION_STATE_CREATE); - tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, - TNC_CONNECTION_STATE_HANDSHAKE); - this->send_msg = TRUE; - tnc->imcs->begin_handshake(tnc->imcs, this->connection_id); - this->send_msg = FALSE; - } - - state = this->state_machine->get_state(this->state_machine); - - if (this->fatal_error && state == PB_STATE_END) - { - DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection"); - return FAILED; - } - - /* Do not allow any asynchronous IMCs or IMVs to add additional messages */ - this->mutex->lock(this->mutex); - - if (this->request_handshake_retry) - { - if (state != PB_STATE_INIT) - { - build_retry_batch(this); - } - - /* Reset the flag for the next handshake retry request */ - this->request_handshake_retry = FALSE; - } - - if (this->is_server && state == PB_STATE_SERVER_WORKING && - this->recs->have_recommendation(this->recs, NULL, NULL)) + if (this->to_server) { - check_and_build_recommendation(this); - } + DBG2(DBG_TNC, "TNC client is handling outbound connection"); - if (this->batch_type == PB_BATCH_NONE) - { - if (this->is_server) + /* Before sending the first PB-TNC batch create TNC client */ + if (this->tnc_client) { - if (state == PB_STATE_SERVER_WORKING) - { - if (this->state_machine->get_empty_cdata(this->state_machine)) - { - check_and_build_recommendation(this); - } - else - { - DBG2(DBG_TNC, "no recommendation available yet, " - "sending empty PB-TNC SDATA batch"); - this->batch_type = PB_BATCH_SDATA; - } - } + this->tnccs_handler = this->tnc_client; } else { - switch (state) + this->tnc_client = tnccs_20_client_create(&this->public, _send_msg, + this->max_batch_len, + this->max_msg_len); + if (!this->tnc_client) { - case PB_STATE_CLIENT_WORKING: - DBG2(DBG_TNC, "no client data to send, " - "sending empty PB-TNC CDATA batch"); - this->batch_type = PB_BATCH_CDATA; - break; - case PB_STATE_DECIDED: - /** - * In the DECIDED state and if no CRETRY is under way, - * a PB-TNC client replies with an empty CLOSE batch. - */ - this->batch_type = PB_BATCH_CLOSE; - break; - default: - break; + return FAILED; } + this->tnccs_handler = this->tnc_client; + this->tnccs_handler->begin_handshake(this->tnccs_handler, + this->mutual); } } - - if (this->batch_type != PB_BATCH_NONE) + else { - pb_tnc_batch_t *batch; - pb_tnc_msg_t *msg; - chunk_t data; - int msg_count; - enumerator_t *enumerator; + DBG2(DBG_TNC, "TNC server is handling outbound connection"); - if (this->state_machine->send_batch(this->state_machine, this->batch_type)) + /* Before sending the first PB-TNC batch create TNC server */ + if (this->tnc_server) { - batch = pb_tnc_batch_create(this->is_server, this->batch_type, - min(this->max_batch_len, *buflen)); - - enumerator = this->messages->create_enumerator(this->messages); - while (enumerator->enumerate(enumerator, &msg)) - { - if (batch->add_msg(batch, msg)) - { - this->messages->remove_at(this->messages, enumerator); - } - else - { - break; - } - } - enumerator->destroy(enumerator); - - batch->build(batch); - data = batch->get_encoding(batch); - DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u", - pb_tnc_batch_type_names, this->batch_type, data.len, - this->connection_id); - DBG3(DBG_TNC, "%B", &data); - - *buflen = data.len; - *msglen = 0; - memcpy(buf, data.ptr, *buflen); - batch->destroy(batch); - - msg_count = this->messages->get_count(this->messages); - if (msg_count) - { - DBG2(DBG_TNC, "queued %d PB-TNC message%s for next %N batch", - msg_count, (msg_count == 1) ? "" : "s", - pb_tnc_batch_type_names, this->batch_type); - } - else - { - this->batch_type = PB_BATCH_NONE; - } - - status = ALREADY_DONE; + this->tnccs_handler = this->tnc_server; } else { - change_batch_type(this, PB_BATCH_NONE); - status = INVALID_STATE; + this->tnc_server = tnccs_20_server_create(&this->public, _send_msg, + this->max_batch_len, this->max_msg_len, + this->eap_transport); + if (!this->tnc_server) + { + return FAILED; + } + this->tnccs_handler = this->tnc_server; + this->tnccs_handler->begin_handshake(this->tnccs_handler, + this->mutual); } } - else - { - DBG1(DBG_TNC, "no PB-TNC batch to send"); - status = INVALID_STATE; - } - this->mutex->unlock(this->mutex); - - return status; + return this->tnccs_handler->build(this->tnccs_handler, buf, buflen, msglen); } METHOD(tls_t, is_server, bool, @@ -923,20 +337,20 @@ METHOD(tls_t, is_server, bool, METHOD(tls_t, get_server_id, identification_t*, private_tnccs_20_t *this) { - return this->server; + return this->server_id; } METHOD(tls_t, set_peer_id, void, private_tnccs_20_t *this, identification_t *id) { - DESTROY_IF(this->peer); - this->peer = id->clone(id); + DESTROY_IF(this->peer_id); + this->peer_id = id->clone(id); } METHOD(tls_t, get_peer_id, identification_t*, private_tnccs_20_t *this) { - return this->peer; + return this->peer_id; } METHOD(tls_t, get_purpose, tls_purpose_t, @@ -951,14 +365,17 @@ METHOD(tls_t, is_complete, bool, TNC_IMV_Action_Recommendation rec; TNC_IMV_Evaluation_Result eval; - if (this->recs && this->recs->have_recommendation(this->recs, &rec, &eval)) + if (this->tnc_server) { - return this->callback ? this->callback(rec, eval) : TRUE; - } - else - { - return FALSE; + tnccs_20_server_t *tnc_server; + + tnc_server = (tnccs_20_server_t*)this->tnc_server; + if (tnc_server->have_recommendation(tnc_server, &rec, &eval)) + { + return this->callback ? this->callback(rec, eval) : TRUE; + } } + return FALSE; } METHOD(tls_t, get_eap_msk, chunk_t, @@ -972,19 +389,28 @@ METHOD(tls_t, destroy, void, { if (ref_put(&this->ref)) { - tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, - this->is_server); - this->server->destroy(this->server); - this->peer->destroy(this->peer); - this->state_machine->destroy(this->state_machine); - this->mutex->destroy(this->mutex); - this->messages->destroy_offset(this->messages, - offsetof(pb_tnc_msg_t, destroy)); - free(this->pdp_server.ptr); + DESTROY_IF(this->tnc_server); + DESTROY_IF(this->tnc_client); + this->server_id->destroy(this->server_id); + this->peer_id->destroy(this->peer_id); + this->server_ip->destroy(this->server_ip); + this->peer_ip->destroy(this->peer_ip); free(this); } } +METHOD(tnccs_t, get_server_ip, host_t*, + private_tnccs_20_t *this) +{ + return this->server_ip; +} + +METHOD(tnccs_t, get_peer_ip, host_t*, + private_tnccs_20_t *this) +{ + return this->peer_ip; +} + METHOD(tnccs_t, get_transport, tnc_ift_type_t, private_tnccs_20_t *this) { @@ -1012,9 +438,19 @@ METHOD(tnccs_t, set_auth_type, void, METHOD(tnccs_t, get_pdp_server, chunk_t, private_tnccs_20_t *this, u_int16_t *port) { - *port = this->pdp_port; + if (this->tnc_client) + { + tnccs_20_client_t *tnc_client; + + tnc_client = (tnccs_20_client_t*)this->tnc_client; - return this->pdp_server; + return tnc_client->get_pdp_server(tnc_client, port); + } + else + { + *port = 0; + return chunk_empty; + } } METHOD(tnccs_t, get_ref, tnccs_t*, @@ -1027,9 +463,10 @@ METHOD(tnccs_t, get_ref, tnccs_t*, /** * See header */ -tnccs_t* tnccs_20_create(bool is_server, - identification_t *server, identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb) +tnccs_t* tnccs_20_create(bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb) { private_tnccs_20_t *this; size_t max_batch_size, default_max_batch_size; @@ -1079,6 +516,8 @@ tnccs_t* tnccs_20_create(bool is_server, .get_eap_msk = _get_eap_msk, .destroy = _destroy, }, + .get_server_ip = _get_server_ip, + .get_peer_ip = _get_peer_ip, .get_transport = _get_transport, .set_transport = _set_transport, .get_auth_type = _get_auth_type, @@ -1087,13 +526,15 @@ tnccs_t* tnccs_20_create(bool is_server, .get_ref = _get_ref, }, .is_server = is_server, - .server = server->clone(server), - .peer = peer->clone(peer), + .to_server = !is_server, + .server_id = server_id->clone(server_id), + .peer_id = peer_id->clone(peer_id), + .server_ip = server_ip->clone(server_ip), + .peer_ip = peer_ip->clone(peer_ip), .transport = transport, + .eap_transport = transport == TNC_IFT_EAP_1_1 || + transport == TNC_IFT_EAP_2_0, .callback = cb, - .state_machine = pb_tnc_state_machine_create(is_server), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - .messages = linked_list_create(), .max_batch_len = max_batch_size, .max_msg_len = max_message_size, .ref = 1, diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20.h b/src/libtnccs/plugins/tnccs_20/tnccs_20.h index 2857b1408..010cbecdc 100644 --- a/src/libtnccs/plugins/tnccs_20/tnccs_20.h +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -29,14 +29,17 @@ * Create an instance of the TNC IF-TNCCS 2.0 protocol handler. * * @param is_server TRUE to act as TNC Server, FALSE for TNC Client - * @param server Server identity - * @param peer Client identity + * @param server_id Server identity + * @param peer_id Client identity + * @param server_ip Server IP address + * @param peer_ip Client IP address * @param transport Underlying IF-T transport protocol * @param cb Callback function if TNC Server, NULL if TNC Client * @return TNC_IF_TNCCS 2.0 protocol stack */ -tnccs_t* tnccs_20_create(bool is_server, - identification_t *server, identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb); +tnccs_t* tnccs_20_create(bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb); #endif /** TNCCS_20_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_client.c b/src/libtnccs/plugins/tnccs_20/tnccs_20_client.c new file mode 100644 index 000000000..4ba8221d0 --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_client.c @@ -0,0 +1,820 @@ +/* + * Copyright (C) 2015 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 "tnccs_20_client.h" +#include "messages/pb_tnc_msg.h" +#include "messages/ietf/pb_pa_msg.h" +#include "messages/ietf/pb_error_msg.h" +#include "messages/ietf/pb_assessment_result_msg.h" +#include "messages/ietf/pb_access_recommendation_msg.h" +#include "messages/ietf/pb_remediation_parameters_msg.h" +#include "messages/ietf/pb_reason_string_msg.h" +#include "messages/ietf/pb_language_preference_msg.h" +#include "messages/ita/pb_mutual_capability_msg.h" +#include "messages/ita/pb_noskip_test_msg.h" +#include "messages/tcg/pb_pdp_referral_msg.h" +#include "state_machine/pb_tnc_state_machine.h" + +#include <tncif_names.h> +#include <tncif_pa_subtypes.h> + +#include <tnc/tnc.h> +#include <tnc/tnccs/tnccs_manager.h> +#include <tnc/imc/imc_manager.h> + +#include <threading/mutex.h> +#include <utils/debug.h> +#include <collections/linked_list.h> +#include <pen/pen.h> + +typedef struct private_tnccs_20_client_t private_tnccs_20_client_t; + +/** + * Private data of a tnccs_20_client_t object. + */ +struct private_tnccs_20_client_t { + + /** + * Public tnccs_20_client_t interface. + */ + tnccs_20_client_t public; + + /** + * PB-TNC State Machine + */ + pb_tnc_state_machine_t *state_machine; + + /** + * Connection ID assigned to this TNCCS connection + */ + TNC_ConnectionID connection_id; + + /** + * PB-TNC messages to be sent + */ + linked_list_t *messages; + + /** + * Type of PB-TNC batch being constructed + */ + pb_tnc_batch_type_t batch_type; + + /** + * Maximum PB-TNC batch size + */ + size_t max_batch_len; + + /** + * Mutex locking the batch in construction + */ + mutex_t *mutex; + + /** + * Flag set while processing + */ + bool fatal_error; + + /** + * Flag set by IMC RequestHandshakeRetry() function + */ + bool request_handshake_retry; + + /** + * SendMessage() by IMC only allowed if flag is set + */ + bool send_msg; + + /** + * PDP server FQDN + */ + chunk_t pdp_server; + + /** + * PDP server port + */ + u_int16_t pdp_port; + + /** + * Mutual PB-TNC protocol enabled + */ + bool mutual; + + /** + * Mutual Capability message sent + */ + bool sent_mutual_capability; + +}; + +/** + * The following two functions are shared with the tnccs_20_server class + */ +void tnccs_20_handle_ietf_error_msg(pb_tnc_msg_t *msg, bool *fatal_error) +{ + pb_error_msg_t *err_msg; + u_int32_t vendor_id; + u_int16_t error_code; + bool fatal; + + err_msg = (pb_error_msg_t*)msg; + fatal = err_msg->get_fatal_flag(err_msg); + vendor_id = err_msg->get_vendor_id(err_msg); + error_code = err_msg->get_error_code(err_msg); + + if (fatal) + { + *fatal_error = TRUE; + } + + if (vendor_id == PEN_IETF) + { + switch (error_code) + { + case PB_ERROR_INVALID_PARAMETER: + case PB_ERROR_UNSUPPORTED_MANDATORY_MSG: + DBG1(DBG_TNC, "received %s PB-TNC error '%N' (offset %u bytes)", + fatal ? "fatal" : "non-fatal", + pb_tnc_error_code_names, error_code, + err_msg->get_offset(err_msg)); + break; + case PB_ERROR_VERSION_NOT_SUPPORTED: + DBG1(DBG_TNC, "received %s PB-TNC error '%N' " + "caused by bad version 0x%02x", + fatal ? "fatal" : "non-fatal", + pb_tnc_error_code_names, error_code, + err_msg->get_bad_version(err_msg)); + break; + case PB_ERROR_UNEXPECTED_BATCH_TYPE: + case PB_ERROR_LOCAL_ERROR: + default: + DBG1(DBG_TNC, "received %s PB-TNC error '%N'", + fatal ? "fatal" : "non-fatal", + pb_tnc_error_code_names, error_code); + break; + } + } + else + { + DBG1(DBG_TNC, "received %s PB-TNC error (%u) with Vendor ID 0x%06x", + fatal ? "fatal" : "non-fatal", error_code, vendor_id); + } +} + +bool tnccs_20_handle_ita_mutual_capability_msg(pb_tnc_msg_t *msg) +{ + pb_mutual_capability_msg_t *mutual_msg; + uint32_t protocols; + + if (!lib->settings->get_bool(lib->settings, + "%s.plugins.tnccs-20.mutual", FALSE, lib->ns)) + { + /* PB-TNC mutual capability disabled, ignore message */ + return FALSE; + } + + mutual_msg = (pb_mutual_capability_msg_t*)msg; + protocols = mutual_msg->get_protocols(mutual_msg); + + if (protocols & PB_MUTUAL_HALF_DUPLEX) + { + DBG1(DBG_TNC, "activating mutual PB-TNC %N protocol", + pb_tnc_mutual_protocol_type_names, PB_MUTUAL_HALF_DUPLEX); + return TRUE; + } + + return FALSE; +} + +/** + * If the batch type changes then delete all accumulated PB-TNC messages + */ +static void change_batch_type(private_tnccs_20_client_t *this, + pb_tnc_batch_type_t batch_type) +{ + pb_tnc_msg_t *msg; + + if (batch_type != this->batch_type) + { + if (this->batch_type != PB_BATCH_NONE) + { + DBG1(DBG_TNC, "cancelling PB-TNC %N batch", + pb_tnc_batch_type_names, this->batch_type); + + while (this->messages->remove_last(this->messages, + (void**)&msg) == SUCCESS) + { + msg->destroy(msg); + } + } + this->batch_type = batch_type; + } +} + +/** + * Handle a single PB-TNC IETF standard message according to its type + */ +static void handle_ietf_message(private_tnccs_20_client_t *this, pb_tnc_msg_t *msg) +{ + pen_type_t msg_type = msg->get_type(msg); + + switch (msg_type.type) + { + case PB_MSG_EXPERIMENTAL: + /* nothing to do */ + break; + case PB_MSG_PA: + { + pb_pa_msg_t *pa_msg; + pen_type_t msg_subtype; + u_int16_t imc_id, imv_id; + chunk_t msg_body; + bool excl; + enum_name_t *pa_subtype_names; + + pa_msg = (pb_pa_msg_t*)msg; + msg_subtype = pa_msg->get_subtype(pa_msg); + msg_body = pa_msg->get_body(pa_msg); + imc_id = pa_msg->get_collector_id(pa_msg); + imv_id = pa_msg->get_validator_id(pa_msg); + excl = pa_msg->get_exclusive_flag(pa_msg); + + pa_subtype_names = get_pa_subtype_names(msg_subtype.vendor_id); + if (pa_subtype_names) + { + DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x", + pen_names, msg_subtype.vendor_id, pa_subtype_names, + msg_subtype.type, msg_subtype.vendor_id, msg_subtype.type); + } + else + { + DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x", + pen_names, msg_subtype.vendor_id, msg_subtype.vendor_id, + msg_subtype.type); + } + this->send_msg = TRUE; + tnc->imcs->receive_message(tnc->imcs, this->connection_id, + excl, msg_body.ptr, msg_body.len, + msg_subtype.vendor_id, + msg_subtype.type, imv_id, imc_id); + this->send_msg = FALSE; + break; + } + case PB_MSG_ASSESSMENT_RESULT: + { + pb_assessment_result_msg_t *assess_msg; + u_int32_t result; + + assess_msg = (pb_assessment_result_msg_t*)msg; + result = assess_msg->get_assessment_result(assess_msg); + DBG1(DBG_TNC, "PB-TNC assessment result is '%N'", + TNC_IMV_Evaluation_Result_names, result); + break; + } + case PB_MSG_ACCESS_RECOMMENDATION: + { + pb_access_recommendation_msg_t *rec_msg; + pb_access_recommendation_code_t rec; + TNC_ConnectionState state = TNC_CONNECTION_STATE_ACCESS_NONE; + + rec_msg = (pb_access_recommendation_msg_t*)msg; + rec = rec_msg->get_access_recommendation(rec_msg); + DBG1(DBG_TNC, "PB-TNC access recommendation is '%N'", + pb_access_recommendation_code_names, rec); + switch (rec) + { + case PB_REC_ACCESS_ALLOWED: + state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; + break; + case PB_REC_ACCESS_DENIED: + state = TNC_CONNECTION_STATE_ACCESS_NONE; + break; + case PB_REC_QUARANTINED: + state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; + } + tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, + state); + break; + } + case PB_MSG_REMEDIATION_PARAMETERS: + { + pb_remediation_parameters_msg_t *rem_msg; + pen_type_t parameters_type; + chunk_t parameters, string, lang_code; + + rem_msg = (pb_remediation_parameters_msg_t*)msg; + parameters_type = rem_msg->get_parameters_type(rem_msg); + parameters = rem_msg->get_parameters(rem_msg); + + if (parameters_type.vendor_id == PEN_IETF) + { + switch (parameters_type.type) + { + case PB_REMEDIATION_URI: + DBG1(DBG_TNC, "remediation uri: %.*s", + parameters.len, parameters.ptr); + break; + case PB_REMEDIATION_STRING: + string = rem_msg->get_string(rem_msg, &lang_code); + DBG1(DBG_TNC, "remediation string: [%.*s]\n%.*s", + lang_code.len, lang_code.ptr, + string.len, string.ptr); + break; + default: + DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); + } + } + else + { + DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); + } + break; + } + case PB_MSG_ERROR: + tnccs_20_handle_ietf_error_msg(msg, &this->fatal_error); + break; + case PB_MSG_REASON_STRING: + { + pb_reason_string_msg_t *reason_msg; + chunk_t reason_string, language_code; + + reason_msg = (pb_reason_string_msg_t*)msg; + reason_string = reason_msg->get_reason_string(reason_msg); + language_code = reason_msg->get_language_code(reason_msg); + DBG1(DBG_TNC, "reason string is '%.*s' [%.*s]", + (int)reason_string.len, reason_string.ptr, + (int)language_code.len, language_code.ptr); + break; + } + default: + break; + } +} + +/** + * Handle a single PB-TNC TCG standard message according to its type + */ +static void handle_tcg_message(private_tnccs_20_client_t *this, pb_tnc_msg_t *msg) +{ + pen_type_t msg_type = msg->get_type(msg); + + switch (msg_type.type) + { + case PB_TCG_MSG_PDP_REFERRAL: + { + pb_pdp_referral_msg_t *pdp_msg; + pen_type_t pdp_id_type; + u_int8_t pdp_protocol; + + pdp_msg = (pb_pdp_referral_msg_t*)msg; + pdp_id_type = pdp_msg->get_identifier_type(pdp_msg); + + if (pdp_id_type.vendor_id == PEN_TCG && + pdp_id_type.type == PB_PDP_ID_FQDN) + { + this->pdp_server = chunk_clone(pdp_msg->get_fqdn(pdp_msg, + &pdp_protocol, &this->pdp_port)); + if (pdp_protocol != 0) + { + DBG1(DBG_TNC, "unsupported PDP transport protocol"); + break; + } + DBG1(DBG_TNC, "PDP server '%.*s' is listening on port %u", + this->pdp_server.len, this->pdp_server.ptr, + this->pdp_port); + } + break; + } + default: + break; + } +} + +/** + * Handle a single PB-TNC ITA standard message according to its type + */ +static void handle_ita_message(private_tnccs_20_client_t *this, pb_tnc_msg_t *msg) +{ + pen_type_t msg_type = msg->get_type(msg); + + switch (msg_type.type) + { + case PB_ITA_MSG_MUTUAL_CAPABILITY: + this->mutual = tnccs_20_handle_ita_mutual_capability_msg(msg); + break; + default: + break; + } +} + +/** + * Handle a single PB-TNC message according to its type + */ +static void handle_message(private_tnccs_20_client_t *this, pb_tnc_msg_t *msg) +{ + pen_type_t msg_type = msg->get_type(msg); + + switch (msg_type.vendor_id) + { + case PEN_IETF: + handle_ietf_message(this, msg); + break; + case PEN_TCG: + handle_tcg_message(this, msg); + break; + case PEN_ITA: + handle_ita_message(this, msg); + break; + default: + break; + } +} + +/** + * Build a CRETRY batch + */ +static void build_retry_batch(private_tnccs_20_client_t *this) +{ + if (this->batch_type == PB_BATCH_CRETRY) + { + /* retry batch has already been selected */ + return; + } + change_batch_type(this, PB_BATCH_CRETRY); +} + +METHOD(tnccs_20_handler_t, process, status_t, + private_tnccs_20_client_t *this, pb_tnc_batch_t *batch) +{ + pb_tnc_batch_type_t batch_type; + status_t status; + + batch_type = batch->get_type(batch); + + DBG1(DBG_TNC, "processing PB-TNC %N batch for Connection ID %d", + pb_tnc_batch_type_names, batch_type, this->connection_id); + + status = batch->process(batch, this->state_machine); + + if (status != FAILED) + { + enumerator_t *enumerator; + pb_tnc_msg_t *msg; + bool empty = TRUE; + + if (batch_type == PB_BATCH_SRETRY) + { + /* Restart the measurements */ + tnc->imcs->notify_connection_change(tnc->imcs, + this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE); + this->send_msg = TRUE; + tnc->imcs->begin_handshake(tnc->imcs, this->connection_id); + this->send_msg = FALSE; + } + + enumerator = batch->create_msg_enumerator(batch); + while (enumerator->enumerate(enumerator, &msg)) + { + handle_message(this, msg); + empty = FALSE; + } + enumerator->destroy(enumerator); + + /* received a CLOSE batch from PB-TNC server */ + if (batch_type == PB_BATCH_CLOSE) + { + return empty ? SUCCESS : FAILED; + } + + this->send_msg = TRUE; + tnc->imcs->batch_ending(tnc->imcs, this->connection_id); + this->send_msg = FALSE; + } + + switch (status) + { + case FAILED: + this->fatal_error = TRUE; + status = VERIFY_ERROR; + break; + case VERIFY_ERROR: + break; + case SUCCESS: + default: + status = NEED_MORE; + break; + } + + return status; +} + +METHOD(tnccs_20_handler_t, build, status_t, + private_tnccs_20_client_t *this, void *buf, size_t *buflen, size_t *msglen) +{ + status_t status; + pb_tnc_state_t state; + + state = this->state_machine->get_state(this->state_machine); + + if (this->fatal_error && state == PB_STATE_END) + { + DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection"); + return FAILED; + } + + /* Do not allow any asynchronous IMCs to add additional messages */ + this->mutex->lock(this->mutex); + + if (this->request_handshake_retry) + { + if (state != PB_STATE_INIT) + { + build_retry_batch(this); + } + + /* Reset the flag for the next handshake retry request */ + this->request_handshake_retry = FALSE; + } + + if (this->batch_type == PB_BATCH_NONE) + { + switch (state) + { + case PB_STATE_CLIENT_WORKING: + DBG2(DBG_TNC, "no client data to send, " + "sending empty PB-TNC CDATA batch"); + this->batch_type = PB_BATCH_CDATA; + break; + case PB_STATE_DECIDED: + /** + * In the DECIDED state and if no CRETRY is under way, + * a PB-TNC client replies with an empty CLOSE batch. + */ + this->batch_type = PB_BATCH_CLOSE; + break; + default: + break; + } + } + + if (this->batch_type != PB_BATCH_NONE) + { + pb_tnc_batch_t *batch; + pb_tnc_msg_t *msg; + chunk_t data; + int msg_count; + enumerator_t *enumerator; + + if (this->state_machine->send_batch(this->state_machine, this->batch_type)) + { + batch = pb_tnc_batch_create(FALSE, this->batch_type, + min(this->max_batch_len, *buflen)); + + enumerator = this->messages->create_enumerator(this->messages); + while (enumerator->enumerate(enumerator, &msg)) + { + if (batch->add_msg(batch, msg)) + { + this->messages->remove_at(this->messages, enumerator); + } + else + { + break; + } + } + enumerator->destroy(enumerator); + + batch->build(batch); + data = batch->get_encoding(batch); + DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u", + pb_tnc_batch_type_names, this->batch_type, data.len, + this->connection_id); + DBG3(DBG_TNC, "%B", &data); + + *buflen = data.len; + *msglen = 0; + memcpy(buf, data.ptr, *buflen); + batch->destroy(batch); + + msg_count = this->messages->get_count(this->messages); + if (msg_count) + { + DBG2(DBG_TNC, "queued %d PB-TNC message%s for next %N batch", + msg_count, (msg_count == 1) ? "" : "s", + pb_tnc_batch_type_names, this->batch_type); + } + else + { + this->batch_type = PB_BATCH_NONE; + } + + status = ALREADY_DONE; + } + else + { + change_batch_type(this, PB_BATCH_NONE); + status = INVALID_STATE; + } + } + else + { + DBG1(DBG_TNC, "no PB-TNC batch to send"); + status = INVALID_STATE; + } + this->mutex->unlock(this->mutex); + + return status; +} + +METHOD(tnccs_20_handler_t, begin_handshake, void, + private_tnccs_20_client_t *this, bool mutual) +{ + pb_tnc_msg_t *msg; + char *pref_lang; + + tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, + TNC_CONNECTION_STATE_HANDSHAKE); + + /* Announce PB-TNC Mutual Capability if activated */ + this->sent_mutual_capability = mutual; + + if (!mutual && lib->settings->get_bool(lib->settings, + "%s.plugins.tnccs-20.mutual", FALSE, lib->ns)) + { + pb_tnc_mutual_protocol_type_t protocols; + + protocols = PB_MUTUAL_HALF_DUPLEX; + DBG2(DBG_TNC, "proposing PB-TNC mutual %N protocol", + pb_tnc_mutual_protocol_type_names, PB_MUTUAL_HALF_DUPLEX); + msg = pb_mutual_capability_msg_create(protocols); + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg); + this->mutex->unlock(this->mutex); + this->sent_mutual_capability = TRUE; + } + + /* Create PB-TNC Language Preference message */ + pref_lang = tnc->imcs->get_preferred_language(tnc->imcs); + msg = pb_language_preference_msg_create(chunk_create(pref_lang, + strlen(pref_lang))); + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg); + this->mutex->unlock(this->mutex); + + this->send_msg = TRUE; + tnc->imcs->begin_handshake(tnc->imcs, this->connection_id); + this->send_msg = FALSE; + + /* Send a PB-Noskip-Test message for testing purposes */ + if (lib->settings->get_bool(lib->settings, + "%s.plugins.tnccs-20.tests.pb_tnc_noskip", FALSE, lib->ns)) + { + msg = pb_noskip_test_msg_create(); + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg); + this->mutex->unlock(this->mutex); + } +} + +METHOD(tnccs_20_handler_t, get_send_flag, bool, + private_tnccs_20_client_t *this) +{ + return this->send_msg; +} + +METHOD(tnccs_20_handler_t, get_mutual, bool, + private_tnccs_20_client_t *this) +{ + return this->mutual; +} + +METHOD(tnccs_20_handler_t, get_state, pb_tnc_state_t, + private_tnccs_20_client_t *this) +{ + return this->state_machine->get_state(this->state_machine); +} + +METHOD(tnccs_20_handler_t, add_msg, void, + private_tnccs_20_client_t *this, pb_tnc_msg_t *msg) +{ + /* adding PA message to CDATA batch only */ + this->mutex->lock(this->mutex); + if (this->batch_type == PB_BATCH_NONE) + { + this->batch_type = PB_BATCH_CDATA; + } + if (this->batch_type == PB_BATCH_CDATA) + { + this->messages->insert_last(this->messages, msg); + } + else + { + msg->destroy(msg); + } + this->mutex->unlock(this->mutex); +} + +METHOD(tnccs_20_handler_t, handle_errors, void, + private_tnccs_20_client_t *this, pb_tnc_batch_t *batch, + bool fatal_header_error) +{ + pb_tnc_msg_t *msg; + enumerator_t *enumerator; + + if (fatal_header_error || this->fatal_error) + { + this->mutex->lock(this->mutex); + change_batch_type(this, PB_BATCH_CLOSE); + this->mutex->unlock(this->mutex); + } + + enumerator = batch->create_error_enumerator(batch); + while (enumerator->enumerate(enumerator, &msg)) + { + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg->get_ref(msg)); + this->mutex->unlock(this->mutex); + } + enumerator->destroy(enumerator); +} + +METHOD(tnccs_20_handler_t, destroy, void, + private_tnccs_20_client_t *this) +{ + if (this->connection_id) + { + tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, FALSE); + } + this->state_machine->destroy(this->state_machine); + this->mutex->destroy(this->mutex); + this->messages->destroy_offset(this->messages, + offsetof(pb_tnc_msg_t, destroy)); + free(this->pdp_server.ptr); + free(this); +} + +METHOD(tnccs_20_client_t, get_pdp_server, chunk_t, + private_tnccs_20_client_t *this, u_int16_t *port) +{ + *port = this->pdp_port; + + return this->pdp_server; +} + +/** + * See header + */ +tnccs_20_handler_t* tnccs_20_client_create(tnccs_t *tnccs, + tnccs_send_message_t send_msg, + size_t max_batch_len, + size_t max_msg_len) +{ + private_tnccs_20_client_t *this; + + INIT(this, + .public = { + .handler = { + .process = _process, + .build = _build, + .begin_handshake = _begin_handshake, + .get_send_flag = _get_send_flag, + .get_mutual = _get_mutual, + .get_state = _get_state, + .add_msg = _add_msg, + .handle_errors = _handle_errors, + .destroy = _destroy, + }, + .get_pdp_server = _get_pdp_server, + }, + .state_machine = pb_tnc_state_machine_create(FALSE), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .messages = linked_list_create(), + .batch_type = PB_BATCH_CDATA, + .max_batch_len = max_batch_len, + ); + + this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, + TNCCS_2_0, tnccs, send_msg, + &this->request_handshake_retry, + max_msg_len, NULL); + if (!this->connection_id) + { + destroy(this); + return NULL; + } + tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, + TNC_CONNECTION_STATE_CREATE); + + return &this->public.handler; +} diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_client.h b/src/libtnccs/plugins/tnccs_20/tnccs_20_client.h new file mode 100644 index 000000000..7a5f33ebc --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_client.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 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 tnccs_20_client_h tnccs_20_client + * @{ @ingroup tnccs_20 + */ + +#ifndef TNCCS_20_CLIENT_H_ +#define TNCCS_20_CLIENT_H_ + +#include <library.h> + +#include <tnc/tnccs/tnccs.h> + +#include "tnccs_20_handler.h" + +typedef struct tnccs_20_client_t tnccs_20_client_t; + +/** + * Interface for a TNC client + */ +struct tnccs_20_client_t { + + /** + * IF-TNCCS 2.0 protocol handler interface + */ + tnccs_20_handler_t handler; + + /** + * Get PDP server information if available + * + * @param port PT-TLS port of the PDP server + * @return FQDN of PDP server + */ + chunk_t (*get_pdp_server)(tnccs_20_client_t *this, u_int16_t *port); + +}; + +/** + * Create an instance of the TNC IF-TNCCS 2.0 client-side protocol handler. + * + * @param tnccs TNC IF-TNCCS 2.0 stack + * @param send_msg TNF IF-TNCCS 2.0 send message callback function + * @param max_batch_len Maximum PB-TNC batch size + * @param max_msg_len Maximum PA-TNC message size + */ +tnccs_20_handler_t* tnccs_20_client_create(tnccs_t *tnccs, + tnccs_send_message_t send_msg, + size_t max_batch_len, + size_t max_msg_len); + +#endif /** TNCCS_20_CLIENT_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_handler.h b/src/libtnccs/plugins/tnccs_20/tnccs_20_handler.h new file mode 100644 index 000000000..5c4d7a7b4 --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_handler.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 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 tnccs_20_handler_h tnccs_20_handler + * @{ @ingroup tnccs_20 + */ + +#ifndef TNCCS_20_HANDLER_H_ +#define TNCCS_20_HANDLER_H_ + +#include <library.h> + +#include "batch/pb_tnc_batch.h" +#include "messages/pb_tnc_msg.h" + +typedef struct tnccs_20_handler_t tnccs_20_handler_t; + +/** + * Interface for an IF-TNCCS 2.0 protocol handler + */ +struct tnccs_20_handler_t { + + /** + * Process content of received PB-TNC batch + * + * @param batch PB-TNC batch to be processed + * @return status + */ + status_t (*process)(tnccs_20_handler_t *this, pb_tnc_batch_t *batch); + + /** + * Build PB-TNC batch to be sent + * + * @param buf buffer to write PB-TNC batch to + * @param buflen size of buffer, receives bytes written + * @param msglen receives size of all PB-TNCH batch + * @return status + */ + status_t (*build)(tnccs_20_handler_t *this, void *buf, size_t *buflen, + size_t *msglen); + + /** + * Put the IMCs or IMVs into the handshake state + * + * @param mutual TRUE if PB-TNC mutual mode is already established + */ + void (*begin_handshake)(tnccs_20_handler_t *this, bool mutual); + + /** + * Indicates if IMCs or IMVs are allowed to send PA-TNC messages + * + * @return TRUE if allowed to send + */ + bool (*get_send_flag)(tnccs_20_handler_t *this); + + /** + * Indicates if the PB-TNC mutual protocol has been enabled + * + * @return TRUE if enabled + */ + bool (*get_mutual)(tnccs_20_handler_t *this); + + /** + * Get state of the PB-TNC protocol + * + * @return PB-TNC state + */ + pb_tnc_state_t (*get_state)(tnccs_20_handler_t *this); + + /** + * Add a PB-PA message to the handler's message queue + * + * @param msg PB-PA message to be added + */ + void (*add_msg)(tnccs_20_handler_t *this, pb_tnc_msg_t *msg); + + /** + * Handle errors that occurred during PB-TNC batch header processing + * + * @param batch batch where a fatal error occurred + * @param fatal_header_error TRUE if fatal error in batch header + */ + void (*handle_errors)(tnccs_20_handler_t *this, pb_tnc_batch_t *batch, + bool fatal_header_error); + + /** + * Destroys a tnccs_20_handler_t object. + */ + void (*destroy)(tnccs_20_handler_t *this); +}; + +#endif /** TNCCS_20_HANDLER_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h b/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h index 1c4ecf4c9..5073fbe7c 100644 --- a/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_plugin.h @@ -15,7 +15,7 @@ /** * @defgroup tnccs_20 tnccs_20 - * @ingroup cplugins + * @ingroup tplugins * * @defgroup tnccs_20_plugin tnccs_20_plugin * @{ @ingroup tnccs_20 diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_server.c b/src/libtnccs/plugins/tnccs_20/tnccs_20_server.c new file mode 100644 index 000000000..038fc178b --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_server.c @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2015 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 "tnccs_20_server.h" +#include "messages/pb_tnc_msg.h" +#include "messages/ietf/pb_pa_msg.h" +#include "messages/ietf/pb_error_msg.h" +#include "messages/ietf/pb_assessment_result_msg.h" +#include "messages/ietf/pb_access_recommendation_msg.h" +#include "messages/ietf/pb_remediation_parameters_msg.h" +#include "messages/ietf/pb_reason_string_msg.h" +#include "messages/ietf/pb_language_preference_msg.h" +#include "messages/ita/pb_mutual_capability_msg.h" +#include "messages/ita/pb_noskip_test_msg.h" +#include "messages/tcg/pb_pdp_referral_msg.h" +#include "state_machine/pb_tnc_state_machine.h" + +#include <tncif_names.h> +#include <tncif_pa_subtypes.h> + +#include <tnc/tnc.h> +#include <tnc/tnccs/tnccs_manager.h> +#include <tnc/imv/imv_manager.h> + +#include <threading/mutex.h> +#include <utils/debug.h> +#include <collections/linked_list.h> +#include <pen/pen.h> + +typedef struct private_tnccs_20_server_t private_tnccs_20_server_t; + +/** + * Private data of a tnccs_20_server_t object. + */ +struct private_tnccs_20_server_t { + + /** + * Public tnccs_20_server_t interface. + */ + tnccs_20_server_t public; + + /** + * PB-TNC State Machine + */ + pb_tnc_state_machine_t *state_machine; + + /** + * Connection ID assigned to this TNCCS connection + */ + TNC_ConnectionID connection_id; + + /** + * PB-TNC messages to be sent + */ + linked_list_t *messages; + + /** + * Type of PB-TNC batch being constructed + */ + pb_tnc_batch_type_t batch_type; + + /** + * Maximum PB-TNC batch size + */ + size_t max_batch_len; + + /** + * Mutex locking the batch in construction + */ + mutex_t *mutex; + + /** + * Flag set while processing + */ + bool fatal_error; + + /** + * Flag set by IMC/IMV RequestHandshakeRetry() function + */ + bool request_handshake_retry; + + /** + * SendMessage() by IMV only allowed if flag is set + */ + bool send_msg; + + /** + * Set of IMV recommendations + */ + recommendations_t *recs; + + /** + * TNC IF-T transport protocol for EAP methods + */ + bool eap_transport; + + /** + * Mutual PB-TNC protocol enabled + */ + bool mutual; + + /** + * Mutual Capability message sent + */ + bool sent_mutual_capability; + +}; + +/** + * The following two functions are shared with the tnccs_20_server class + */ +extern void tnccs_20_handle_ietf_error_msg(pb_tnc_msg_t *msg, + bool *fatal_error); +extern bool tnccs_20_handle_ita_mutual_capability_msg(pb_tnc_msg_t *msg); + +/** + * If the batch type changes then delete all accumulated PB-TNC messages + */ +static void change_batch_type(private_tnccs_20_server_t *this, + pb_tnc_batch_type_t batch_type) +{ + pb_tnc_msg_t *msg; + + if (batch_type != this->batch_type) + { + if (this->batch_type != PB_BATCH_NONE) + { + DBG1(DBG_TNC, "cancelling PB-TNC %N batch", + pb_tnc_batch_type_names, this->batch_type); + + while (this->messages->remove_last(this->messages, + (void**)&msg) == SUCCESS) + { + msg->destroy(msg); + } + } + this->batch_type = batch_type; + } +} + +/** + * Handle a single PB-TNC IETF standard message according to its type + */ +static void handle_ietf_message(private_tnccs_20_server_t *this, pb_tnc_msg_t *msg) +{ + pen_type_t msg_type = msg->get_type(msg); + + switch (msg_type.type) + { + case PB_MSG_EXPERIMENTAL: + /* nothing to do */ + break; + case PB_MSG_PA: + { + pb_pa_msg_t *pa_msg; + pen_type_t msg_subtype; + u_int16_t imc_id, imv_id; + chunk_t msg_body; + bool excl; + enum_name_t *pa_subtype_names; + + pa_msg = (pb_pa_msg_t*)msg; + msg_subtype = pa_msg->get_subtype(pa_msg); + msg_body = pa_msg->get_body(pa_msg); + imc_id = pa_msg->get_collector_id(pa_msg); + imv_id = pa_msg->get_validator_id(pa_msg); + excl = pa_msg->get_exclusive_flag(pa_msg); + + pa_subtype_names = get_pa_subtype_names(msg_subtype.vendor_id); + if (pa_subtype_names) + { + DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x", + pen_names, msg_subtype.vendor_id, pa_subtype_names, + msg_subtype.type, msg_subtype.vendor_id, msg_subtype.type); + } + else + { + DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x", + pen_names, msg_subtype.vendor_id, msg_subtype.vendor_id, + msg_subtype.type); + } + this->send_msg = TRUE; + tnc->imvs->receive_message(tnc->imvs, this->connection_id, + excl, msg_body.ptr, msg_body.len, + msg_subtype.vendor_id, + msg_subtype.type, imc_id, imv_id); + this->send_msg = FALSE; + break; + } + case PB_MSG_ERROR: + tnccs_20_handle_ietf_error_msg(msg, &this->fatal_error); + break; + case PB_MSG_LANGUAGE_PREFERENCE: + { + pb_language_preference_msg_t *lang_msg; + chunk_t lang; + + lang_msg = (pb_language_preference_msg_t*)msg; + lang = lang_msg->get_language_preference(lang_msg); + DBG2(DBG_TNC, "setting language preference to '%.*s'", + (int)lang.len, lang.ptr); + this->recs->set_preferred_language(this->recs, lang); + break; + } + default: + break; + } +} + +/** + * Handle a single PB-TNC ITA standard message according to its type + */ +static void handle_ita_message(private_tnccs_20_server_t *this, pb_tnc_msg_t *msg) +{ + pen_type_t msg_type = msg->get_type(msg); + + switch (msg_type.type) + { + case PB_ITA_MSG_MUTUAL_CAPABILITY: + this->mutual = tnccs_20_handle_ita_mutual_capability_msg(msg); + + /* Respond with PB-TNC Mutual Capability message if necessary */ + if (this->mutual && !this->sent_mutual_capability) + { + msg = pb_mutual_capability_msg_create(PB_MUTUAL_HALF_DUPLEX); + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg); + this->mutex->unlock(this->mutex); + this->sent_mutual_capability = TRUE; + } + break; + default: + break; + } +} + +/** + * Handle a single PB-TNC message according to its type + */ +static void handle_message(private_tnccs_20_server_t *this, pb_tnc_msg_t *msg) +{ + pen_type_t msg_type = msg->get_type(msg); + + switch (msg_type.vendor_id) + { + case PEN_IETF: + handle_ietf_message(this, msg); + break; + case PEN_ITA: + handle_ita_message(this, msg); + break; + default: + break; + } +} + +/** + * Build an SRETRY batch + */ +static void build_retry_batch(private_tnccs_20_server_t *this) +{ + if (this->batch_type == PB_BATCH_SRETRY) + { + /* retry batch has already been selected */ + return; + } + change_batch_type(this, PB_BATCH_SRETRY); + + this->recs->clear_recommendation(this->recs); + tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, + TNC_CONNECTION_STATE_HANDSHAKE); +} + +METHOD(tnccs_20_handler_t, process, status_t, + private_tnccs_20_server_t *this, pb_tnc_batch_t *batch) +{ + pb_tnc_batch_type_t batch_type; + status_t status; + + batch_type = batch->get_type(batch); + + DBG1(DBG_TNC, "processing PB-TNC %N batch for Connection ID %d", + pb_tnc_batch_type_names, batch_type, this->connection_id); + status = batch->process(batch, this->state_machine); + + if (status != FAILED) + { + enumerator_t *enumerator; + pb_tnc_msg_t *msg; + bool empty = TRUE; + + if (batch_type == PB_BATCH_CRETRY) + { + /* Send an SRETRY batch in response */ + this->mutex->lock(this->mutex); + build_retry_batch(this); + this->mutex->unlock(this->mutex); + } + + enumerator = batch->create_msg_enumerator(batch); + while (enumerator->enumerate(enumerator, &msg)) + { + handle_message(this, msg); + empty = FALSE; + } + enumerator->destroy(enumerator); + + /* received a CLOSE batch from PB-TNC client */ + if (batch_type == PB_BATCH_CLOSE) + { + return empty ? SUCCESS : FAILED; + } + + this->send_msg = TRUE; + tnc->imvs->batch_ending(tnc->imvs, this->connection_id); + this->send_msg = FALSE; + } + + switch (status) + { + case FAILED: + this->fatal_error = TRUE; + status = VERIFY_ERROR; + break; + case VERIFY_ERROR: + break; + case SUCCESS: + default: + status = NEED_MORE; + break; + } + + return status; +} + +/** + * Build a RESULT batch if a final recommendation is available + */ +static void check_and_build_recommendation(private_tnccs_20_server_t *this) +{ + TNC_IMV_Action_Recommendation rec; + TNC_IMV_Evaluation_Result eval; + TNC_ConnectionState state; + TNC_IMVID id; + chunk_t reason, language; + enumerator_t *enumerator; + pb_tnc_msg_t *msg; + pb_access_recommendation_code_t pb_rec; + + if (!this->recs->have_recommendation(this->recs, &rec, &eval)) + { + tnc->imvs->solicit_recommendation(tnc->imvs, this->connection_id); + } + if (this->recs->have_recommendation(this->recs, &rec, &eval)) + { + this->batch_type = PB_BATCH_RESULT; + + msg = pb_assessment_result_msg_create(eval); + this->messages->insert_last(this->messages, msg); + + /** + * Map IMV Action Recommendation codes to PB Access Recommendation codes + * and communicate Access Recommendation to IMVs + */ + switch (rec) + { + case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: + state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; + pb_rec = PB_REC_ACCESS_ALLOWED; + break; + case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: + state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; + pb_rec = PB_REC_QUARANTINED; + break; + case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: + case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: + default: + state = TNC_CONNECTION_STATE_ACCESS_NONE; + pb_rec = PB_REC_ACCESS_DENIED; + } + tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, + state); + + msg = pb_access_recommendation_msg_create(pb_rec); + this->messages->insert_last(this->messages, msg); + + enumerator = this->recs->create_reason_enumerator(this->recs); + while (enumerator->enumerate(enumerator, &id, &reason, &language)) + { + msg = pb_reason_string_msg_create(reason, language); + this->messages->insert_last(this->messages, msg); + } + enumerator->destroy(enumerator); + } +} + +METHOD(tnccs_20_handler_t, build, status_t, + private_tnccs_20_server_t *this, void *buf, size_t *buflen, size_t *msglen) +{ + status_t status; + pb_tnc_state_t state; + + state = this->state_machine->get_state(this->state_machine); + + if (this->fatal_error && state == PB_STATE_END) + { + DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection"); + return FAILED; + } + + /* Do not allow any asynchronous IMVs to add additional messages */ + this->mutex->lock(this->mutex); + + if (this->request_handshake_retry) + { + if (state != PB_STATE_INIT) + { + build_retry_batch(this); + } + + /* Reset the flag for the next handshake retry request */ + this->request_handshake_retry = FALSE; + } + + if (state == PB_STATE_SERVER_WORKING && + this->recs->have_recommendation(this->recs, NULL, NULL)) + { + check_and_build_recommendation(this); + } + + if (this->batch_type == PB_BATCH_NONE) + { + if (state == PB_STATE_SERVER_WORKING) + { + if (this->state_machine->get_empty_cdata(this->state_machine)) + { + check_and_build_recommendation(this); + } + else + { + DBG2(DBG_TNC, "no recommendation available yet, " + "sending empty PB-TNC SDATA batch"); + this->batch_type = PB_BATCH_SDATA; + } + } + } + + if (this->batch_type != PB_BATCH_NONE) + { + pb_tnc_batch_t *batch; + pb_tnc_msg_t *msg; + chunk_t data; + int msg_count; + enumerator_t *enumerator; + + if (this->state_machine->send_batch(this->state_machine, this->batch_type)) + { + batch = pb_tnc_batch_create(TRUE, this->batch_type, + min(this->max_batch_len, *buflen)); + + enumerator = this->messages->create_enumerator(this->messages); + while (enumerator->enumerate(enumerator, &msg)) + { + if (batch->add_msg(batch, msg)) + { + this->messages->remove_at(this->messages, enumerator); + } + else + { + break; + } + } + enumerator->destroy(enumerator); + + batch->build(batch); + data = batch->get_encoding(batch); + DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u", + pb_tnc_batch_type_names, this->batch_type, data.len, + this->connection_id); + DBG3(DBG_TNC, "%B", &data); + + *buflen = data.len; + *msglen = 0; + memcpy(buf, data.ptr, *buflen); + batch->destroy(batch); + + msg_count = this->messages->get_count(this->messages); + if (msg_count) + { + DBG2(DBG_TNC, "queued %d PB-TNC message%s for next %N batch", + msg_count, (msg_count == 1) ? "" : "s", + pb_tnc_batch_type_names, this->batch_type); + } + else + { + this->batch_type = PB_BATCH_NONE; + } + + status = ALREADY_DONE; + } + else + { + change_batch_type(this, PB_BATCH_NONE); + status = INVALID_STATE; + } + } + else + { + DBG1(DBG_TNC, "no PB-TNC batch to send"); + status = INVALID_STATE; + } + this->mutex->unlock(this->mutex); + + return status; +} + +METHOD(tnccs_20_handler_t, begin_handshake, void, + private_tnccs_20_server_t *this, bool mutual) +{ + pb_tnc_msg_t *msg; + identification_t *pdp_server; + u_int16_t *pdp_port; + + tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, + TNC_CONNECTION_STATE_HANDSHAKE); + + /* Send a PB-TNC TCG PDP Referral message if PDP is known */ + pdp_server = (identification_t*)lib->get(lib, "pt-tls-server"); + pdp_port = (u_int16_t*)lib->get(lib, "pt-tls-port"); + + if (this->eap_transport && pdp_server && pdp_port) + { + msg = pb_pdp_referral_msg_create_from_fqdn( + pdp_server->get_encoding(pdp_server), *pdp_port); + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg); + this->mutex->unlock(this->mutex); + } + + /* Send a PB-Noskip-Test message for testing purposes */ + if (lib->settings->get_bool(lib->settings, + "%s.plugins.tnccs-20.tests.pb_tnc_noskip", FALSE, lib->ns)) + { + msg = pb_noskip_test_msg_create(); + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg); + this->mutex->unlock(this->mutex); + } +} + +METHOD(tnccs_20_handler_t, get_send_flag, bool, + private_tnccs_20_server_t *this) +{ + return this->send_msg; +} + +METHOD(tnccs_20_handler_t, get_mutual, bool, + private_tnccs_20_server_t *this) +{ + return this->mutual; +} + +METHOD(tnccs_20_handler_t, get_state, pb_tnc_state_t, + private_tnccs_20_server_t *this) +{ + return this->state_machine->get_state(this->state_machine); +} + +METHOD(tnccs_20_handler_t, add_msg, void, + private_tnccs_20_server_t *this, pb_tnc_msg_t *msg) +{ + /* adding PA message to SDATA batch only */ + this->mutex->lock(this->mutex); + if (this->batch_type == PB_BATCH_NONE) + { + this->batch_type = PB_BATCH_SDATA; + } + if (this->batch_type == PB_BATCH_SDATA) + { + this->messages->insert_last(this->messages, msg); + } + else + { + msg->destroy(msg); + } + this->mutex->unlock(this->mutex); +} + +METHOD(tnccs_20_handler_t, handle_errors, void, + private_tnccs_20_server_t *this, pb_tnc_batch_t *batch, + bool fatal_header_error) +{ + pb_tnc_msg_t *msg; + enumerator_t *enumerator; + + if (fatal_header_error || this->fatal_error) + { + this->mutex->lock(this->mutex); + change_batch_type(this, PB_BATCH_CLOSE); + this->mutex->unlock(this->mutex); + } + + enumerator = batch->create_error_enumerator(batch); + while (enumerator->enumerate(enumerator, &msg)) + { + this->mutex->lock(this->mutex); + this->messages->insert_last(this->messages, msg->get_ref(msg)); + this->mutex->unlock(this->mutex); + } + enumerator->destroy(enumerator); +} + +METHOD(tnccs_20_handler_t, destroy, void, + private_tnccs_20_server_t *this) +{ + if (this->connection_id) + { + tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, TRUE); + } + this->state_machine->destroy(this->state_machine); + this->mutex->destroy(this->mutex); + this->messages->destroy_offset(this->messages, + offsetof(pb_tnc_msg_t, destroy)); + free(this); +} + +METHOD(tnccs_20_server_t, have_recommendation, bool, + private_tnccs_20_server_t *this, TNC_IMV_Action_Recommendation *rec, + TNC_IMV_Evaluation_Result *eval) +{ + return this->recs->have_recommendation(this->recs, rec, eval); +} + +/** + * See header + */ +tnccs_20_handler_t* tnccs_20_server_create(tnccs_t *tnccs, + tnccs_send_message_t send_msg, + size_t max_batch_len, + size_t max_msg_len, + bool eap_transport) +{ + private_tnccs_20_server_t *this; + + INIT(this, + .public = { + .handler = { + .process = _process, + .build = _build, + .begin_handshake = _begin_handshake, + .get_send_flag = _get_send_flag, + .get_mutual = _get_mutual, + .get_state = _get_state, + .add_msg = _add_msg, + .handle_errors = _handle_errors, + .destroy = _destroy, + }, + .have_recommendation = _have_recommendation, + }, + .state_machine = pb_tnc_state_machine_create(TRUE), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .messages = linked_list_create(), + .batch_type = PB_BATCH_SDATA, + .max_batch_len = max_batch_len, + .eap_transport = eap_transport, + ); + + this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, + TNCCS_2_0, tnccs, send_msg, + &this->request_handshake_retry, + max_msg_len, &this->recs); + if (!this->connection_id) + { + destroy(this); + return NULL; + } + tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, + TNC_CONNECTION_STATE_CREATE); + + return &this->public.handler; +} diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20_server.h b/src/libtnccs/plugins/tnccs_20/tnccs_20_server.h new file mode 100644 index 000000000..5833d1132 --- /dev/null +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20_server.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 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 tnccs_20_server_h tnccs_20_server + * @{ @ingroup tnccs_20 + */ + +#ifndef TNCCS_20_SERVER_H_ +#define TNCCS_20_SERVER_H_ + +#include <library.h> + +#include <tnc/tnccs/tnccs.h> + +#include "tnccs_20_handler.h" + +typedef struct tnccs_20_server_t tnccs_20_server_t; + +/** + * Interface for a TNC server + */ +struct tnccs_20_server_t { + + /** + * IF-TNCCS 2.0 protocol handler interface + */ + tnccs_20_handler_t handler; + + /** + * Check if an Action Recommendation is already available + * + * @param rec TNC Action Recommendation + * @param eval TNC Evaluation Result + * @return TRUE if Action Recommendation is + */ + bool (*have_recommendation)(tnccs_20_server_t *this, + TNC_IMV_Action_Recommendation *rec, + TNC_IMV_Evaluation_Result *eval); + +}; + +/** + * Create an instance of the TNC IF-TNCCS 2.0 server-side protocol handler. + * + * @param tnccs TNC IF-TNCCS 2.0 stack + * @param send_msg TNF IF-TNCCS 2.0 send message callback function + * @param max_batch_len Maximum PB-TNC batch size + * @param max_msg_len Maximum PA-TNC message size + * @param eap_transport TRUE if IF-T for EAP methods + */ +tnccs_20_handler_t* tnccs_20_server_create(tnccs_t *tnccs, + tnccs_send_message_t send_msg, + size_t max_batch_len, + size_t max_msg_len, + bool eap_transport); + + +#endif /** TNCCS_20_SERVER_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_dynamic/Makefile.in b/src/libtnccs/plugins/tnccs_dynamic/Makefile.in index 6a03df994..3f21a22d4 100644 --- a/src/libtnccs/plugins/tnccs_dynamic/Makefile.in +++ b/src/libtnccs/plugins/tnccs_dynamic/Makefile.in @@ -231,6 +231,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -291,10 +292,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -368,6 +371,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ diff --git a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c index e08236eb7..44b804fb2 100644 --- a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c +++ b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Andreas Steffen + * Copyright (C) 2011-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -34,12 +34,22 @@ struct private_tnccs_dynamic_t { /** * Server identity */ - identification_t *server; + identification_t *server_id; /** * Client identity */ - identification_t *peer; + identification_t *peer_id; + + /** + * Server IP address + */ + host_t *server_ip; + + /** + * Client IP address + */ + host_t *peer_ip; /** * Detected TNC IF-TNCCS stack @@ -109,8 +119,8 @@ METHOD(tls_t, process, status_t, DBG1(DBG_TNC, "%N protocol detected dynamically", tnccs_type_names, type); tnccs = tnc->tnccs->create_instance(tnc->tnccs, type, TRUE, - this->server, this->peer, this->transport, - this->callback); + this->server_id, this->peer_id, this->server_ip, + this->peer_ip, this->transport, this->callback); if (!tnccs) { DBG1(DBG_TNC, "N% protocol not supported", tnccs_type_names, type); @@ -137,14 +147,14 @@ METHOD(tls_t, is_server, bool, METHOD(tls_t, get_server_id, identification_t*, private_tnccs_dynamic_t *this) { - return this->server; + return this->server_id; } METHOD(tls_t, set_peer_id, void, private_tnccs_dynamic_t *this, identification_t *id) { - DESTROY_IF(this->peer); - this->peer = id->clone(id); + DESTROY_IF(this->peer_id); + this->peer_id = id->clone(id); if (this->tls) { this->tls->set_peer_id(this->tls, id); @@ -154,7 +164,7 @@ METHOD(tls_t, set_peer_id, void, METHOD(tls_t, get_peer_id, identification_t*, private_tnccs_dynamic_t *this) { - return this->peer; + return this->peer_id; } METHOD(tls_t, get_purpose, tls_purpose_t, @@ -181,12 +191,26 @@ METHOD(tls_t, destroy, void, if (ref_put(&this->ref)) { DESTROY_IF(this->tls); - this->server->destroy(this->server); - this->peer->destroy(this->peer); + this->server_id->destroy(this->server_id); + this->peer_id->destroy(this->peer_id); + this->server_ip->destroy(this->server_ip); + this->peer_ip->destroy(this->peer_ip); free(this); } } +METHOD(tnccs_t, get_server_ip, host_t*, + private_tnccs_dynamic_t *this) +{ + return this->server_ip; +} + +METHOD(tnccs_t, get_peer_ip, host_t*, + private_tnccs_dynamic_t *this) +{ + return this->peer_ip; +} + METHOD(tnccs_t, get_transport, tnc_ift_type_t, private_tnccs_dynamic_t *this) { @@ -229,9 +253,10 @@ METHOD(tnccs_t, get_ref, tnccs_t*, /** * See header */ -tnccs_t* tnccs_dynamic_create(bool is_server, - identification_t *server, identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb) +tnccs_t* tnccs_dynamic_create(bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb) { private_tnccs_dynamic_t *this; @@ -249,6 +274,8 @@ tnccs_t* tnccs_dynamic_create(bool is_server, .get_eap_msk = _get_eap_msk, .destroy = _destroy, }, + .get_server_ip = _get_server_ip, + .get_peer_ip = _get_peer_ip, .get_transport = _get_transport, .set_transport = _set_transport, .get_auth_type = _get_auth_type, @@ -256,8 +283,10 @@ tnccs_t* tnccs_dynamic_create(bool is_server, .get_pdp_server = _get_pdp_server, .get_ref = _get_ref, }, - .server = server->clone(server), - .peer = peer->clone(peer), + .server_id = server_id->clone(server_id), + .peer_id = peer_id->clone(peer_id), + .server_ip = server_ip->clone(server_ip), + .peer_ip = peer_ip->clone(peer_ip), .transport = transport, .callback = cb, .ref = 1, diff --git a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h index cbdc80b83..2e1141780 100644 --- a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h +++ b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Andreas Steffen + * Copyright (C) 2011-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -29,14 +29,17 @@ * Create an instance of a dynamic TNC IF-TNCCS protocol handler. * * @param is_server TRUE to act as TNC Server, FALSE for TNC Client - * @param server Server identity - * @param peer Client identity + * @param server_id Server identity + * @param peer_id Client identity + * @param server_ip Server IP address + * @param peer_ip Client IP address * @param transport Underlying IF-T transport protocol * @param cb Callback function if TNC Server, NULL if TNC Client * @return dynamic TNC IF-TNCCS protocol stack */ -tnccs_t* tnccs_dynamic_create(bool is_server, - identification_t *server, identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb); +tnccs_t* tnccs_dynamic_create(bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb); #endif /** TNCCS_DYNAMIC_H_ @}*/ diff --git a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h index b518e1278..97dd0df43 100644 --- a/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h +++ b/src/libtnccs/plugins/tnccs_dynamic/tnccs_dynamic_plugin.h @@ -15,7 +15,7 @@ /** * @defgroup tnccs_dynamic tnccs_dynamic - * @ingroup cplugins + * @ingroup tplugins * * @defgroup tnccs_dynamic_plugin tnccs_dynamic_plugin * @{ @ingroup tnccs_dynamic diff --git a/src/libtnccs/tnc/imc/imc.h b/src/libtnccs/tnc/imc/imc.h index 3ff7d5194..6d13f6bc5 100644 --- a/src/libtnccs/tnc/imc/imc.h +++ b/src/libtnccs/tnc/imc/imc.h @@ -15,7 +15,7 @@ /** * @defgroup imc imc - * @ingroup tnc + * @ingroup libtnccs * * @defgroup imct imc * @{ @ingroup imc diff --git a/src/libtnccs/tnc/imv/imv.h b/src/libtnccs/tnc/imv/imv.h index 3716532d6..fbc26a1e7 100644 --- a/src/libtnccs/tnc/imv/imv.h +++ b/src/libtnccs/tnc/imv/imv.h @@ -15,7 +15,7 @@ /** * @defgroup imv imv - * @ingroup tnc + * @ingroup libtnccs * * @defgroup imvt imv * @{ @ingroup imv diff --git a/src/libtnccs/tnc/tnc.h b/src/libtnccs/tnc/tnc.h index e5a4a2959..7bf8c84b7 100644 --- a/src/libtnccs/tnc/tnc.h +++ b/src/libtnccs/tnc/tnc.h @@ -14,9 +14,12 @@ */ /** - * @defgroup tnc tnc + * @defgroup libtnccs libtnccs * - * @addtogroup tnc + * @defgroup tplugins plugins + * @ingroup libtnccs + * + * @addtogroup libtnccs * @{ */ diff --git a/src/libtnccs/tnc/tnccs/tnccs.h b/src/libtnccs/tnc/tnccs/tnccs.h index eefd5565d..8ff295bcc 100644 --- a/src/libtnccs/tnc/tnccs/tnccs.h +++ b/src/libtnccs/tnc/tnccs/tnccs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,7 +15,7 @@ /** * @defgroup tnccs tnccs - * @ingroup tnc + * @ingroup libtnccs * * @defgroup tnccst tnccs * @{ @ingroup tnccs @@ -87,6 +87,20 @@ struct tnccs_t { tls_t tls; /** + * Get server IP address + * + * @return Server IP address + */ + host_t* (*get_server_ip)(tnccs_t *this); + + /** + * Get peer IP address + * + * @return Peer IP address + */ + host_t* (*get_peer_ip)(tnccs_t *this); + + /** * Get underlying TNC IF-T transport protocol * * @return TNC IF-T transport protocol @@ -135,15 +149,19 @@ struct tnccs_t { * Constructor definition for a pluggable TNCCS protocol implementation. * * @param is_server TRUE if TNC Server, FALSE if TNC Client - * @param server Server identity - * @param peer Client identity + * @param server_id Server identity + * @param peer_id Client identity + * @param server_ip Server IP address + * @param peer_ip Client IP address * @param transport Underlying TNC IF-T transport protocol used * @param cb Callback function if TNC Server, NULL if TNC Client * @return implementation of the tnccs_t interface */ typedef tnccs_t *(*tnccs_constructor_t)(bool is_server, - identification_t *server, - identification_t *peer, + identification_t *server_id, + identification_t *peer_id, + host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, tnccs_cb_t cb); diff --git a/src/libtnccs/tnc/tnccs/tnccs_manager.h b/src/libtnccs/tnc/tnccs/tnccs_manager.h index 791336ee1..b5c85f3c0 100644 --- a/src/libtnccs/tnc/tnccs/tnccs_manager.h +++ b/src/libtnccs/tnc/tnccs/tnccs_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -56,16 +56,19 @@ struct tnccs_manager_t { * * @param type type of the TNCCS protocol * @param is_server TRUE if TNC Server, FALSE if TNC Client - * @param server Server identity - * @param peer Client identity + * @param server_id Server identity + * @param peer_id Client identity + * @param server_ip Server IP address + * @param peer_ip Client IP address * @param transport Underlying TNC IF-T transport protocol used * @param cb Callback function if TNC Server, NULL if TNC Client * @return TNCCS protocol instance, NULL if no constructor found */ tnccs_t* (*create_instance)(tnccs_manager_t *this, tnccs_type_t type, - bool is_server, identification_t *server, - identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb); + bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb); /** * Create a TNCCS connection and assign a unique connection ID as well a |