Merged libpts into libimcv

This commit is contained in:
Andreas Steffen
2014-10-05 12:55:37 +02:00
parent c4d0987609
commit d6fb2cc6e3
159 changed files with 232 additions and 439 deletions
+53 -1
View File
@@ -41,7 +41,59 @@ libimcv_la_SOURCES := \
os_info/os_info.h os_info/os_info.c \
pa_tnc/pa_tnc_attr.h \
pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c
pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c \
pts/pts.h pts/pts.c \
pts/pts_error.h pts/pts_error.c \
pts/pts_pcr.h pts/pts_pcr.c \
pts/pts_proto_caps.h \
pts/pts_req_func_comp_evid.h \
pts/pts_simple_evid_final.h \
pts/pts_creds.h pts/pts_creds.c \
pts/pts_database.h pts/pts_database.c \
pts/pts_dh_group.h pts/pts_dh_group.c \
pts/pts_file_meas.h pts/pts_file_meas.c \
pts/pts_file_meta.h pts/pts_file_meta.c \
pts/pts_file_type.h pts/pts_file_type.c \
pts/pts_ima_bios_list.h pts/pts_ima_bios_list.c \
pts/pts_ima_event_list.h pts/pts_ima_event_list.c \
pts/pts_meas_algo.h pts/pts_meas_algo.c \
pts/components/pts_component.h \
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \
pts/components/pts_comp_func_name.h pts/components/pts_comp_func_name.c \
pts/components/ita/ita_comp_func_name.h pts/components/ita/ita_comp_func_name.c \
pts/components/ita/ita_comp_ima.h pts/components/ita/ita_comp_ima.c \
pts/components/ita/ita_comp_tboot.h pts/components/ita/ita_comp_tboot.c \
pts/components/ita/ita_comp_tgrub.h pts/components/ita/ita_comp_tgrub.c \
pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
seg/seg_contract.h seg/seg_contract.c \
seg/seg_contract_manager.h seg/seg_contract_manager.c \
seg/seg_env.h seg/seg_env.c \
swid/swid_error.h swid/swid_error.c \
swid/swid_inventory.h swid/swid_inventory.c \
swid/swid_tag.h swid/swid_tag.c \
swid/swid_tag_id.h swid/swid_tag_id.c \
tcg/tcg_attr.h tcg/tcg_attr.c \
tcg/pts/tcg_pts_attr_proto_caps.h tcg/pts/tcg_pts_attr_proto_caps.c \
tcg/pts/tcg_pts_attr_dh_nonce_params_req.h tcg/pts/tcg_pts_attr_dh_nonce_params_req.c \
tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h tcg/pts/tcg_pts_attr_dh_nonce_params_resp.c \
tcg/pts/tcg_pts_attr_dh_nonce_finish.h tcg/pts/tcg_pts_attr_dh_nonce_finish.c \
tcg/pts/tcg_pts_attr_meas_algo.h tcg/pts/tcg_pts_attr_meas_algo.c \
tcg/pts/tcg_pts_attr_get_tpm_version_info.h tcg/pts/tcg_pts_attr_get_tpm_version_info.c \
tcg/pts/tcg_pts_attr_tpm_version_info.h tcg/pts/tcg_pts_attr_tpm_version_info.c \
tcg/pts/tcg_pts_attr_get_aik.h tcg/pts/tcg_pts_attr_get_aik.c \
tcg/pts/tcg_pts_attr_aik.h tcg/pts/tcg_pts_attr_aik.c \
tcg/pts/tcg_pts_attr_req_func_comp_evid.h tcg/pts/tcg_pts_attr_req_func_comp_evid.c \
tcg/pts/tcg_pts_attr_gen_attest_evid.h tcg/pts/tcg_pts_attr_gen_attest_evid.c \
tcg/pts/tcg_pts_attr_simple_comp_evid.h tcg/pts/tcg_pts_attr_simple_comp_evid.c \
tcg/pts/tcg_pts_attr_simple_evid_final.h tcg/pts/tcg_pts_attr_simple_evid_final.c \
tcg/pts/tcg_pts_attr_req_file_meas.h tcg/pts/tcg_pts_attr_req_file_meas.c \
tcg/pts/tcg_pts_attr_file_meas.h tcg/pts/tcg_pts_attr_file_meas.c \
tcg/pts/tcg_pts_attr_req_file_meta.h tcg/pts/tcg_pts_attr_req_file_meta.c \
tcg/pts/tcg_pts_attr_unix_file_meta.h tcg/pts/tcg_pts_attr_unix_file_meta.c \
tcg/swid/tcg_swid_attr_req.h tcg/swid/tcg_swid_attr_req.c \
tcg/swid/tcg_swid_attr_tag_id_inv.h tcg/swid/tcg_swid_attr_tag_id_inv.c \
tcg/swid/tcg_swid_attr_tag_inv.h tcg/swid/tcg_swid_attr_tag_inv.c
LOCAL_SRC_FILES := $(filter %.c,$(libimcv_la_SOURCES))
+73 -1
View File
@@ -12,6 +12,10 @@ libimcv_la_LIBADD = \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(top_builddir)/src/libtncif/libtncif.la
if USE_TROUSERS
libimcv_la_LIBADD += -ltspi
endif
if USE_WINDOWS
libimcv_la_LIBADD += -lws2_32
endif
@@ -56,9 +60,61 @@ libimcv_la_SOURCES = \
pa_tnc/pa_tnc_attr.h \
pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c \
pts/pts.h pts/pts.c \
pts/pts_error.h pts/pts_error.c \
pts/pts_pcr.h pts/pts_pcr.c \
pts/pts_proto_caps.h \
pts/pts_req_func_comp_evid.h \
pts/pts_simple_evid_final.h \
pts/pts_creds.h pts/pts_creds.c \
pts/pts_database.h pts/pts_database.c \
pts/pts_dh_group.h pts/pts_dh_group.c \
pts/pts_file_meas.h pts/pts_file_meas.c \
pts/pts_file_meta.h pts/pts_file_meta.c \
pts/pts_file_type.h pts/pts_file_type.c \
pts/pts_ima_bios_list.h pts/pts_ima_bios_list.c \
pts/pts_ima_event_list.h pts/pts_ima_event_list.c \
pts/pts_meas_algo.h pts/pts_meas_algo.c \
pts/components/pts_component.h \
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \
pts/components/pts_comp_func_name.h pts/components/pts_comp_func_name.c \
pts/components/ita/ita_comp_func_name.h pts/components/ita/ita_comp_func_name.c \
pts/components/ita/ita_comp_ima.h pts/components/ita/ita_comp_ima.c \
pts/components/ita/ita_comp_tboot.h pts/components/ita/ita_comp_tboot.c \
pts/components/ita/ita_comp_tgrub.h pts/components/ita/ita_comp_tgrub.c \
pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
seg/seg_contract.h seg/seg_contract.c \
seg/seg_contract_manager.h seg/seg_contract_manager.c \
seg/seg_env.h seg/seg_env.c
seg/seg_env.h seg/seg_env.c \
swid/swid_error.h swid/swid_error.c \
swid/swid_inventory.h swid/swid_inventory.c \
swid/swid_tag.h swid/swid_tag.c \
swid/swid_tag_id.h swid/swid_tag_id.c \
tcg/tcg_attr.h tcg/tcg_attr.c \
tcg/pts/tcg_pts_attr_proto_caps.h tcg/pts/tcg_pts_attr_proto_caps.c \
tcg/pts/tcg_pts_attr_dh_nonce_params_req.h tcg/pts/tcg_pts_attr_dh_nonce_params_req.c \
tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h tcg/pts/tcg_pts_attr_dh_nonce_params_resp.c \
tcg/pts/tcg_pts_attr_dh_nonce_finish.h tcg/pts/tcg_pts_attr_dh_nonce_finish.c \
tcg/pts/tcg_pts_attr_meas_algo.h tcg/pts/tcg_pts_attr_meas_algo.c \
tcg/pts/tcg_pts_attr_get_tpm_version_info.h tcg/pts/tcg_pts_attr_get_tpm_version_info.c \
tcg/pts/tcg_pts_attr_tpm_version_info.h tcg/pts/tcg_pts_attr_tpm_version_info.c \
tcg/pts/tcg_pts_attr_get_aik.h tcg/pts/tcg_pts_attr_get_aik.c \
tcg/pts/tcg_pts_attr_aik.h tcg/pts/tcg_pts_attr_aik.c \
tcg/pts/tcg_pts_attr_req_func_comp_evid.h tcg/pts/tcg_pts_attr_req_func_comp_evid.c \
tcg/pts/tcg_pts_attr_gen_attest_evid.h tcg/pts/tcg_pts_attr_gen_attest_evid.c \
tcg/pts/tcg_pts_attr_simple_comp_evid.h tcg/pts/tcg_pts_attr_simple_comp_evid.c \
tcg/pts/tcg_pts_attr_simple_evid_final.h tcg/pts/tcg_pts_attr_simple_evid_final.c \
tcg/pts/tcg_pts_attr_req_file_meas.h tcg/pts/tcg_pts_attr_req_file_meas.c \
tcg/pts/tcg_pts_attr_file_meas.h tcg/pts/tcg_pts_attr_file_meas.c \
tcg/pts/tcg_pts_attr_req_file_meta.h tcg/pts/tcg_pts_attr_req_file_meta.c \
tcg/pts/tcg_pts_attr_unix_file_meta.h tcg/pts/tcg_pts_attr_unix_file_meta.c \
tcg/seg/tcg_seg_attr_max_size.h tcg/seg/tcg_seg_attr_max_size.c \
tcg/seg/tcg_seg_attr_seg_env.h tcg/seg/tcg_seg_attr_seg_env.c \
tcg/seg/tcg_seg_attr_next_seg.h tcg/seg/tcg_seg_attr_next_seg.c \
tcg/swid/tcg_swid_attr_req.h tcg/swid/tcg_swid_attr_req.c \
tcg/swid/tcg_swid_attr_tag_id_inv.h tcg/swid/tcg_swid_attr_tag_id_inv.c \
tcg/swid/tcg_swid_attr_tag_inv.h tcg/swid/tcg_swid_attr_tag_inv.c
ipsec_SCRIPTS = imv/_imv_policy
EXTRA_DIST = imv/_imv_policy Android.mk
@@ -99,3 +155,19 @@ endif
if USE_IMV_OS
SUBDIRS += plugins/imv_os
endif
if USE_IMC_ATTESTATION
SUBDIRS += plugins/imc_attestation
endif
if USE_IMV_ATTESTATION
SUBDIRS += plugins/imv_attestation
endif
if USE_IMC_SWID
SUBDIRS += plugins/imc_swid
endif
if USE_IMV_SWID
SUBDIRS += plugins/imv_swid
endif
+3 -4
View File
@@ -18,14 +18,13 @@
#include "ietf/ietf_attr.h"
#include "ietf/ietf_attr_assess_result.h"
#include "ietf/ietf_attr_remediation_instr.h"
#include "tcg/seg/tcg_seg_attr_max_size.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include "tcg/seg/tcg_seg_attr_next_seg.h"
#include <tncif_names.h>
#include <tncif_pa_subtypes.h>
#include <tcg/seg/tcg_seg_attr_max_size.h>
#include <tcg/seg/tcg_seg_attr_seg_env.h>
#include <tcg/seg/tcg_seg_attr_next_seg.h>
#include <pen/pen.h>
#include <collections/linked_list.h>
#include <utils/debug.h>
+37
View File
@@ -15,6 +15,14 @@
#include "imcv.h"
#include "ietf/ietf_attr.h"
#include "ita/ita_attr.h"
#include "tcg/tcg_attr.h"
#include "pts/components/pts_component.h"
#include "pts/components/pts_component_manager.h"
#include "pts/components/tcg/tcg_comp_func_name.h"
#include "pts/components/ita/ita_comp_func_name.h"
#include "pts/components/ita/ita_comp_ima.h"
#include "pts/components/ita/ita_comp_tboot.h"
#include "pts/components/ita/ita_comp_tgrub.h"
#include <utils/debug.h>
#include <utils/utils.h>
@@ -43,6 +51,11 @@ imv_session_manager_t *imcv_sessions;
*/
imv_database_t *imcv_db;
/**
* PTS Functional Component manager
*/
pts_component_manager_t *imcv_pts_components;
/**
* Reference count for libimcv
*/
@@ -162,7 +175,26 @@ bool libimcv_init(bool is_imv)
ietf_attr_create_from_data, ietf_attr_names);
imcv_pa_tnc_attributes->add_vendor(imcv_pa_tnc_attributes, PEN_ITA,
ita_attr_create_from_data, ita_attr_names);
imcv_pa_tnc_attributes->add_vendor(imcv_pa_tnc_attributes, PEN_TCG,
tcg_attr_create_from_data, tcg_attr_names);
imcv_pts_components = pts_component_manager_create();
imcv_pts_components->add_vendor(imcv_pts_components, PEN_TCG,
pts_tcg_comp_func_names, PTS_TCG_QUALIFIER_TYPE_SIZE,
pts_tcg_qualifier_flag_names, pts_tcg_qualifier_type_names);
imcv_pts_components->add_vendor(imcv_pts_components, PEN_ITA,
pts_ita_comp_func_names, PTS_ITA_QUALIFIER_TYPE_SIZE,
pts_ita_qualifier_flag_names, pts_ita_qualifier_type_names);
imcv_pts_components->add_component(imcv_pts_components, PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_TGRUB,
pts_ita_comp_tgrub_create);
imcv_pts_components->add_component(imcv_pts_components, PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_TBOOT,
pts_ita_comp_tboot_create);
imcv_pts_components->add_component(imcv_pts_components, PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_IMA,
pts_ita_comp_ima_create);
if (is_imv)
{
/* instantiate global IMV session manager */
@@ -193,8 +225,13 @@ void libimcv_deinit(void)
{
if (ref_put(&libimcv_ref))
{
imcv_pts_components->remove_vendor(imcv_pts_components, PEN_TCG);
imcv_pts_components->remove_vendor(imcv_pts_components, PEN_ITA);
imcv_pts_components->destroy(imcv_pts_components);
imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF);
imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA);
imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_TCG);
DESTROY_IF(imcv_pa_tnc_attributes);
imcv_pa_tnc_attributes = NULL;
DESTROY_IF(imcv_db);
+6
View File
@@ -37,6 +37,7 @@
#include "pa_tnc/pa_tnc_attr_manager.h"
#include "imv/imv_database.h"
#include "imv/imv_session_manager.h"
#include "pts/components/pts_component_manager.h"
#include <library.h>
@@ -68,4 +69,9 @@ extern imv_database_t* imcv_db;
*/
extern imv_session_manager_t* imcv_sessions;
/**
* PTS Functional Component manager
*/
extern pts_component_manager_t* imcv_pts_components;
#endif /** IMCV_H_ @}*/
+3 -4
View File
@@ -18,14 +18,13 @@
#include "ietf/ietf_attr.h"
#include "ietf/ietf_attr_assess_result.h"
#include "ietf/ietf_attr_remediation_instr.h"
#include "tcg/seg/tcg_seg_attr_max_size.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include "tcg/seg/tcg_seg_attr_next_seg.h"
#include <tncif_names.h>
#include <tncif_pa_subtypes.h>
#include <tcg/seg/tcg_seg_attr_max_size.h>
#include <tcg/seg/tcg_seg_attr_seg_env.h>
#include <tcg/seg/tcg_seg_attr_next_seg.h>
#include <pen/pen.h>
#include <collections/linked_list.h>
#include <utils/debug.h>
@@ -0,0 +1,18 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
imcv_LTLIBRARIES = imc-attestation.la
imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imc_attestation_la_SOURCES = imc_attestation.c \
imc_attestation_state.h imc_attestation_state.c \
imc_attestation_process.h imc_attestation_process.c
imc_attestation_la_LDFLAGS = -module -avoid-version -no-undefined
@@ -0,0 +1,335 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_attestation_state.h"
#include "imc_attestation_process.h"
#include <imc/imc_agent.h>
#include <imc/imc_msg.h>
#include <ietf/ietf_attr.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <ietf/ietf_attr_product_info.h>
#include <ietf/ietf_attr_string_version.h>
#include <ietf/ietf_attr_assess_result.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <os_info/os_info.h>
#include <pts/pts_error.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <collections/linked_list.h>
/* IMC definitions */
static const char imc_name[] = "Attestation";
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_PTS }
};
static imc_agent_t *imc_attestation;
/**
* Supported PTS measurement algorithms
*/
static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE;
/**
* Supported PTS Diffie Hellman Groups
*/
static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
/**
* see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_Initialize(TNC_IMCID imc_id,
TNC_Version min_version,
TNC_Version max_version,
TNC_Version *actual_version)
{
bool mandatory_dh_groups;
if (imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
return TNC_RESULT_ALREADY_INITIALIZED;
}
imc_attestation = imc_agent_create(imc_name, msg_types, countof(msg_types),
imc_id, actual_version);
if (!imc_attestation)
{
return TNC_RESULT_FATAL;
}
mandatory_dh_groups = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-attestation.mandatory_dh_groups", TRUE, lib->ns);
if (!pts_meas_algo_probe(&supported_algorithms) ||
!pts_dh_group_probe(&supported_dh_groups, mandatory_dh_groups))
{
imc_attestation->destroy(imc_attestation);
imc_attestation = NULL;
return TNC_RESULT_FATAL;
}
if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
{
DBG1(DBG_IMC, "no common IF-IMC version");
return TNC_RESULT_NO_COMMON_VERSION;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imc_state_t *state;
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imc_attestation_state_create(connection_id);
return imc_attestation->create_state(imc_attestation, state);
case TNC_CONNECTION_STATE_HANDSHAKE:
if (imc_attestation->change_state(imc_attestation, connection_id,
new_state, &state) != TNC_RESULT_SUCCESS)
{
return TNC_RESULT_FATAL;
}
state->set_result(state, imc_id,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_attestation->delete_state(imc_attestation, connection_id);
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
default:
return imc_attestation->change_state(imc_attestation, connection_id,
new_state, NULL);
}
}
/**
* see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
{
imc_msg_t *out_msg;
imc_attestation_state_t *attestation_state;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
pen_type_t type;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imc_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
type = attr->get_type(attr);
if (type.vendor_id == PEN_IETF)
{
if (type.type == IETF_ATTR_PA_TNC_ERROR)
{
ietf_attr_pa_tnc_error_t *error_attr;
pen_type_t error_code;
chunk_t msg_info;
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
error_code = error_attr->get_error_code(error_attr);
if (error_code.vendor_id == PEN_TCG)
{
msg_info = error_attr->get_msg_info(error_attr);
DBG1(DBG_IMC, "received TCG-PTS error '%N'",
pts_error_code_names, error_code.type);
DBG1(DBG_IMC, "error information: %B", &msg_info);
result = TNC_RESULT_FATAL;
}
}
}
else if (type.vendor_id == PEN_TCG)
{
attestation_state = (imc_attestation_state_t*)state;
if (!imc_attestation_process(attr, out_msg, attestation_state,
supported_algorithms, supported_dh_groups))
{
result = TNC_RESULT_FATAL;
break;
}
}
}
enumerator->destroy(enumerator);
if (result == TNC_RESULT_SUCCESS)
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
/**
* see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_data(imc_attestation, state, connection_id,
msg_type, chunk_create(msg, msg_len));
result = receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_VendorID msg_vid,
TNC_MessageSubtype msg_subtype,
TNC_UInt32 src_imv_id,
TNC_UInt32 dst_imc_id)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_long_data(imc_attestation, state, connection_id,
src_imv_id, dst_imc_id, msg_vid, msg_subtype,
chunk_create(msg, msg_len));
result =receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_BatchEnding(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_Terminate(TNC_IMCID imc_id)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
imc_attestation->destroy(imc_attestation);
imc_attestation = NULL;
return TNC_RESULT_SUCCESS;
}
/**
* see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return imc_attestation->bind_functions(imc_attestation, bind_function);
}
@@ -0,0 +1,476 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu, 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
/* for isdigit */
#include <ctype.h>
#include "imc_attestation_process.h"
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <pts/pts.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h>
#include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_get_aik.h>
#include <tcg/pts/tcg_pts_attr_aik.h>
#include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
#include <tcg/pts/tcg_pts_attr_simple_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_simple_evid_final.h>
#include <tcg/pts/tcg_pts_attr_req_file_meas.h>
#include <tcg/pts/tcg_pts_attr_file_meas.h>
#include <tcg/pts/tcg_pts_attr_req_file_meta.h>
#include <tcg/pts/tcg_pts_attr_unix_file_meta.h>
#include <utils/debug.h>
#include <utils/lexparser.h>
#define DEFAULT_NONCE_LEN 20
bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
imc_attestation_state_t *attestation_state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups)
{
chunk_t attr_info;
pts_t *pts;
pts_error_code_t pts_error;
pen_type_t attr_type;
bool valid_path;
pts = attestation_state->get_pts(attestation_state);
attr_type = attr->get_type(attr);
switch (attr_type.type)
{
case TCG_PTS_REQ_PROTO_CAPS:
{
tcg_pts_attr_proto_caps_t *attr_cast;
pts_proto_caps_flag_t imc_caps, imv_caps;
attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
imv_caps = attr_cast->get_flags(attr_cast);
imc_caps = pts->get_proto_caps(pts);
pts->set_proto_caps(pts, imc_caps & imv_caps);
/* Send PTS Protocol Capabilities attribute */
attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps, FALSE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_MEAS_ALGO:
{
tcg_pts_attr_meas_algo_t *attr_cast;
pts_meas_algorithms_t offered_algorithms, selected_algorithm;
attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
offered_algorithms = attr_cast->get_algorithms(attr_cast);
selected_algorithm = pts_meas_algo_select(supported_algorithms,
offered_algorithms);
if (selected_algorithm == PTS_MEAS_ALGO_NONE)
{
attr = pts_hash_alg_error_create(supported_algorithms);
msg->add_attribute(msg, attr);
break;
}
/* Send Measurement Algorithm Selection attribute */
pts->set_meas_algorithm(pts, selected_algorithm);
attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_DH_NONCE_PARAMS_REQ:
{
tcg_pts_attr_dh_nonce_params_req_t *attr_cast;
pts_dh_group_t offered_dh_groups, selected_dh_group;
chunk_t responder_value, responder_nonce;
int nonce_len, min_nonce_len;
nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imc-attestation.nonce_len",
DEFAULT_NONCE_LEN, lib->ns);
attr_cast = (tcg_pts_attr_dh_nonce_params_req_t*)attr;
min_nonce_len = attr_cast->get_min_nonce_len(attr_cast);
if (nonce_len < PTS_MIN_NONCE_LEN ||
(min_nonce_len > 0 && nonce_len < min_nonce_len))
{
attr = pts_dh_nonce_error_create(nonce_len, PTS_MAX_NONCE_LEN);
msg->add_attribute(msg, attr);
break;
}
offered_dh_groups = attr_cast->get_dh_groups(attr_cast);
selected_dh_group = pts_dh_group_select(supported_dh_groups,
offered_dh_groups);
if (selected_dh_group == PTS_DH_GROUP_NONE)
{
attr = pts_dh_group_error_create(supported_dh_groups);
msg->add_attribute(msg, attr);
break;
}
/* Create own DH factor and nonce */
if (!pts->create_dh_nonce(pts, selected_dh_group, nonce_len))
{
return FALSE;
}
pts->get_my_public_value(pts, &responder_value, &responder_nonce);
/* Send DH Nonce Parameters Response attribute */
attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group,
supported_algorithms, responder_nonce, responder_value);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_DH_NONCE_FINISH:
{
tcg_pts_attr_dh_nonce_finish_t *attr_cast;
pts_meas_algorithms_t selected_algorithm;
chunk_t initiator_nonce, initiator_value;
int nonce_len;
attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr;
selected_algorithm = attr_cast->get_hash_algo(attr_cast);
if (!(selected_algorithm & supported_algorithms))
{
DBG1(DBG_IMC, "PTS-IMV selected unsupported DH hash algorithm");
return FALSE;
}
pts->set_dh_hash_algorithm(pts, selected_algorithm);
initiator_value = attr_cast->get_initiator_value(attr_cast);
initiator_nonce = attr_cast->get_initiator_nonce(attr_cast);
nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imc-attestation.nonce_len",
DEFAULT_NONCE_LEN, lib->ns);
if (nonce_len != initiator_nonce.len)
{
DBG1(DBG_IMC, "initiator and responder DH nonces "
"have differing lengths");
return FALSE;
}
pts->set_peer_public_value(pts, initiator_value, initiator_nonce);
if (!pts->calculate_secret(pts))
{
return FALSE;
}
break;
}
case TCG_PTS_GET_TPM_VERSION_INFO:
{
chunk_t tpm_version_info, attr_info;
pen_type_t error_code = { PEN_TCG, TCG_PTS_TPM_VERS_NOT_SUPPORTED };
if (!pts->get_tpm_version_info(pts, &tpm_version_info))
{
attr_info = attr->get_value(attr);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
/* Send TPM Version Info attribute */
attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_GET_AIK:
{
certificate_t *aik;
aik = pts->get_aik(pts);
if (!aik)
{
DBG1(DBG_IMC, "no AIK certificate or public key available");
break;
}
/* Send AIK attribute */
attr = tcg_pts_attr_aik_create(aik);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_REQ_FILE_MEAS:
{
tcg_pts_attr_req_file_meas_t *attr_cast;
char *pathname;
u_int16_t request_id;
bool is_directory;
u_int32_t delimiter;
pts_file_meas_t *measurements;
pen_type_t error_code;
attr_info = attr->get_value(attr);
attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
is_directory = attr_cast->get_directory_flag(attr_cast);
request_id = attr_cast->get_request_id(attr_cast);
delimiter = attr_cast->get_delimiter(attr_cast);
pathname = attr_cast->get_pathname(attr_cast);
valid_path = pts->is_path_valid(pts, pathname, &pts_error);
if (valid_path && pts_error)
{
error_code = pen_type_create(PEN_TCG, pts_error);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
else if (!valid_path)
{
break;
}
if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_INVALID_DELIMITER);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
/* Do PTS File Measurements and send them to PTS-IMV */
DBG2(DBG_IMC, "measurement request %d for %s '%s'",
request_id, is_directory ? "directory" : "file",
pathname);
measurements = pts_file_meas_create_from_path(request_id,
pathname, is_directory, TRUE,
pts->get_meas_algorithm(pts));
if (!measurements)
{
/* TODO handle error codes from measurements */
return FALSE;
}
attr = tcg_pts_attr_file_meas_create(measurements);
attr->set_noskip_flag(attr, TRUE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_REQ_FILE_META:
{
tcg_pts_attr_req_file_meta_t *attr_cast;
char *pathname;
bool is_directory;
u_int8_t delimiter;
pts_file_meta_t *metadata;
pen_type_t error_code;
attr_info = attr->get_value(attr);
attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
is_directory = attr_cast->get_directory_flag(attr_cast);
delimiter = attr_cast->get_delimiter(attr_cast);
pathname = attr_cast->get_pathname(attr_cast);
valid_path = pts->is_path_valid(pts, pathname, &pts_error);
if (valid_path && pts_error)
{
error_code = pen_type_create(PEN_TCG, pts_error);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
else if (!valid_path)
{
break;
}
if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_INVALID_DELIMITER);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
/* Get File Metadata and send them to PTS-IMV */
DBG2(DBG_IMC, "metadata request for %s '%s'",
is_directory ? "directory" : "file",
pathname);
metadata = pts->get_metadata(pts, pathname, is_directory);
if (!metadata)
{
/* TODO handle error codes from measurements */
return FALSE;
}
attr = tcg_pts_attr_unix_file_meta_create(metadata);
attr->set_noskip_flag(attr, TRUE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_REQ_FUNC_COMP_EVID:
{
tcg_pts_attr_req_func_comp_evid_t *attr_cast;
pts_proto_caps_flag_t negotiated_caps;
pts_comp_func_name_t *name;
pts_comp_evidence_t *evid;
pts_component_t *comp;
pen_type_t error_code;
u_int32_t depth;
u_int8_t flags;
status_t status;
enumerator_t *e;
attr_info = attr->get_value(attr);
attr_cast = (tcg_pts_attr_req_func_comp_evid_t*)attr;
DBG1(DBG_IMC, "evidence requested for %d functional components",
attr_cast->get_count(attr_cast));
e = attr_cast->create_enumerator(attr_cast);
while (e->enumerate(e, &flags, &depth, &name))
{
name->log(name, "* ");
negotiated_caps = pts->get_proto_caps(pts);
if (flags & PTS_REQ_FUNC_COMP_EVID_TTC)
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_DET_TTC);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (flags & PTS_REQ_FUNC_COMP_EVID_VER &&
!(negotiated_caps & PTS_PROTO_CAPS_V))
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_LOCAL_VAL);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (flags & PTS_REQ_FUNC_COMP_EVID_CURR &&
!(negotiated_caps & PTS_PROTO_CAPS_C))
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_CUR_EVID);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (flags & PTS_REQ_FUNC_COMP_EVID_PCR &&
!(negotiated_caps & PTS_PROTO_CAPS_T))
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_DET_PCR);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (depth > 0)
{
DBG1(DBG_IMC, "the Attestation IMC currently does not "
"support sub component measurements");
return FALSE;
}
comp = attestation_state->create_component(attestation_state,
name, depth);
if (!comp)
{
DBG2(DBG_IMC, " not registered: no evidence provided");
continue;
}
/* do the component evidence measurement[s] and cache them */
do
{
status = comp->measure(comp, name->get_qualifier(name),
pts, &evid);
if (status == FAILED)
{
break;
}
attestation_state->add_evidence(attestation_state, evid);
}
while (status == NEED_MORE);
}
e->destroy(e);
break;
}
case TCG_PTS_GEN_ATTEST_EVID:
{
pts_simple_evid_final_flag_t flags;
pts_meas_algorithms_t comp_hash_algorithm;
pts_comp_evidence_t *evid;
chunk_t pcr_composite, quote_sig;
bool use_quote2;
/* Send cached Component Evidence entries */
while (attestation_state->next_evidence(attestation_state, &evid))
{
attr = tcg_pts_attr_simple_comp_evid_create(evid);
msg->add_attribute(msg, attr);
}
use_quote2 = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-attestation.use_quote2", TRUE,
lib->ns);
if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, &quote_sig))
{
DBG1(DBG_IMC, "error occurred during TPM quote operation");
return FALSE;
}
/* Send Simple Evidence Final attribute */
flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
attr = tcg_pts_attr_simple_evid_final_create(flags,
comp_hash_algorithm, pcr_composite, quote_sig);
msg->add_attribute(msg, attr);
break;
}
/* TODO: Not implemented yet */
case TCG_PTS_REQ_INTEG_MEAS_LOG:
/* Attributes using XML */
case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
case TCG_PTS_UPDATE_TEMPL_REF_MANI:
/* On Windows only*/
case TCG_PTS_REQ_REGISTRY_VALUE:
/* Received on IMV side only*/
case TCG_PTS_PROTO_CAPS:
case TCG_PTS_DH_NONCE_PARAMS_RESP:
case TCG_PTS_MEAS_ALGO_SELECTION:
case TCG_PTS_TPM_VERSION_INFO:
case TCG_PTS_TEMPL_REF_MANI_SET_META:
case TCG_PTS_AIK:
case TCG_PTS_SIMPLE_COMP_EVID:
case TCG_PTS_SIMPLE_EVID_FINAL:
case TCG_PTS_VERIFICATION_RESULT:
case TCG_PTS_INTEG_REPORT:
case TCG_PTS_UNIX_FILE_META:
case TCG_PTS_FILE_MEAS:
case TCG_PTS_INTEG_MEAS_LOG:
default:
DBG1(DBG_IMC, "received unsupported attribute '%N'",
tcg_attr_names, attr->get_type(attr));
break;
}
return TRUE;
}
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imc_attestation_process_t imc_attestation_process
* @{ @ingroup imc_attestation
*/
#ifndef IMC_ATTESTATION_PROCESS_H_
#define IMC_ATTESTATION_PROCESS_H_
#include "imc_attestation_state.h"
#include <library.h>
#include <imc/imc_msg.h>
#include <pa_tnc/pa_tnc_attr.h>
#include <pts/pts_dh_group.h>
#include <pts/pts_meas_algo.h>
/**
* Process a TCG PTS attribute
*
* @param attr PA-TNC attribute to be processed
* @param msg outbound PA-TNC message to be assembled
* @param attestation_state attestation state of a given connection
* @param supported_algorithms supported PTS measurement algorithms
* @param supported_dh_groups supported DH groups
* @return TRUE if successful
*/
bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
imc_attestation_state_t *attestation_state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups);
#endif /** IMC_ATTESTATION_PROCESS_H_ @}*/
@@ -0,0 +1,260 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_attestation_state.h"
#include <imcv.h>
#include <tncif_names.h>
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_imc_attestation_state_t private_imc_attestation_state_t;
typedef struct func_comp_t func_comp_t;
/**
* Private data of an imc_attestation_state_t object.
*/
struct private_imc_attestation_state_t {
/**
* Public members of imc_attestation_state_t
*/
imc_attestation_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Assessment/Evaluation Result
*/
TNC_IMV_Evaluation_Result result;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
u_int32_t max_msg_len;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* PTS object
*/
pts_t *pts;
/**
* List of Functional Components
*/
linked_list_t *components;
/**
* Functional Component Evidence cache list
*/
linked_list_t *list;
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
private_imc_attestation_state_t *this)
{
return this->connection_id;
}
METHOD(imc_state_t, has_long, bool,
private_imc_attestation_state_t *this)
{
return this->has_long;
}
METHOD(imc_state_t, has_excl, bool,
private_imc_attestation_state_t *this)
{
return this->has_excl;
}
METHOD(imc_state_t, set_flags, void,
private_imc_attestation_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imc_state_t, set_max_msg_len, void,
private_imc_attestation_state_t *this, u_int32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imc_state_t, get_max_msg_len, u_int32_t,
private_imc_attestation_state_t *this)
{
return this->max_msg_len;
}
METHOD(imc_state_t, get_contracts, seg_contract_manager_t*,
private_imc_attestation_state_t *this)
{
return this->contracts;
}
METHOD(imc_state_t, change_state, void,
private_imc_attestation_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imc_state_t, set_result, void,
private_imc_attestation_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result result)
{
this->result = result;
}
METHOD(imc_state_t, get_result, bool,
private_imc_attestation_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result *result)
{
if (result)
{
*result = this->result;
}
return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
}
METHOD(imc_state_t, destroy, void,
private_imc_attestation_state_t *this)
{
this->pts->destroy(this->pts);
this->components->destroy_offset(this->components,
offsetof(pts_component_t, destroy));
this->list->destroy_offset(this->list,
offsetof(pts_comp_evidence_t, destroy));
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imc_attestation_state_t, get_pts, pts_t*,
private_imc_attestation_state_t *this)
{
return this->pts;
}
METHOD(imc_attestation_state_t, create_component, pts_component_t*,
private_imc_attestation_state_t *this, pts_comp_func_name_t *name,
u_int32_t depth)
{
enumerator_t *enumerator;
pts_component_t *component;
bool found = FALSE;
enumerator = this->components->create_enumerator(this->components);
while (enumerator->enumerate(enumerator, &component))
{
if (name->equals(name, component->get_comp_func_name(component)))
{
found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
if (!found)
{
component = imcv_pts_components->create(imcv_pts_components,
name, depth, NULL);
if (!component)
{
return NULL;
}
this->components->insert_last(this->components, component);
}
return component;
}
METHOD(imc_attestation_state_t, add_evidence, void,
private_imc_attestation_state_t *this, pts_comp_evidence_t *evid)
{
this->list->insert_last(this->list, evid);
}
METHOD(imc_attestation_state_t, next_evidence, bool,
private_imc_attestation_state_t *this, pts_comp_evidence_t **evid)
{
return this->list->remove_first(this->list, (void**)evid) == SUCCESS;
}
/**
* Described in header.
*/
imc_state_t *imc_attestation_state_create(TNC_ConnectionID connection_id)
{
private_imc_attestation_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.get_contracts = _get_contracts,
.change_state = _change_state,
.set_result = _set_result,
.get_result = _get_result,
.destroy = _destroy,
},
.get_pts = _get_pts,
.create_component = _create_component,
.add_evidence = _add_evidence,
.next_evidence = _next_evidence,
},
.connection_id = connection_id,
.state = TNC_CONNECTION_STATE_CREATE,
.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.contracts = seg_contract_manager_create(),
.pts = pts_create(TRUE),
.components = linked_list_create(),
.list = linked_list_create(),
);
return &this->public.interface;
}
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imc_attestation imc_attestation
* @ingroup libimcv_plugins
*
* @defgroup imc_attestation_state_t imc_attestation_state
* @{ @ingroup imc_attestation
*/
#ifndef IMC_ATTESTATION_STATE_H_
#define IMC_ATTESTATION_STATE_H_
#include <imc/imc_state.h>
#include <pts/pts.h>
#include <pts/components/pts_component.h>
#include <pts/components/pts_comp_evidence.h>
#include <library.h>
typedef struct imc_attestation_state_t imc_attestation_state_t;
/**
* Internal state of an imc_attestation_t connection instance
*/
struct imc_attestation_state_t {
/**
* imc_state_t interface
*/
imc_state_t interface;
/**
* Get the PTS object
*
* @return PTS object
*/
pts_t* (*get_pts)(imc_attestation_state_t *this);
/**
* Create and add an entry to the list of Functional Components
*
* @param name Component Functional Name
* @param depth Sub-component Depth
* @return created functional component instance or NULL
*/
pts_component_t* (*create_component)(imc_attestation_state_t *this,
pts_comp_func_name_t *name, u_int32_t depth);
/**
* Add an entry to the Component Evidence cache list
*
* @param evid Component Evidence entry
*/
void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *evid);
/**
* Removes next entry from the Component Evidence cache list and returns it
*
* @param evid Next Component Evidence entry
* @return TRUE if next entry is available
*/
bool (*next_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t** evid);
};
/**
* Create an imc_attestation_state_t instance
*
* @param id connection ID
*/
imc_state_t* imc_attestation_state_create(TNC_ConnectionID id);
#endif /** IMC_ATTESTATION_STATE_H_ @}*/
+1
View File
@@ -0,0 +1 @@
regid.2004-03.org.strongswan*.swidtag
+37
View File
@@ -0,0 +1,37 @@
regid = regid.2004-03.org.strongswan
unique_sw_id = strongSwan-$(PACKAGE_VERSION_MAJOR)-$(PACKAGE_VERSION_MINOR)-$(PACKAGE_VERSION_BUILD)$(PACKAGE_VERSION_REVIEW)
swid_tag = $(regid)_$(unique_sw_id).swidtag
swiddir = $(prefix)/share/$(regid)
swid_DATA = $(swid_tag)
ipsec_DATA = $(swid_tag)
EXTRA_DIST = $(regid)_strongSwan.swidtag.in
CLEANFILES = $(regid)_strongSwan*.swidtag
$(swid_tag) : regid.2004-03.org.strongswan_strongSwan.swidtag.in
$(AM_V_GEN) \
sed \
-e "s:@VERSION_MAJOR@:$(PACKAGE_VERSION_MAJOR):" \
-e "s:@VERSION_MINOR@:$(PACKAGE_VERSION_MINOR):" \
-e "s:@VERSION_BUILD@:$(PACKAGE_VERSION_BUILD):" \
-e "s:@VERSION_REVIEW@:$(PACKAGE_VERSION_REVIEW):" \
$(srcdir)/$(regid)_strongSwan.swidtag.in > $@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv \
-DSWID_DIRECTORY=\"${prefix}/share\"
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
imcv_LTLIBRARIES = imc-swid.la
imc_swid_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imc_swid_la_SOURCES = imc_swid.c imc_swid_state.h imc_swid_state.c
imc_swid_la_LDFLAGS = -module -avoid-version -no-undefined
+447
View File
@@ -0,0 +1,447 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_swid_state.h"
#include <imc/imc_agent.h>
#include <imc/imc_msg.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_angel.h>
#include "tcg/swid/tcg_swid_attr_req.h"
#include "tcg/swid/tcg_swid_attr_tag_inv.h"
#include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
#include "swid/swid_inventory.h"
#include "swid/swid_error.h"
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#define SWID_GENERATOR "/usr/local/bin/swid_generator"
/* IMC definitions */
static const char imc_name[] = "SWID";
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_SWID }
};
static imc_agent_t *imc_swid;
/**
* see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
TNC_Version min_version,
TNC_Version max_version,
TNC_Version *actual_version)
{
if (imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
return TNC_RESULT_ALREADY_INITIALIZED;
}
imc_swid = imc_agent_create(imc_name, msg_types, countof(msg_types),
imc_id, actual_version);
if (!imc_swid)
{
return TNC_RESULT_FATAL;
}
if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
{
DBG1(DBG_IMC, "no common IF-IMC version");
return TNC_RESULT_NO_COMMON_VERSION;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imc_state_t *state;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imc_swid_state_create(connection_id);
return imc_swid->create_state(imc_swid, state);
case TNC_CONNECTION_STATE_HANDSHAKE:
if (imc_swid->change_state(imc_swid, connection_id, new_state,
&state) != TNC_RESULT_SUCCESS)
{
return TNC_RESULT_FATAL;
}
state->set_result(state, imc_id,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_swid->delete_state(imc_swid, connection_id);
default:
return imc_swid->change_state(imc_swid, connection_id,
new_state, NULL);
}
}
/**
* see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
imc_state_t *state;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swid->get_state(imc_swid, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
return TNC_RESULT_SUCCESS;
}
/**
* Add one or multiple SWID Inventory attributes to the send queue
*/
static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg,
uint32_t request_id, bool full_tags,
swid_inventory_t *targets)
{
pa_tnc_attr_t *attr, *attr_angel, *attr_error;
imc_swid_state_t *swid_state;
swid_inventory_t *swid_inventory;
char *swid_directory, *swid_generator;
uint32_t eid_epoch;
size_t max_attr_size, attr_size, entry_size;
bool first = TRUE, swid_pretty, swid_full;
enumerator_t *enumerator;
swid_directory = lib->settings->get_str(lib->settings,
"%s.plugins.imc-swid.swid_directory",
SWID_DIRECTORY, lib->ns);
swid_generator = lib->settings->get_str(lib->settings,
"%s.plugins.imc-swid.swid_generator",
SWID_GENERATOR, lib->ns);
swid_pretty = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-swid.swid_pretty",
FALSE, lib->ns);
swid_full = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-swid.swid_full",
FALSE, lib->ns);
swid_inventory = swid_inventory_create(full_tags);
if (!swid_inventory->collect(swid_inventory, swid_directory, swid_generator,
targets, swid_pretty, swid_full))
{
swid_inventory->destroy(swid_inventory);
attr_error = swid_error_create(TCG_SWID_ERROR, request_id,
0, "error in SWID tag collection");
msg->add_attribute(msg, attr_error);
return FALSE;
}
DBG1(DBG_IMC, "collected %d SWID tag%s%s",
swid_inventory->get_count(swid_inventory), full_tags ? "" : " ID",
swid_inventory->get_count(swid_inventory) == 1 ? "" : "s");
swid_state = (imc_swid_state_t*)state;
eid_epoch = swid_state->get_eid_epoch(swid_state);
/**
* Compute the maximum TCG SWID Tag [ID] Inventory attribute size
* leaving space for an additional ITA Angel attribute
*/
max_attr_size = state->get_max_msg_len(state) -
PA_TNC_HEADER_SIZE - PA_TNC_ATTR_HEADER_SIZE;
if (full_tags)
{
tcg_swid_attr_tag_inv_t *swid_attr;
swid_tag_t *tag;
chunk_t encoding, instance_id;
/* At least one TCG Tag Inventory attribute is sent */
attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_INV_MIN_SIZE;
attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
enumerator = swid_inventory->create_enumerator(swid_inventory);
while (enumerator->enumerate(enumerator, &tag))
{
instance_id = tag->get_instance_id(tag);
encoding = tag->get_encoding(tag);
entry_size = 2 + instance_id.len + 4 + encoding.len;
/* Check for oversize tags that cannot be transported */
if (PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_INV_MIN_SIZE +
entry_size > max_attr_size)
{
attr_error = swid_error_create(TCG_SWID_RESPONSE_TOO_LARGE,
request_id, max_attr_size,
"oversize SWID tag omitted");
msg->add_attribute(msg, attr_error);
continue;
}
if (attr_size + entry_size > max_attr_size)
{
if (first)
{
/**
* Send an ITA Start Angel attribute to the IMV signalling
* that multiple TGC SWID Tag Inventory attributes follow
*/
attr_angel = ita_attr_angel_create(TRUE);
msg->add_attribute(msg, attr_angel);
first = FALSE;
}
msg->add_attribute(msg, attr);
/* create the next TCG SWID Tag Inventory attribute */
attr_size = PA_TNC_ATTR_HEADER_SIZE +
TCG_SWID_TAG_INV_MIN_SIZE;
attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
}
swid_attr = (tcg_swid_attr_tag_inv_t*)attr;
swid_attr->add(swid_attr, tag->get_ref(tag));
attr_size += entry_size;
}
enumerator->destroy(enumerator);
}
else
{
tcg_swid_attr_tag_id_inv_t *swid_id_attr;
swid_tag_id_t *tag_id;
/* Send a TCG Tag ID Inventory attribute */
attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1);
swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr;
enumerator = swid_inventory->create_enumerator(swid_inventory);
while (enumerator->enumerate(enumerator, &tag_id))
{
swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id));
}
enumerator->destroy(enumerator);
}
msg->add_attribute(msg, attr);
swid_inventory->destroy(swid_inventory);
if (!first)
{
/**
* If we sent an ITA Start Angel attribute in the first place,
* terminate by appending a matching ITA Stop Angel attribute.
*/
attr_angel = ita_attr_angel_create(FALSE);
msg->add_attribute(msg, attr_angel);
}
return TRUE;
}
static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
{
imc_msg_t *out_msg;
pa_tnc_attr_t *attr;
enumerator_t *enumerator;
pen_type_t type;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imc_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
tcg_swid_attr_req_t *attr_req;
uint8_t flags;
uint32_t request_id;
bool full_tags;
swid_inventory_t *targets;
type = attr->get_type(attr);
if (type.vendor_id != PEN_TCG || type.type != TCG_SWID_REQUEST)
{
continue;
}
attr_req = (tcg_swid_attr_req_t*)attr;
flags = attr_req->get_flags(attr_req);
request_id = attr_req->get_request_id(attr_req);
targets = attr_req->get_targets(attr_req);
if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C))
{
attr = swid_error_create(TCG_SWID_SUBSCRIPTION_DENIED, request_id,
0, "no subscription available yet");
out_msg->add_attribute(out_msg, attr);
break;
}
full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0;
if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets))
{
break;
}
}
enumerator->destroy(enumerator);
if (fatal_error)
{
result = TNC_RESULT_FATAL;
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
/**
* see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swid->get_state(imc_swid, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_data(imc_swid, state, connection_id, msg_type,
chunk_create(msg, msg_len));
result = receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_VendorID msg_vid,
TNC_MessageSubtype msg_subtype,
TNC_UInt32 src_imv_id,
TNC_UInt32 dst_imc_id)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swid->get_state(imc_swid, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_long_data(imc_swid, state, connection_id,
src_imv_id, dst_imc_id,msg_vid, msg_subtype,
chunk_create(msg, msg_len));
result =receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
{
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
imc_swid->destroy(imc_swid);
imc_swid = NULL;
return TNC_RESULT_SUCCESS;
}
/**
* see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
{
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return imc_swid->bind_functions(imc_swid, bind_function);
}
@@ -0,0 +1,203 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_swid_state.h"
#include <tncif_names.h>
#include <utils/debug.h>
typedef struct private_imc_swid_state_t private_imc_swid_state_t;
/**
* Private data of an imc_swid_state_t object.
*/
struct private_imc_swid_state_t {
/**
* Public members of imc_swid_state_t
*/
imc_swid_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Assessment/Evaluation Result
*/
TNC_IMV_Evaluation_Result result;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
u_int32_t max_msg_len;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* Event ID Epoch
*/
u_int32_t eid_epoch;
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
private_imc_swid_state_t *this)
{
return this->connection_id;
}
METHOD(imc_state_t, has_long, bool,
private_imc_swid_state_t *this)
{
return this->has_long;
}
METHOD(imc_state_t, has_excl, bool,
private_imc_swid_state_t *this)
{
return this->has_excl;
}
METHOD(imc_state_t, set_flags, void,
private_imc_swid_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imc_state_t, set_max_msg_len, void,
private_imc_swid_state_t *this, u_int32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imc_state_t, get_max_msg_len, u_int32_t,
private_imc_swid_state_t *this)
{
return this->max_msg_len;
}
METHOD(imc_state_t, get_contracts, seg_contract_manager_t*,
private_imc_swid_state_t *this)
{
return this->contracts;
}
METHOD(imc_state_t, change_state, void,
private_imc_swid_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imc_state_t, set_result, void,
private_imc_swid_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result result)
{
this->result = result;
}
METHOD(imc_state_t, get_result, bool,
private_imc_swid_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result *result)
{
if (result)
{
*result = this->result;
}
return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
}
METHOD(imc_state_t, destroy, void,
private_imc_swid_state_t *this)
{
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imc_swid_state_t, get_eid_epoch, u_int32_t,
private_imc_swid_state_t *this)
{
return this->eid_epoch;
}
/**
* Described in header.
*/
imc_state_t *imc_swid_state_create(TNC_ConnectionID connection_id)
{
private_imc_swid_state_t *this;
u_int32_t eid_epoch;
nonce_gen_t *ng;
ng = lib->crypto->create_nonce_gen(lib->crypto);
if (!ng || !ng->get_nonce(ng, 4, (u_int8_t*)&eid_epoch))
{
DBG1(DBG_TNC, "failed to generate random EID epoch value");
DESTROY_IF(ng);
return NULL;
}
ng->destroy(ng);
DBG1(DBG_IMC, "creating random EID epoch 0x%08x", eid_epoch);
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.get_contracts = _get_contracts,
.change_state = _change_state,
.set_result = _set_result,
.get_result = _get_result,
.destroy = _destroy,
},
.get_eid_epoch = _get_eid_epoch,
},
.state = TNC_CONNECTION_STATE_CREATE,
.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.contracts = seg_contract_manager_create(),
.eid_epoch = eid_epoch,
);
return &this->public.interface;
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2013 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imc_swid imc_swid
* @ingroup libimcv_plugins
*
* @defgroup imc_swid_state_t imc_swid_state
* @{ @ingroup imc_swid
*/
#ifndef IMC_SWID_STATE_H_
#define IMC_SWID_STATE_H_
#include <imc/imc_state.h>
#include <library.h>
typedef struct imc_swid_state_t imc_swid_state_t;
/**
* Internal state of an imc_swid_t connection instance
*/
struct imc_swid_state_t {
/**
* imc_state_t interface
*/
imc_state_t interface;
/**
* Get Event ID Epoch
*
* @return Event ID Epoch
*/
u_int32_t (*get_eid_epoch)(imc_swid_state_t *this);
};
/**
* Create an imc_swid_state_t instance
*
* @param id connection ID
*/
imc_state_t* imc_swid_state_create(TNC_ConnectionID id);
#endif /** IMC_SWID_STATE_H_ @}*/
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>apache2</product_title>
<product_version>
<name>2.2-22-13</name>
<numeric>
<major>2</major>
<minor>2</minor>
<build>22</build>
<review>13</review>
</numeric>
</product_version>
<software_creator>
<name>Apache Software Foundation</name>
<regid>regid.1995-04.org.apache</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>apache-2-2-22-13</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>bind9</product_title>
<product_version>
<name>9-8-4-dfsg</name>
<numeric>
<major>9</major>
<minor>8</minor>
<build>4</build>
<review>dfsg</review>
</numeric>
</product_version>
<software_creator>
<name>Internet Systems Consortium</name>
<regid>regid.1994-04.org.isc</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>bind-9-8-4-dfsg</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libsqlite3</product_title>
<product_version>
<name>3.7.13-1</name>
<numeric>
<major>3</major>
<minor>7</minor>
<build>13</build>
<review>1</review>
</numeric>
</product_version>
<software_creator>
<name>SQLite Project</name>
<regid>regid.2002-08.org.sqlite</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libsqlite-3-7-13-1</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libssl1.0.0</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libssl-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libssl-dev</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libssl-dev-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>openssl</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>openssl-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>sqlite3</product_title>
<product_version>
<name>3.7.13-1</name>
<numeric>
<major>3</major>
<minor>7</minor>
<build>13</build>
<review>1</review>
</numeric>
</product_version>
<software_creator>
<name>SQLite Project</name>
<regid>regid.2002-08.org.sqlite</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>sqlite-3-7-13-1</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<SoftwareIdentity
name="strongSwan"
uniqueId="strongSwan-@VERSION_MAJOR@-@VERSION_MINOR@-@VERSION_BUILD@@VERSION_REVIEW@"
version="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_BUILD@@VERSION_REVIEW@" versionScheme="alphanumeric"
xmlns="http://standards.iso.org/iso/19770/-2/2014/schema.xsd">
<Entity
name="strongSwan Project"
regid="regid.2004-03.org.strongswan"
role="publisher licensor tagcreator"/>
</SoftwareIdentity>
@@ -0,0 +1 @@
attest
@@ -0,0 +1,33 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv \
-DPLUGINS=\""${attest_plugins}\""
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
imcv_LTLIBRARIES = imv-attestation.la
imv_attestation_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imv_attestation_la_SOURCES = imv_attestation.c \
imv_attestation_state.h imv_attestation_state.c \
imv_attestation_agent.h imv_attestation_agent.c \
imv_attestation_process.h imv_attestation_process.c \
imv_attestation_build.h imv_attestation_build.c
imv_attestation_la_LDFLAGS = -module -avoid-version -no-undefined
ipsec_PROGRAMS = attest
attest_SOURCES = attest.c \
attest_usage.h attest_usage.c \
attest_db.h attest_db.c
attest_LDADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
attest.o : $(top_builddir)/config.status
EXTRA_DIST = build-database.sh
@@ -0,0 +1,484 @@
/*
* Copyright (C) 2011-2014 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.
*/
#define _GNU_SOURCE
#include <getopt.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <libgen.h>
#ifdef HAVE_SYSLOG
# include <syslog.h>
#endif
#include <library.h>
#include <utils/debug.h>
#include <imcv.h>
#include <pts/pts_meas_algo.h>
#include "attest_db.h"
#include "attest_usage.h"
/**
* global debug output variables
*/
static int debug_level = 1;
static bool stderr_quiet = TRUE;
/**
* attest dbg function
*/
static void attest_dbg(debug_t group, level_t level, char *fmt, ...)
{
va_list args;
if (level <= debug_level)
{
if (!stderr_quiet)
{
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
#ifdef HAVE_SYSLOG
{
int priority = LOG_INFO;
char buffer[8192];
char *current = buffer, *next;
/* write in memory buffer first */
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
/* do a syslog with every line */
while (current)
{
next = strchr(current, '\n');
if (next)
{
*(next++) = '\0';
}
syslog(priority, "%s\n", current);
current = next;
}
}
#endif /* HAVE_SYSLOG */
}
}
/**
* global attestation database object
*/
attest_db_t *attest;
/**
* atexit handler to close db on shutdown
*/
static void cleanup(void)
{
attest->destroy(attest);
libimcv_deinit();
#ifdef HAVE_SYSLOG
closelog();
#endif
}
static void do_args(int argc, char *argv[])
{
enum {
OP_UNDEF,
OP_USAGE,
OP_KEYS,
OP_COMPONENTS,
OP_DEVICES,
OP_DIRECTORIES,
OP_FILES,
OP_HASHES,
OP_MEASUREMENTS,
OP_PACKAGES,
OP_PRODUCTS,
OP_SESSIONS,
OP_ADD,
OP_DEL,
} op = OP_UNDEF;
/* reinit getopt state */
optind = 0;
while (TRUE)
{
int c;
struct option long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "components", no_argument, NULL, 'c' },
{ "devices", no_argument, NULL, 'e' },
{ "directories", no_argument, NULL, 'd' },
{ "dirs", no_argument, NULL, 'd' },
{ "files", no_argument, NULL, 'f' },
{ "keys", no_argument, NULL, 'k' },
{ "packages", no_argument, NULL, 'g' },
{ "products", no_argument, NULL, 'p' },
{ "hashes", no_argument, NULL, 'H' },
{ "measurements", no_argument, NULL, 'm' },
{ "sessions", no_argument, NULL, 's' },
{ "add", no_argument, NULL, 'a' },
{ "delete", no_argument, NULL, 'r' },
{ "del", no_argument, NULL, 'r' },
{ "remove", no_argument, NULL, 'r' },
{ "aik", required_argument, NULL, 'A' },
{ "blacklist", no_argument, NULL, 'B' },
{ "component", required_argument, NULL, 'C' },
{ "comp", required_argument, NULL, 'C' },
{ "directory", required_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'D' },
{ "file", required_argument, NULL, 'F' },
{ "package", required_argument, NULL, 'G' },
{ "key", required_argument, NULL, 'K' },
{ "measdir", required_argument, NULL, 'M' },
{ "owner", required_argument, NULL, 'O' },
{ "product", required_argument, NULL, 'P' },
{ "relative", no_argument, NULL, 'R' },
{ "rel", no_argument, NULL, 'R' },
{ "sequence", required_argument, NULL, 'S' },
{ "seq", required_argument, NULL, 'S' },
{ "utc", no_argument, NULL, 'U' },
{ "version", required_argument, NULL, 'V' },
{ "security", no_argument, NULL, 'Y' },
{ "sha1", no_argument, NULL, '1' },
{ "sha256", no_argument, NULL, '2' },
{ "sha384", no_argument, NULL, '3' },
{ "did", required_argument, NULL, '4' },
{ "fid", required_argument, NULL, '5' },
{ "pid", required_argument, NULL, '6' },
{ "cid", required_argument, NULL, '7' },
{ "kid", required_argument, NULL, '8' },
{ "gid", required_argument, NULL, '9' },
{ 0,0,0,0 }
};
c = getopt_long(argc, argv, "", long_opts, NULL);
switch (c)
{
case EOF:
break;
case 'h':
op = OP_USAGE;
break;
case 'c':
op = OP_COMPONENTS;
continue;
case 'd':
op = OP_DIRECTORIES;
continue;
case 'e':
op = OP_DEVICES;
continue;
case 'f':
op = OP_FILES;
continue;
case 'g':
op = OP_PACKAGES;
continue;
case 'k':
op = OP_KEYS;
continue;
case 'p':
op = OP_PRODUCTS;
continue;
case 'H':
op = OP_HASHES;
continue;
case 'm':
op = OP_MEASUREMENTS;
continue;
case 's':
op = OP_SESSIONS;
continue;
case 'a':
op = OP_ADD;
continue;
case 'r':
op = OP_DEL;
continue;
case 'A':
{
certificate_t *aik_cert;
public_key_t *aik_key;
chunk_t aik;
aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_X509, BUILD_FROM_FILE, optarg, BUILD_END);
if (!aik_cert)
{
printf("AIK certificate '%s' could not be loaded\n", optarg);
exit(EXIT_FAILURE);
}
aik_key = aik_cert->get_public_key(aik_cert);
aik_cert->destroy(aik_cert);
if (!aik_key)
{
printf("AIK public key could not be retrieved\n");
exit(EXIT_FAILURE);
}
if (!aik_key->get_fingerprint(aik_key, KEYID_PUBKEY_INFO_SHA1,
&aik))
{
printf("AIK fingerprint could not be computed\n");
aik_key->destroy(aik_key);
exit(EXIT_FAILURE);
}
aik = chunk_clone(aik);
aik_key->destroy(aik_key);
if (!attest->set_key(attest, aik, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
}
case 'B':
attest->set_package_state(attest, OS_PACKAGE_STATE_BLACKLIST);
continue;
case 'C':
if (!attest->set_component(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'D':
if (!attest->set_directory(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'F':
{
char *dir = path_dirname(optarg);
char *file = path_basename(optarg);
if (*dir != '.')
{
if (!attest->set_directory(attest, dir, op == OP_ADD))
{
free(file);
free(dir);
exit(EXIT_FAILURE);
}
}
free(dir);
if (!attest->set_file(attest, file, op == OP_ADD))
{
free(file);
exit(EXIT_FAILURE);
}
free(file);
continue;
}
case 'G':
if (!attest->set_package(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'K':
{
chunk_t aik;
aik = chunk_from_hex(chunk_create(optarg, strlen(optarg)), NULL);
if (!attest->set_key(attest, aik, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
}
case 'M':
if (!attest->set_meas_directory(attest, optarg))
{
exit(EXIT_FAILURE);
}
continue;
case 'O':
attest->set_owner(attest, optarg);
continue;
case 'P':
if (!attest->set_product(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'R':
attest->set_relative(attest);
continue;
case 'S':
attest->set_sequence(attest, atoi(optarg));
continue;
case 'U':
attest->set_utc(attest);
continue;
case 'V':
if (!attest->set_version(attest, optarg))
{
exit(EXIT_FAILURE);
}
continue;
case 'Y':
attest->set_package_state(attest, OS_PACKAGE_STATE_SECURITY);
continue;
case '1':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA1);
continue;
case '2':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA256);
continue;
case '3':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA384);
continue;
case '4':
if (!attest->set_did(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '5':
if (!attest->set_fid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '6':
if (!attest->set_pid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '7':
if (!attest->set_cid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '8':
if (!attest->set_kid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '9':
if (!attest->set_gid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
}
break;
}
switch (op)
{
case OP_USAGE:
usage();
break;
case OP_PACKAGES:
attest->list_packages(attest);
break;
case OP_PRODUCTS:
attest->list_products(attest);
break;
case OP_KEYS:
attest->list_keys(attest);
break;
case OP_COMPONENTS:
attest->list_components(attest);
break;
case OP_DEVICES:
attest->list_devices(attest);
break;
case OP_DIRECTORIES:
attest->list_directories(attest);
break;
case OP_FILES:
attest->list_files(attest);
break;
case OP_HASHES:
attest->list_hashes(attest);
break;
case OP_MEASUREMENTS:
attest->list_measurements(attest);
break;
case OP_SESSIONS:
attest->list_sessions(attest);
break;
case OP_ADD:
attest->add(attest);
break;
case OP_DEL:
attest->delete(attest);
break;
default:
usage();
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
char *uri;
/* enable attest debugging hook */
dbg = attest_dbg;
#ifdef HAVE_SYSLOG
openlog("attest", 0, LOG_DEBUG);
#endif
atexit(library_deinit);
/* initialize library */
if (!library_init(NULL, "attest"))
{
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
}
if (!lib->plugins->load(lib->plugins,
lib->settings->get_str(lib->settings, "attest.load", PLUGINS)))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
uri = lib->settings->get_str(lib->settings, "attest.database", NULL);
if (!uri)
{
fprintf(stderr, "database URI attest.database not set.\n");
exit(SS_RC_INITIALIZATION_FAILED);
}
attest = attest_db_create(uri);
if (!attest)
{
exit(SS_RC_INITIALIZATION_FAILED);
}
atexit(cleanup);
libimcv_init(FALSE);
do_args(argc, argv);
exit(EXIT_SUCCESS);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,267 @@
/*
* Copyright (C) 2011-2014 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 attest_db_t attest_db
* @{ @ingroup libpts
*/
#ifndef ATTEST_DB_H_
#define ATTEST_DB_H_
#include <pts/pts_meas_algo.h>
#include <os_info/os_info.h>
#include <library.h>
typedef struct attest_db_t attest_db_t;
/**
* Attestation database object
*/
struct attest_db_t {
/**
* Set functional component to be queried
*
* @param comp functional component
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_component)(attest_db_t *this, char *comp, bool create);
/**
* Set primary key of the functional component to be queried
*
* @param fid primary key of functional component
* @return TRUE if successful
*/
bool (*set_cid)(attest_db_t *this, int fid);
/**
* Set directory to be queried
*
* @param dir directory
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_directory)(attest_db_t *this, char *dir, bool create);
/**
* Set primary key of the directory to be queried
*
* @param did primary key of directory
* @return TRUE if successful
*/
bool (*set_did)(attest_db_t *this, int did);
/**
* Set measurement file to be queried
*
* @param file measurement file
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_file)(attest_db_t *this, char *file, bool create);
/**
* Set primary key of the measurement file to be queried
*
* @param fid primary key of measurement file
* @return TRUE if successful
*/
bool (*set_fid)(attest_db_t *this, int fid);
/**
* Set path to directory where file[s] are to be measured
*
* @param meas_dir measurement directory
* @return TRUE if successful
*/
bool (*set_meas_directory)(attest_db_t *this, char *dir);
/**
* Set functional component to be queried
*
* @param key AIK
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_key)(attest_db_t *this, chunk_t key, bool create);
/**
* Set primary key of the AIK to be queried
*
* @param kid primary key of AIK
* @return TRUE if successful
*/
bool (*set_kid)(attest_db_t *this, int kid);
/**
* Set software package to be queried
*
* @param product software package
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_package)(attest_db_t *this, char *package, bool create);
/**
* Set primary key of the software package to be queried
*
* @param gid primary key of software package
* @return TRUE if successful
*/
bool (*set_gid)(attest_db_t *this, int gid);
/**
* Set software product to be queried
*
* @param product software product
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_product)(attest_db_t *this, char *product, bool create);
/**
* Set primary key of the software product to be queried
*
* @param pid primary key of software product
* @return TRUE if successful
*/
bool (*set_pid)(attest_db_t *this, int pid);
/**
* Set software package version to be queried
*
* @param version software package version
* @return TRUE if successful
*/
bool (*set_version)(attest_db_t *this, char *version);
/**
* Set measurement hash algorithm
*
* @param algo hash algorithm
*/
void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo);
/**
* Set that the IMA-specific SHA-1 template hash be computed
*/
void (*set_ima)(attest_db_t *this);
/**
* Set that relative filenames are to be used
*/
void (*set_relative)(attest_db_t *this);
/**
* Set the package security or blacklist state
*/
void (*set_package_state)(attest_db_t *this, os_package_state_t package_state);
/**
* Set the sequence number
*/
void (*set_sequence)(attest_db_t *this, int seq_no);
/**
* Set owner [user/host] of an AIK
*
* @param owner user/host name
* @return TRUE if successful
*/
void (*set_owner)(attest_db_t *this, char *owner);
/**
* Display all dates in UTC
*/
void (*set_utc)(attest_db_t *this);
/**
* List all packages stored in the database
*/
void (*list_packages)(attest_db_t *this);
/**
* List all products stored in the database
*/
void (*list_products)(attest_db_t *this);
/**
* List all directories stored in the database
*/
void (*list_directories)(attest_db_t *this);
/**
* List selected files stored in the database
*/
void (*list_files)(attest_db_t *this);
/**
* List all components stored in the database
*/
void (*list_components)(attest_db_t *this);
/**
* List all devices stored in the database
*/
void (*list_devices)(attest_db_t *this);
/**
* List all AIKs stored in the database
*/
void (*list_keys)(attest_db_t *this);
/**
* List selected measurement hashes stored in the database
*/
void (*list_hashes)(attest_db_t *this);
/**
* List selected component measurement stored in the database
*/
void (*list_measurements)(attest_db_t *this);
/**
* List sessions stored in the database
*/
void (*list_sessions)(attest_db_t *this);
/**
* Add an entry to the database
*/
bool (*add)(attest_db_t *this);
/**
* Delete an entry from the database
*/
bool (*delete)(attest_db_t *this);
/**
* Destroy attest_db_t object
*/
void (*destroy)(attest_db_t *this);
};
/**
* Create an attest_db_t instance
*
* @param uri database URI
*/
attest_db_t* attest_db_create(char *uri);
#endif /** ATTEST_DB_H_ @}*/
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2011-2014 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 <stdio.h>
#include "attest_usage.h"
/**
* print attest usage info
*/
void usage(void)
{
printf("\
Usage:\n\
ipsec attest --components|--devices|--sessions|--files|--hashes|--keys [options]\n\
\n\
ipsec attest --measurements|--packages|--products|--add|--del [options]\n\
\n\
ipsec attest --components [--key <digest>|--kid <id>]\n\
Show a list of components with an AIK digest or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --devices [--utc]\n\
Show a list of registered devices and associated collected information\n\
\n\
ipsec attest --sessions [--utc]\n\
Show a chronologically sorted list of all TNC sessions\n\
\n\
ipsec attest --files [--product <name>|--pid <id>]\n\
Show a list of files with a software product name or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --hashes [--sha1|--sha256|--sha384] [--product <name>|--pid <id>]\n\
Show a list of measurement hashes for a given software product or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --hashes [--sha1|--sha1-ima|--sha256|--sha384] [--file <path>|--fid <id>]\n\
Show a list of measurement hashes for a given file or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --keys [--components <cfn>|--cid <id>]\n\
Show a list of AIK key digests with a component or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --measurements --sha1|--sha256|--sha384 [--component <cfn>|--cid <id>]\n\
Show a list of component measurements for a given component or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --measurements --sha1|--sha256|--sha384 [--key <digest>|--kid <id>|--aik <path>]\n\
Show a list of component measurements for a given AIK or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --packages [--product <name>|--pid <id>] [--utc]\n\
Show a list of software packages for a given product or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --products [--file <path>|--fid <id>]\n\
Show a list of supported software products with a file path or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --add --file <path>|--dir <path>|--product <name>|--component <cfn>\n\
Add a file, directory, product or component entry\n\
Component <cfn> entries must be of the form <vendor_id>/<name>-<qualifier>\n\
\n\
ipsec attest --add [--owner <name>] --key <digest>|--aik <path>\n\
Add an AIK public key digest entry preceded by an optional owner name\n\
\n\
ipsec attest --add --product <name>|--pid <id> --sha1|--sha1-ima|--sha256|--sha384\n\
[--relative|--rel] --dir <path>|--file <path>\n\
Add hashes of a single file or all files in a directory under absolute or relative filenames\n\
\n\
ipsec attest --add --key <digest|--kid <id> --component <cfn>|--cid <id> --sequence <no>|--seq <no>\n\
Add an ordered key/component entry\n\
\n\
ipsec attest --add --package <name> --version <string> [--security|--blacklist]\n\
[--product <name>|--pid <id>]\n\
Add a package version for a given product optionally with security or blacklist flag\n\
\n\
ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>\n\
Delete a file or directory entry referenced either by value or primary key\n\
\n\
ipsec attest --del --product <name>|--pid <id>|--component <cfn>|--cid <id>\n\
Delete a product or component entry referenced either by value or primary key\n\
\n\
ipsec attest --del --product <name>|--pid <id> --file <path>|--fid <id>|--dir <path>|--did <id>\n\
Delete a product/file entry referenced either by value or primary key\n\
\n\
ipsec attest --del --key <digest>|--kid <id>|--aik <path>\n\
Delete an AIK entry referenced either by value or primary key\n\
\n\
ipsec attest --del --key <digest|--kid <id> --component <cfn>|--cid <id>\n\
Delete a key/component entry\n\
\n\
ipsec attest --del --product <name>|--pid <id> --sha1|--sha1-ima|--sha256|--sha384\n\
[--dir <path>|--did <id>] --file <path>|--fid <id>\n\
Delete a file hash given an absolute or relative filename\n\
\n");
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef ATTEST_USAGE_H_
#define ATTEST_USAGE_H_
/**
* print attest usage info
*/
void usage(void);
#endif /* ATTEST_USAGE_H_ */
+84
View File
@@ -0,0 +1,84 @@
#!/bin/sh
p="Ubuntu 14.04 x86_64"
a="x86_64-linux-gnu"
k="3.13.0-34-generic"
for hash in sha1 sha256
do
ipsec attest --add --product "$p" --$hash --dir /sbin
ipsec attest --add --product "$p" --$hash --dir /usr/sbin
ipsec attest --add --product "$p" --$hash --dir /bin
ipsec attest --add --product "$p" --$hash --dir /usr/bin
ipsec attest --add --product "$p" --$hash --file /etc/init.d/rc
ipsec attest --add --product "$p" --$hash --file /etc/init.d/rcS
ipsec attest --add --product "$p" --$hash --dir /etc/network/if-pre-up.d
ipsec attest --add --product "$p" --$hash --dir /etc/network/if-up.d
ipsec attest --add --product "$p" --$hash --dir /etc/ppp/ip-down.d
ipsec attest --add --product "$p" --$hash --dir /etc/rcS.d
ipsec attest --add --product "$p" --$hash --dir /etc/rc2.d
ipsec attest --add --product "$p" --$hash --file /etc/rc.local
ipsec attest --add --product "$p" --$hash --dir /etc/resolvconf/update.d
ipsec attest --add --product "$p" --$hash --file /etc/resolvconf/update-libc.d/avahi-daemon
ipsec attest --add --product "$p" --$hash --dir /etc/update-motd.d
ipsec attest --add --product "$p" --$hash --dir /lib
ipsec attest --add --product "$p" --$hash --file /lib/crda/setregdomain
ipsec attest --add --product "$p" --$hash --dir /lib/ebtables
ipsec attest --add --product "$p" --$hash --file /lib/init/apparmor-profile-load
ipsec attest --add --product "$p" --$hash --file /lib/resolvconf/list-records
ipsec attest --add --product "$p" --$hash --dir /lib/ufw
ipsec attest --add --product "$p" --$hash --dir /lib/udev
ipsec attest --add --product "$p" --$hash --dir /lib/systemd
ipsec attest --add --product "$p" --$hash --dir /lib/xtables
ipsec attest --add --product "$p" --$hash --dir /lib/$a
ipsec attest --add --product "$p" --$hash --dir /lib/$a/plymouth
ipsec attest --add --product "$p" --$hash --dir /lib/$a/plymouth/renderers
ipsec attest --add --product "$p" --$hash --dir /lib/$a/security
ipsec attest --add --product "$p" --$hash --file /lib64/ld-linux-x86-64.so.2
for file in `find /usr/lib -name *.so`
do
ipsec attest --add --product "$p" --$hash --file $file
done
for file in `find /usr/lib -name *service`
do
ipsec attest --add --product "$p" --$hash --file $file
done
ipsec attest --add --product "$p" --$hash --dir /usr/lib
ipsec attest --add --product "$p" --$hash --dir /usr/lib/accountsservice
ipsec attest --add --product "$p" --$hash --dir /usr/lib/at-spi2-core
ipsec attest --add --product "$p" --$hash --file /usr/lib/avahi/avahi-daemon-check-dns.sh
ipsec attest --add --product "$p" --$hash --file /usr/lib/dbus-1.0/dbus-daemon-launch-helper
ipsec attest --add --product "$p" --$hash --dir /usr/lib/gvfs
ipsec attest --add --product "$p" --$hash --file /usr/lib/firefox/firefox
ipsec attest --add --product "$p" --$hash --dir /usr/lib/NetworkManager
ipsec attest --add --product "$p" --$hash --dir /usr/lib/pm-utils/power.d
ipsec attest --add --product "$p" --$hash --file /usr/lib/policykit-1/polkitd
ipsec attest --add --product "$p" --$hash --file /usr/lib/thunderbird/thunderbird
ipsec attest --add --product "$p" --$hash --dir /usr/lib/ubuntu-release-upgrader
ipsec attest --add --product "$p" --$hash --dir /usr/lib/update-notifier
ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a
ipsec attest --add --product "$p" --$hash --file /usr/lib/$a/mesa/libGL.so.1.2.0
ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a/samba
ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a/sasl2
ipsec attest --add --product "$p" --$hash --dir /usr/share/language-tools
ipsec attest --add --product "$p" --$hash --file /init \
--measdir /usr/share/initramfs-tools
ipsec attest --add --product "$p" --$hash --file /scripts/functions \
--measdir /usr/share/initramfs-tools/scripts
for file in `find /lib/modules/$k -name *.ko`
do
ipsec attest --add --product "$p" --$hash --file $file
done
done
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_attestation_agent.h"
static const char imv_name[] = "Attestation";
static const imv_agent_create_t imv_agent_create = imv_attestation_agent_create;
/* include generic TGC TNC IF-IMV API code below */
#include <imv/imv_if.h>
@@ -0,0 +1,904 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 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.
*/
#define _GNU_SOURCE /* for stdndup() */
#include <string.h>
#include "imv_attestation_agent.h"
#include "imv_attestation_state.h"
#include "imv_attestation_process.h"
#include "imv_attestation_build.h"
#include <imcv.h>
#include <imv/imv_agent.h>
#include <imv/imv_msg.h>
#include <imv/imv_session.h>
#include <imv/imv_os_info.h>
#include <ietf/ietf_attr.h>
#include <ietf/ietf_attr_attr_request.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <ietf/ietf_attr_product_info.h>
#include <ietf/ietf_attr_string_version.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_device_id.h>
#include <tcg/tcg_attr.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_req_file_meas.h>
#include <tcg/pts/tcg_pts_attr_req_file_meta.h>
#include <pts/pts.h>
#include <pts/pts_database.h>
#include <pts/pts_creds.h>
#include <pts/components/ita/ita_comp_func_name.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <credentials/credential_manager.h>
#include <collections/linked_list.h>
typedef struct private_imv_attestation_agent_t private_imv_attestation_agent_t;
/* Subscribed PA-TNC message subtypes */
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_PTS },
{ PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM }
};
/**
* Private data of an imv_attestation_agent_t object.
*/
struct private_imv_attestation_agent_t {
/**
* Public members of imv_attestation_agent_t
*/
imv_agent_if_t public;
/**
* IMV agent responsible for generic functions
*/
imv_agent_t *agent;
/**
* Supported PTS measurement algorithms
*/
pts_meas_algorithms_t supported_algorithms;
/**
* Supported PTS Diffie Hellman Groups
*/
pts_dh_group_t supported_dh_groups;
/**
* PTS file measurement database
*/
pts_database_t *pts_db;
/**
* PTS credentials
*/
pts_creds_t *pts_creds;
/**
* PTS credential manager
*/
credential_manager_t *pts_credmgr;
};
METHOD(imv_agent_if_t, bind_functions, TNC_Result,
private_imv_attestation_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
{
return this->agent->bind_functions(this->agent, bind_function);
}
METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id,
TNC_ConnectionState new_state)
{
TNC_IMV_Action_Recommendation rec;
imv_state_t *state;
imv_session_t *session;
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imv_attestation_state_create(id);
return this->agent->create_state(this->agent, state);
case TNC_CONNECTION_STATE_DELETE:
return this->agent->delete_state(this->agent, id);
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
if (this->agent->get_state(this->agent, id, &state) && imcv_db)
{
session = state->get_session(state);
if (session->get_policy_started(session))
{
switch (new_state)
{
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
break;
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
break;
case TNC_CONNECTION_STATE_ACCESS_NONE:
default:
rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
}
imcv_db->add_recommendation(imcv_db, session, rec);
if (!imcv_db->policy_script(imcv_db, session, FALSE))
{
DBG1(DBG_IMV, "error in policy script stop");
}
}
}
/* fall through to default state */
default:
return this->agent->change_state(this->agent, id, new_state, NULL);
}
}
/**
* Process a received message
*/
static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
imv_state_t *state, imv_msg_t *in_msg)
{
imv_msg_t *out_msg;
imv_session_t *session;
imv_os_info_t *os_info;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
pen_type_t type;
TNC_Result result;
chunk_t os_name, os_version;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imv_msg_create_as_reply(in_msg);
out_msg->set_msg_type(out_msg, msg_types[0]);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
session = state->get_session(state);
os_info = session->get_os_info(session);
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
type = attr->get_type(attr);
if (type.vendor_id == PEN_IETF)
{
switch (type.type)
{
case IETF_ATTR_PA_TNC_ERROR:
{
ietf_attr_pa_tnc_error_t *error_attr;
pen_type_t error_code;
chunk_t msg_info;
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
error_code = error_attr->get_error_code(error_attr);
if (error_code.vendor_id == PEN_TCG)
{
msg_info = error_attr->get_msg_info(error_attr);
DBG1(DBG_IMV, "received TCG-PTS error '%N'",
pts_error_code_names, error_code.type);
DBG1(DBG_IMV, "error information: %B", &msg_info);
fatal_error = TRUE;
}
break;
}
case IETF_ATTR_PRODUCT_INFORMATION:
{
ietf_attr_product_info_t *attr_cast;
pen_t vendor_id;
state->set_action_flags(state,
IMV_ATTESTATION_ATTR_PRODUCT_INFO);
attr_cast = (ietf_attr_product_info_t*)attr;
os_name = attr_cast->get_info(attr_cast, &vendor_id, NULL);
os_info->set_name(os_info, os_name);
if (vendor_id != PEN_IETF)
{
DBG1(DBG_IMV, "operating system name is '%.*s' "
"from vendor %N", os_name.len, os_name.ptr,
pen_names, vendor_id);
}
else
{
DBG1(DBG_IMV, "operating system name is '%.*s'",
os_name.len, os_name.ptr);
}
break;
break;
}
case IETF_ATTR_STRING_VERSION:
{
ietf_attr_string_version_t *attr_cast;
state->set_action_flags(state,
IMV_ATTESTATION_ATTR_STRING_VERSION);
attr_cast = (ietf_attr_string_version_t*)attr;
os_version = attr_cast->get_version(attr_cast, NULL, NULL);
os_info->set_version(os_info, os_version);
if (os_version.len)
{
DBG1(DBG_IMV, "operating system version is '%.*s'",
os_version.len, os_version.ptr);
}
break;
}
default:
break;
}
}
else if (type.vendor_id == PEN_ITA)
{
switch (type.type)
{
case ITA_ATTR_DEVICE_ID:
{
chunk_t value;
state->set_action_flags(state,
IMV_ATTESTATION_ATTR_DEVICE_ID);
value = attr->get_value(attr);
DBG1(DBG_IMV, "device ID is %.*s", value.len, value.ptr);
session->set_device_id(session, value);
break;
}
default:
break;
}
}
else if (type.vendor_id == PEN_TCG)
{
if (!imv_attestation_process(attr, out_msg, state,
this->supported_algorithms, this->supported_dh_groups,
this->pts_db, this->pts_credmgr))
{
result = TNC_RESULT_FATAL;
break;
}
}
}
enumerator->destroy(enumerator);
if (fatal_error || result != TNC_RESULT_SUCCESS)
{
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
result = out_msg->send_assessment(out_msg);
if (result == TNC_RESULT_SUCCESS)
{
result = this->agent->provide_recommendation(this->agent, state);
}
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id,
TNC_MessageType msg_type, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id,
TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_long_data(this->agent, state, id,
src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* Build an IETF Attribute Request attribute for missing attributes
*/
static pa_tnc_attr_t* build_attr_request(uint32_t received)
{
pa_tnc_attr_t *attr;
ietf_attr_attr_request_t *attr_cast;
attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
attr_cast = (ietf_attr_attr_request_t*)attr;
if (!(received & IMV_ATTESTATION_ATTR_PRODUCT_INFO) ||
!(received & IMV_ATTESTATION_ATTR_STRING_VERSION))
{
attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION);
attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
}
if (!(received & IMV_ATTESTATION_ATTR_DEVICE_ID))
{
attr_cast->add(attr_cast, PEN_ITA, ITA_ATTR_DEVICE_ID);
}
return attr;
}
METHOD(imv_agent_if_t, batch_ending, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id)
{
imv_msg_t *out_msg;
imv_state_t *state;
imv_session_t *session;
imv_attestation_state_t *attestation_state;
imv_attestation_handshake_state_t handshake_state;
imv_workitem_t *workitem;
TNC_IMV_Action_Recommendation rec;
TNC_IMV_Evaluation_Result eval;
TNC_IMVID imv_id;
TNC_Result result = TNC_RESULT_SUCCESS;
pts_t *pts;
int pid;
uint32_t actions;
enumerator_t *enumerator;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
attestation_state = (imv_attestation_state_t*)state;
pts = attestation_state->get_pts(attestation_state);
handshake_state = attestation_state->get_handshake_state(attestation_state);
actions = state->get_action_flags(state);
session = state->get_session(state);
imv_id = this->agent->get_id(this->agent);
/* exit if a recommendation has already been provided */
if (actions & IMV_ATTESTATION_REC)
{
return TNC_RESULT_SUCCESS;
}
/* send an IETF attribute request if no platform info was received */
if (!(actions & IMV_ATTESTATION_ATTR_REQ))
{
if ((actions & IMV_ATTESTATION_ATTR_MUST) != IMV_ATTESTATION_ATTR_MUST)
{
imv_msg_t *os_msg;
/* create attribute request for missing mandatory attributes */
os_msg = imv_msg_create(this->agent, state, id, imv_id,
TNC_IMCID_ANY, msg_types[1]);
os_msg->add_attribute(os_msg, build_attr_request(actions));
result = os_msg->send(os_msg, FALSE);
os_msg->destroy(os_msg);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
}
state->set_action_flags(state, IMV_ATTESTATION_ATTR_REQ);
}
if (!session->get_policy_started(session) &&
(actions & IMV_ATTESTATION_ATTR_PRODUCT_INFO) &&
(actions & IMV_ATTESTATION_ATTR_STRING_VERSION) &&
(actions & IMV_ATTESTATION_ATTR_DEVICE_ID))
{
if (imcv_db)
{
/* start the policy script */
if (!imcv_db->policy_script(imcv_db, session, TRUE))
{
DBG1(DBG_IMV, "error in policy script start");
}
}
else
{
DBG2(DBG_IMV, "no workitems available - no evaluation possible");
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
session->set_policy_started(session, TRUE);
}
}
if (handshake_state == IMV_ATTESTATION_STATE_INIT)
{
pa_tnc_attr_t *attr;
pts_proto_caps_flag_t flags;
out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
msg_types[0]);
/* Send Request Protocol Capabilities attribute */
flags = pts->get_proto_caps(pts);
attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Send Measurement Algorithms attribute */
attr = tcg_pts_attr_meas_algo_create(this->supported_algorithms, FALSE);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_DISCOVERY);
/* send these initial PTS attributes and exit */
result = out_msg->send(out_msg, FALSE);
out_msg->destroy(out_msg);
return result;
}
/* exit if we are not ready yet for PTS measurements */
if (!(actions & IMV_ATTESTATION_ALGO))
{
return TNC_RESULT_SUCCESS;
}
session->get_session_id(session, &pid, NULL);
pts->set_platform_id(pts, pid);
/* create an empty out message - we might need it */
out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
msg_types[0]);
/* establish the PTS measurements to be taken */
if (!(actions & IMV_ATTESTATION_FILE_MEAS))
{
bool is_dir, no_workitems = TRUE;
uint32_t delimiter = SOLIDUS_UTF;
uint16_t request_id;
pa_tnc_attr_t *attr;
char *pathname;
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_END);
enumerator = session->create_workitem_enumerator(session);
if (enumerator)
{
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY)
{
continue;
}
switch (workitem->get_type(workitem))
{
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_FILE_MEAS:
case IMV_WORKITEM_FILE_META:
is_dir = FALSE;
break;
case IMV_WORKITEM_DIR_REF_MEAS:
case IMV_WORKITEM_DIR_MEAS:
case IMV_WORKITEM_DIR_META:
is_dir = TRUE;
break;
case IMV_WORKITEM_TPM_ATTEST:
{
pts_component_t *comp;
pts_comp_func_name_t *comp_name;
bool no_d_flag, no_t_flag;
char result_str[BUF_LEN];
workitem->set_imv_id(workitem, imv_id);
no_workitems = FALSE;
no_d_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D);
no_t_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T);
if (no_d_flag || no_t_flag)
{
snprintf(result_str, BUF_LEN, "%s%s%s",
(no_t_flag) ? "no TPM available" : "",
(no_t_flag && no_d_flag) ? ", " : "",
(no_d_flag) ? "no DH nonce negotiation" : "");
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
session->remove_workitem(session, enumerator);
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
continue;
}
/* do TPM BIOS measurements */
if (strchr(workitem->get_arg_str(workitem), 'B'))
{
comp_name = pts_comp_func_name_create(PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_IMA,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED);
comp = attestation_state->create_component(
attestation_state, comp_name,
0, this->pts_db);
if (!comp)
{
comp_name->log(comp_name, "unregistered ");
comp_name->destroy(comp_name);
}
}
/* do TPM IMA measurements */
if (strchr(workitem->get_arg_str(workitem), 'I'))
{
comp_name = pts_comp_func_name_create(PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_IMA,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_OS);
comp = attestation_state->create_component(
attestation_state, comp_name,
0, this->pts_db);
if (!comp)
{
comp_name->log(comp_name, "unregistered ");
comp_name->destroy(comp_name);
}
}
/* do TPM TRUSTED BOOT measurements */
if (strchr(workitem->get_arg_str(workitem), 'T'))
{
comp_name = pts_comp_func_name_create(PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_TBOOT,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED);
comp = attestation_state->create_component(
attestation_state, comp_name,
0, this->pts_db);
if (!comp)
{
comp_name->log(comp_name, "unregistered ");
comp_name->destroy(comp_name);
}
}
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_NONCE_REQ);
continue;
}
default:
continue;
}
/* initiate file and directory measurements */
pathname = this->pts_db->get_pathname(this->pts_db, is_dir,
workitem->get_arg_int(workitem));
if (!pathname)
{
continue;
}
workitem->set_imv_id(workitem, imv_id);
no_workitems = FALSE;
if (workitem->get_type(workitem) == IMV_WORKITEM_FILE_META)
{
TNC_IMV_Action_Recommendation rec;
TNC_IMV_Evaluation_Result eval;
char result_str[BUF_LEN];
DBG2(DBG_IMV, "IMV %d requests metadata for %s '%s'",
imv_id, is_dir ? "directory" : "file", pathname);
/* currently just fire and forget metadata requests */
attr = tcg_pts_attr_req_file_meta_create(is_dir,
delimiter, pathname);
snprintf(result_str, BUF_LEN, "%s metadata requested",
is_dir ? "directory" : "file");
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
session->remove_workitem(session, enumerator);
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
}
else
{
/* use lower 16 bits of the workitem ID as request ID */
request_id = workitem->get_id(workitem) & 0xffff;
DBG2(DBG_IMV, "IMV %d requests measurement %d for %s '%s'",
imv_id, request_id, is_dir ? "directory" : "file",
pathname);
attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
delimiter, pathname);
}
free(pathname);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
}
enumerator->destroy(enumerator);
/* sent all file and directory measurement and metadata requests */
state->set_action_flags(state, IMV_ATTESTATION_FILE_MEAS);
if (no_workitems)
{
DBG2(DBG_IMV, "IMV %d has no workitems - "
"no evaluation requested", imv_id);
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
}
}
}
/* check the IMV state for the next PA-TNC attributes to send */
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST)
{
if (!imv_attestation_build(out_msg, state,
this->supported_dh_groups, this->pts_db))
{
imv_reason_string_t *reason_string;
chunk_t result;
char *result_str;
reason_string = imv_reason_string_create("en", ", ");
attestation_state->add_comp_evid_reasons(attestation_state,
reason_string);
result = reason_string->get_encoding(reason_string);
result_str = strndup(result.ptr, result.len);
reason_string->destroy(reason_string);
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
session->remove_workitem(session, enumerator);
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
}
break;
}
}
enumerator->destroy(enumerator);
/* finalized all workitems? */
if (session->get_policy_started(session) &&
session->get_workitem_count(session, imv_id) == 0 &&
attestation_state->get_handshake_state(attestation_state) ==
IMV_ATTESTATION_STATE_END)
{
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
state->set_action_flags(state, IMV_ATTESTATION_REC);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* send non-empty PA-TNC message with excl flag not set */
if (out_msg->get_attribute_count(out_msg))
{
result = out_msg->send(out_msg, FALSE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id)
{
TNC_IMVID imv_id;
imv_state_t *state;
imv_attestation_state_t *attestation_state;
imv_session_t *session;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
attestation_state = (imv_attestation_state_t*)state;
session = state->get_session(state);
imv_id = this->agent->get_id(this->agent);
if (imcv_db)
{
TNC_IMV_Evaluation_Result eval;
TNC_IMV_Action_Recommendation rec;
imv_workitem_t *workitem;
enumerator_t *enumerator;
int pending_file_meas = 0;
char *result_str;
chunk_t result_buf;
bio_writer_t *result;
enumerator = session->create_workitem_enumerator(session);
if (enumerator)
{
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_imv_id(workitem) != imv_id)
{
continue;
}
result = bio_writer_create(128);
switch (workitem->get_type(workitem))
{
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_FILE_MEAS:
case IMV_WORKITEM_DIR_REF_MEAS:
case IMV_WORKITEM_DIR_MEAS:
result_str = "pending file measurements";
pending_file_meas++;
break;
case IMV_WORKITEM_TPM_ATTEST:
attestation_state->finalize_components(attestation_state,
result);
result->write_data(result,
chunk_from_str("; pending component evidence"));
result->write_uint8(result, '\0');
result_buf = result->get_buf(result);
result_str = result_buf.ptr;
break;
default:
result->destroy(result);
continue;
}
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
result->destroy(result);
}
enumerator->destroy(enumerator);
if (pending_file_meas)
{
DBG1(DBG_IMV, "failure due to %d pending file measurements",
pending_file_meas);
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_FILE_MEAS_PEND);
}
}
}
return this->agent->provide_recommendation(this->agent, state);
}
METHOD(imv_agent_if_t, destroy, void,
private_imv_attestation_agent_t *this)
{
if (this->pts_creds)
{
this->pts_credmgr->remove_set(this->pts_credmgr,
this->pts_creds->get_set(this->pts_creds));
this->pts_creds->destroy(this->pts_creds);
}
DESTROY_IF(this->pts_db);
DESTROY_IF(this->pts_credmgr);
DESTROY_IF(this->agent);
free(this);
}
/**
* Described in header.
*/
imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id,
TNC_Version *actual_version)
{
private_imv_attestation_agent_t *this;
imv_agent_t *agent;
char *hash_alg, *dh_group, *cadir;
bool mandatory_dh_groups;
agent = imv_agent_create(name, msg_types, countof(msg_types), id,
actual_version);
if (!agent)
{
return NULL;
}
hash_alg = lib->settings->get_str(lib->settings,
"%s.plugins.imv-attestation.hash_algorithm", "sha256", lib->ns);
dh_group = lib->settings->get_str(lib->settings,
"%s.plugins.imv-attestation.dh_group", "ecp256", lib->ns);
mandatory_dh_groups = lib->settings->get_bool(lib->settings,
"%s.plugins.imv-attestation.mandatory_dh_groups", TRUE, lib->ns);
cadir = lib->settings->get_str(lib->settings,
"%s.plugins.imv-attestation.cadir", NULL, lib->ns);
INIT(this,
.public = {
.bind_functions = _bind_functions,
.notify_connection_change = _notify_connection_change,
.receive_message = _receive_message,
.receive_message_long = _receive_message_long,
.batch_ending = _batch_ending,
.solicit_recommendation = _solicit_recommendation,
.destroy = _destroy,
},
.agent = agent,
.supported_algorithms = PTS_MEAS_ALGO_NONE,
.supported_dh_groups = PTS_DH_GROUP_NONE,
.pts_credmgr = credential_manager_create(),
.pts_creds = pts_creds_create(cadir),
.pts_db = pts_database_create(imcv_db),
);
if (!pts_meas_algo_probe(&this->supported_algorithms) ||
!pts_dh_group_probe(&this->supported_dh_groups, mandatory_dh_groups) ||
!pts_meas_algo_update(hash_alg, &this->supported_algorithms) ||
!pts_dh_group_update(dh_group, &this->supported_dh_groups))
{
destroy(this);
return NULL;
}
if (this->pts_creds)
{
this->pts_credmgr->add_set(this->pts_credmgr,
this->pts_creds->get_set(this->pts_creds));
}
return &this->public;
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation_agent_t imv_attestation_agent
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_AGENT_H_
#define IMV_ATTESTATION_AGENT_H_
#include <imv/imv_agent_if.h>
/**
* Creates a Attestation IMV agent
*
* @param name Name of the IMV
* @param id ID of the IMV
* @param actual_version TNC IF-IMV version
*/
imv_agent_if_t* imv_attestation_agent_create(const char* name, TNC_IMVID id,
TNC_Version *actual_version);
#endif /** IMV_ATTESTATION_AGENT_H_ @}*/
@@ -0,0 +1,150 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_attestation_build.h"
#include "imv_attestation_state.h"
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h>
#include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_get_aik.h>
#include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
#include <utils/debug.h>
bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db)
{
imv_attestation_state_t *attestation_state;
imv_attestation_handshake_state_t handshake_state;
pts_t *pts;
pa_tnc_attr_t *attr = NULL;
attestation_state = (imv_attestation_state_t*)state;
handshake_state = attestation_state->get_handshake_state(attestation_state);
pts = attestation_state->get_pts(attestation_state);
switch (handshake_state)
{
case IMV_ATTESTATION_STATE_NONCE_REQ:
{
int min_nonce_len;
/* Send DH nonce parameters request attribute */
min_nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imv-attestation.min_nonce_len", 0, lib->ns);
attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
supported_dh_groups);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_TPM_INIT);
break;
}
case IMV_ATTESTATION_STATE_TPM_INIT:
{
pts_meas_algorithms_t selected_algorithm;
chunk_t initiator_value, initiator_nonce;
if (!(state->get_action_flags(state) & IMV_ATTESTATION_DH_NONCE))
{
break;
}
/* Send DH nonce finish attribute */
selected_algorithm = pts->get_meas_algorithm(pts);
pts->get_my_public_value(pts, &initiator_value, &initiator_nonce);
attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm,
initiator_value, initiator_nonce);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Send Get TPM Version attribute */
attr = tcg_pts_attr_get_tpm_version_info_create();
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Send Get AIK attribute */
attr = tcg_pts_attr_get_aik_create();
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_COMP_EVID);
break;
}
case IMV_ATTESTATION_STATE_COMP_EVID:
{
tcg_pts_attr_req_func_comp_evid_t *attr_cast;
enumerator_t *enumerator;
pts_comp_func_name_t *name;
uint8_t flags;
uint32_t depth;
bool first_component = TRUE;
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_END);
if (!pts->get_aik_id(pts))
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK);
return FALSE;
}
enumerator = attestation_state->create_component_enumerator(
attestation_state);
while (enumerator->enumerate(enumerator, &flags, &depth, &name))
{
if (first_component)
{
attr = tcg_pts_attr_req_func_comp_evid_create();
attr->set_noskip_flag(attr, TRUE);
first_component = FALSE;
DBG2(DBG_IMV, "evidence request by");
}
name->log(name, " ");
/* TODO check flags against negotiated_caps */
attr_cast = (tcg_pts_attr_req_func_comp_evid_t *)attr;
attr_cast->add_component(attr_cast, flags, depth, name);
}
enumerator->destroy(enumerator);
if (attr)
{
/* Send Request Functional Component Evidence attribute */
out_msg->add_attribute(out_msg, attr);
/* Send Generate Attestation Evidence attribute */
attr = tcg_pts_attr_gen_attest_evid_create();
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_EVID_FINAL);
}
break;
}
default:
break;
}
return TRUE;
}
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation_build_t imv_attestation_build
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_BUILD_H_
#define IMV_ATTESTATION_BUILD_H_
#include "imv_attestation_state.h"
#include <imv/imv_msg.h>
#include <library.h>
#include <pts/pts_database.h>
#include <pts/pts_dh_group.h>
#include <pts/pts_meas_algo.h>
/**
* Process a TCG PTS attribute
*
* @param out_msg outbound PA-TNC message to be built
* @param state state of a given connection
* @param supported_dh_groups supported DH groups
* @param pts_db PTS configuration database
* @return TRUE if successful
*/
bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db);
#endif /** IMV_ATTESTATION_BUILD_H_ @}*/
@@ -0,0 +1,563 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 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.
*/
#define _GNU_SOURCE /* for stdndup() */
#include <string.h>
#include "imv_attestation_process.h"
#include <imcv.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <pts/pts.h>
#include <tcg/pts/tcg_pts_attr_aik.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h>
#include <tcg/pts/tcg_pts_attr_file_meas.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_simple_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_simple_evid_final.h>
#include <tcg/pts/tcg_pts_attr_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_unix_file_meta.h>
#include <utils/debug.h>
#include <crypto/hashers/hasher.h>
#include <inttypes.h>
bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg,
imv_state_t *state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db,
credential_manager_t *pts_credmgr)
{
imv_session_t *session;
imv_attestation_state_t *attestation_state;
pen_type_t attr_type;
pts_t *pts;
session = state->get_session(state);
attestation_state = (imv_attestation_state_t*)state;
pts = attestation_state->get_pts(attestation_state);
attr_type = attr->get_type(attr);
switch (attr_type.type)
{
case TCG_PTS_PROTO_CAPS:
{
tcg_pts_attr_proto_caps_t *attr_cast;
pts_proto_caps_flag_t flags;
attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
flags = attr_cast->get_flags(attr_cast);
pts->set_proto_caps(pts, flags);
break;
}
case TCG_PTS_MEAS_ALGO_SELECTION:
{
tcg_pts_attr_meas_algo_t *attr_cast;
pts_meas_algorithms_t selected_algorithm;
attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
selected_algorithm = attr_cast->get_algorithms(attr_cast);
if (!(selected_algorithm & supported_algorithms))
{
DBG1(DBG_IMV, "PTS-IMC selected unsupported"
" measurement algorithm");
return FALSE;
}
pts->set_meas_algorithm(pts, selected_algorithm);
state->set_action_flags(state, IMV_ATTESTATION_ALGO);
break;
}
case TCG_PTS_DH_NONCE_PARAMS_RESP:
{
tcg_pts_attr_dh_nonce_params_resp_t *attr_cast;
int nonce_len, min_nonce_len;
pts_dh_group_t dh_group;
pts_meas_algorithms_t offered_algorithms, selected_algorithm;
chunk_t responder_value, responder_nonce;
attr_cast = (tcg_pts_attr_dh_nonce_params_resp_t*)attr;
responder_nonce = attr_cast->get_responder_nonce(attr_cast);
/* check compliance of responder nonce length */
min_nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imv-attestation.min_nonce_len", 0, lib->ns);
nonce_len = responder_nonce.len;
if (nonce_len < PTS_MIN_NONCE_LEN ||
(min_nonce_len > 0 && nonce_len < min_nonce_len))
{
attr = pts_dh_nonce_error_create(
max(PTS_MIN_NONCE_LEN, min_nonce_len),
PTS_MAX_NONCE_LEN);
out_msg->add_attribute(out_msg, attr);
break;
}
dh_group = attr_cast->get_dh_group(attr_cast);
if (!(dh_group & supported_dh_groups))
{
DBG1(DBG_IMV, "PTS-IMC selected unsupported DH group");
return FALSE;
}
offered_algorithms = attr_cast->get_hash_algo_set(attr_cast);
selected_algorithm = pts_meas_algo_select(supported_algorithms,
offered_algorithms);
if (selected_algorithm == PTS_MEAS_ALGO_NONE)
{
attr = pts_hash_alg_error_create(supported_algorithms);
out_msg->add_attribute(out_msg, attr);
break;
}
pts->set_dh_hash_algorithm(pts, selected_algorithm);
if (!pts->create_dh_nonce(pts, dh_group, nonce_len))
{
return FALSE;
}
responder_value = attr_cast->get_responder_value(attr_cast);
pts->set_peer_public_value(pts, responder_value,
responder_nonce);
/* Calculate secret assessment value */
if (!pts->calculate_secret(pts))
{
return FALSE;
}
state->set_action_flags(state, IMV_ATTESTATION_DH_NONCE);
break;
}
case TCG_PTS_TPM_VERSION_INFO:
{
tcg_pts_attr_tpm_version_info_t *attr_cast;
chunk_t tpm_version_info;
attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr;
tpm_version_info = attr_cast->get_tpm_version_info(attr_cast);
pts->set_tpm_version_info(pts, tpm_version_info);
break;
}
case TCG_PTS_AIK:
{
tcg_pts_attr_aik_t *attr_cast;
certificate_t *aik, *issuer;
public_key_t *public;
chunk_t keyid, keyid_hex, device_id;
int aik_id;
enumerator_t *e;
bool trusted = FALSE, trusted_chain = FALSE;
attr_cast = (tcg_pts_attr_aik_t*)attr;
aik = attr_cast->get_aik(attr_cast);
if (!aik)
{
DBG1(DBG_IMV, "AIK unavailable");
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK);
break;
}
/* check trust into public key as stored in the database */
public = aik->get_public_key(aik);
public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid);
DBG1(DBG_IMV, "verifying AIK with keyid %#B", &keyid);
keyid_hex = chunk_to_hex(keyid, NULL, FALSE);
if (session->get_device_id(session, &device_id) &&
chunk_equals(keyid_hex, device_id))
{
trusted = session->get_device_trust(session);
}
else
{
DBG1(DBG_IMV, "device ID unknown or different from AIK keyid");
}
DBG1(DBG_IMV, "AIK public key is %strusted", trusted ? "" : "not ");
public->destroy(public);
chunk_free(&keyid_hex);
if (aik->get_type(aik) == CERT_X509)
{
e = pts_credmgr->create_trusted_enumerator(pts_credmgr,
KEY_ANY, aik->get_issuer(aik), FALSE);
while (e->enumerate(e, &issuer))
{
if (aik->issued_by(aik, issuer, NULL))
{
trusted_chain = TRUE;
break;
}
}
e->destroy(e);
DBG1(DBG_IMV, "AIK certificate is %strusted",
trusted_chain ? "" : "not ");
if (!trusted || !trusted_chain)
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK);
break;
}
}
session->get_session_id(session, NULL, &aik_id);
pts->set_aik(pts, aik, aik_id);
break;
}
case TCG_PTS_FILE_MEAS:
{
TNC_IMV_Evaluation_Result eval;
TNC_IMV_Action_Recommendation rec;
tcg_pts_attr_file_meas_t *attr_cast;
uint16_t request_id;
int arg_int, file_count;
pts_meas_algorithms_t algo;
pts_file_meas_t *measurements;
imv_workitem_t *workitem, *found = NULL;
imv_workitem_type_t type;
char result_str[BUF_LEN];
bool is_dir, correct;
enumerator_t *enumerator;
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
algo = pts->get_meas_algorithm(pts);
attr_cast = (tcg_pts_attr_file_meas_t*)attr;
measurements = attr_cast->get_measurements(attr_cast);
request_id = measurements->get_request_id(measurements);
file_count = measurements->get_file_count(measurements);
DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
request_id, file_count, (file_count == 1) ? "":"s");
if (request_id)
{
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
/* request ID consist of lower 16 bits of workitem ID */
if ((workitem->get_id(workitem) & 0xffff) == request_id)
{
found = workitem;
break;
}
}
if (!found)
{
DBG1(DBG_IMV, " no entry found for file measurement "
"request %d", request_id);
enumerator->destroy(enumerator);
break;
}
type = found->get_type(found);
arg_int = found->get_arg_int(found);
switch (type)
{
default:
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_FILE_MEAS:
is_dir = FALSE;
break;
case IMV_WORKITEM_DIR_REF_MEAS:
case IMV_WORKITEM_DIR_MEAS:
is_dir = TRUE;
}
switch (type)
{
case IMV_WORKITEM_FILE_MEAS:
case IMV_WORKITEM_DIR_MEAS:
{
enumerator_t *e;
/* check hashes from database against measurements */
e = pts_db->create_file_hash_enumerator(pts_db,
pts->get_platform_id(pts),
algo, is_dir, arg_int);
if (!e)
{
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
break;
}
correct = measurements->verify(measurements, e, is_dir);
if (!correct)
{
attestation_state->set_measurement_error(
attestation_state,
IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL);
eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR;
}
e->destroy(e);
snprintf(result_str, BUF_LEN, "%s measurement%s correct",
is_dir ? "directory" : "file",
correct ? "" : " not");
break;
}
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_DIR_REF_MEAS:
{
enumerator_t *e;
char *filename;
chunk_t measurement;
e = measurements->create_enumerator(measurements);
while (e->enumerate(e, &filename, &measurement))
{
if (pts_db->add_file_measurement(pts_db,
pts->get_platform_id(pts), algo, measurement,
filename, is_dir, arg_int) != SUCCESS)
{
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
}
}
e->destroy(e);
snprintf(result_str, BUF_LEN, "%s reference measurement "
"successful", is_dir ? "directory" : "file");
break;
}
default:
break;
}
session->remove_workitem(session, enumerator);
enumerator->destroy(enumerator);
rec = found->set_result(found, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, found);
found->destroy(found);
}
else
{
measurements->check(measurements, pts_db,
pts->get_platform_id(pts), algo);
}
break;
}
case TCG_PTS_UNIX_FILE_META:
{
tcg_pts_attr_file_meta_t *attr_cast;
int file_count;
pts_file_meta_t *metadata;
pts_file_metadata_t *entry;
time_t created, modified, accessed;
bool utc = FALSE;
enumerator_t *e;
attr_cast = (tcg_pts_attr_file_meta_t*)attr;
metadata = attr_cast->get_metadata(attr_cast);
file_count = metadata->get_file_count(metadata);
DBG1(DBG_IMV, "metadata request returned %d file%s:",
file_count, (file_count == 1) ? "":"s");
e = metadata->create_enumerator(metadata);
while (e->enumerate(e, &entry))
{
DBG1(DBG_IMV, " '%s' (%"PRIu64" bytes)"
" owner %"PRIu64", group %"PRIu64", type %N",
entry->filename, entry->filesize, entry->owner,
entry->group, pts_file_type_names, entry->type);
created = entry->created;
modified = entry->modified;
accessed = entry->accessed;
DBG1(DBG_IMV, " created %T, modified %T, accessed %T",
&created, utc, &modified, utc, &accessed, utc);
}
e->destroy(e);
break;
}
case TCG_PTS_SIMPLE_COMP_EVID:
{
tcg_pts_attr_simple_comp_evid_t *attr_cast;
pts_comp_func_name_t *name;
pts_comp_evidence_t *evidence;
pts_component_t *comp;
uint32_t depth;
status_t status;
attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr;
evidence = attr_cast->get_comp_evidence(attr_cast);
name = evidence->get_comp_func_name(evidence, &depth);
comp = attestation_state->get_component(attestation_state, name);
if (!comp)
{
DBG1(DBG_IMV, " no entry found for component evidence request");
break;
}
status = comp->verify(comp, name->get_qualifier(name), pts, evidence);
if (status == VERIFY_ERROR || status == FAILED)
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_COMP_EVID_FAIL);
name->log(name, " measurement mismatch for ");
}
break;
}
case TCG_PTS_SIMPLE_EVID_FINAL:
{
tcg_pts_attr_simple_evid_final_t *attr_cast;
uint8_t flags;
pts_meas_algorithms_t comp_hash_algorithm;
chunk_t pcr_comp, tpm_quote_sig, evid_sig;
chunk_t pcr_composite, quote_info, result_buf;
imv_workitem_t *workitem;
imv_reason_string_t *reason_string;
enumerator_t *enumerator;
bool use_quote2, use_ver_info;
bio_writer_t *result;
attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr;
flags = attr_cast->get_quote_info(attr_cast, &comp_hash_algorithm,
&pcr_comp, &tpm_quote_sig);
if (flags != PTS_SIMPLE_EVID_FINAL_NO)
{
use_quote2 = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 ||
flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
use_ver_info = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
/* Construct PCR Composite and TPM Quote Info structures */
if (!pts->get_quote_info(pts, use_quote2, use_ver_info,
comp_hash_algorithm, &pcr_composite, &quote_info))
{
DBG1(DBG_IMV, "unable to construct TPM Quote Info");
return FALSE;
}
if (!chunk_equals(pcr_comp, pcr_composite))
{
DBG1(DBG_IMV, "received PCR Composite does not match "
"constructed one");
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
goto quote_error;
}
DBG2(DBG_IMV, "received PCR Composite matches constructed one");
if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig))
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
goto quote_error;
}
DBG2(DBG_IMV, "TPM Quote Info signature verification successful");
quote_error:
free(pcr_composite.ptr);
free(quote_info.ptr);
/**
* Finalize any pending measurement registrations and check
* if all expected component measurements were received
*/
result = bio_writer_create(128);
attestation_state->finalize_components(attestation_state,
result);
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST)
{
TNC_IMV_Action_Recommendation rec;
TNC_IMV_Evaluation_Result eval;
uint32_t error;
error = attestation_state->get_measurement_error(
attestation_state);
if (error & (IMV_ATTESTATION_ERROR_COMP_EVID_FAIL |
IMV_ATTESTATION_ERROR_COMP_EVID_PEND |
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL))
{
reason_string = imv_reason_string_create("en", ", ");
attestation_state->add_comp_evid_reasons(
attestation_state, reason_string);
result->write_data(result, chunk_from_str("; "));
result->write_data(result,
reason_string->get_encoding(reason_string));
reason_string->destroy(reason_string);
eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR;
}
else
{
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
}
session->remove_workitem(session, enumerator);
result->write_uint8(result, '\0');
result_buf = result->get_buf(result);
rec = workitem->set_result(workitem, result_buf.ptr,
eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_END);
break;
}
}
enumerator->destroy(enumerator);
result->destroy(result);
}
if (attr_cast->get_evid_sig(attr_cast, &evid_sig))
{
/** TODO: What to do with Evidence Signature */
DBG1(DBG_IMV, "this version of the Attestation IMV can not "
"handle Evidence Signatures");
}
break;
}
/* TODO: Not implemented yet */
case TCG_PTS_INTEG_MEAS_LOG:
/* Attributes using XML */
case TCG_PTS_TEMPL_REF_MANI_SET_META:
case TCG_PTS_VERIFICATION_RESULT:
case TCG_PTS_INTEG_REPORT:
/* On Windows only*/
case TCG_PTS_WIN_FILE_META:
case TCG_PTS_REGISTRY_VALUE:
/* Received on IMC side only*/
case TCG_PTS_REQ_PROTO_CAPS:
case TCG_PTS_DH_NONCE_PARAMS_REQ:
case TCG_PTS_DH_NONCE_FINISH:
case TCG_PTS_MEAS_ALGO:
case TCG_PTS_GET_TPM_VERSION_INFO:
case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
case TCG_PTS_UPDATE_TEMPL_REF_MANI:
case TCG_PTS_GET_AIK:
case TCG_PTS_REQ_FUNC_COMP_EVID:
case TCG_PTS_GEN_ATTEST_EVID:
case TCG_PTS_REQ_FILE_META:
case TCG_PTS_REQ_FILE_MEAS:
case TCG_PTS_REQ_INTEG_MEAS_LOG:
default:
DBG1(DBG_IMV, "received unsupported attribute '%N'",
tcg_attr_names, attr->get_type(attr));
break;
}
return TRUE;
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation_process_t imv_attestation_process
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_PROCESS_H_
#define IMV_ATTESTATION_PROCESS_H_
#include "imv_attestation_state.h"
#include <library.h>
#include <collections/linked_list.h>
#include <credentials/credential_manager.h>
#include <crypto/hashers/hasher.h>
#include <imv/imv_msg.h>
#include <pa_tnc/pa_tnc_attr.h>
#include <pts/pts_database.h>
#include <pts/pts_dh_group.h>
#include <pts/pts_meas_algo.h>
/**
* Process a TCG PTS attribute
*
* @param attr PA-TNC attribute to be processed
* @param out_msg PA-TNC message containing error messages
* @param state state of a given connection
* @param supported_algorithms supported PTS measurement algorithms
* @param supported_dh_groups supported DH groups
* @param pts_db PTS configuration database
* @param pts_credmgr PTS credential manager
* @return TRUE if successful
*/
bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg,
imv_state_t *state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db,
credential_manager_t *pts_credmgr);
#endif /** IMV_ATTESTATION_PROCESS_H_ @}*/
@@ -0,0 +1,560 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_attestation_state.h"
#include <imcv.h>
#include <imv/imv_lang_string.h>
#include "imv/imv_reason_string.h"
#include <tncif_policy.h>
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_imv_attestation_state_t private_imv_attestation_state_t;
typedef struct file_meas_request_t file_meas_request_t;
typedef struct func_comp_t func_comp_t;
/**
* Private data of an imv_attestation_state_t object.
*/
struct private_imv_attestation_state_t {
/**
* Public members of imv_attestation_state_t
*/
imv_attestation_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
uint32_t max_msg_len;
/**
* Flags set for completed actions
*/
uint32_t action_flags;
/**
* IMV database session associated with TNCCS connection
*/
imv_session_t *session;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* IMV Attestation handshake state
*/
imv_attestation_handshake_state_t handshake_state;
/**
* IMV action recommendation
*/
TNC_IMV_Action_Recommendation rec;
/**
* IMV evaluation result
*/
TNC_IMV_Evaluation_Result eval;
/**
* List of Functional Components
*/
linked_list_t *components;
/**
* PTS object
*/
pts_t *pts;
/**
* Measurement error flags
*/
uint32_t measurement_error;
/**
* TNC Reason String
*/
imv_reason_string_t *reason_string;
};
/**
* PTS Functional Component entry
*/
struct func_comp_t {
pts_component_t *comp;
pts_comp_func_name_t* name;
};
/**
* Frees a func_comp_t object
*/
static void free_func_comp(func_comp_t *this)
{
this->comp->destroy(this->comp);
this->name->destroy(this->name);
free(this);
}
/**
* Supported languages
*/
static char* languages[] = { "en", "de", "mn" };
/**
* Table of reason strings
*/
static imv_lang_string_t reason_file_meas_fail[] = {
{ "en", "Incorrect file measurement" },
{ "de", "Falsche Dateimessung" },
{ "mn", "Буруу байгаа файл" },
{ NULL, NULL }
};
static imv_lang_string_t reason_file_meas_pend[] = {
{ "en", "Pending file measurement" },
{ "de", "Ausstehende Dateimessung" },
{ "mn", "Xүлээгдэж байгаа файл" },
{ NULL, NULL }
};
static imv_lang_string_t reason_no_trusted_aik[] = {
{ "en", "No trusted AIK available" },
{ "de", "Kein vetrauenswürdiger AIK verfügbar" },
{ NULL, NULL }
};
static imv_lang_string_t reason_comp_evid_fail[] = {
{ "en", "Incorrect component evidence" },
{ "de", "Falsche Komponenten-Evidenz" },
{ "mn", "Буруу компонент хэмжилт" },
{ NULL, NULL }
};
static imv_lang_string_t reason_comp_evid_pend[] = {
{ "en", "Pending component evidence" },
{ "de", "Ausstehende Komponenten-Evidenz" },
{ "mn", "Xүлээгдэж компонент хэмжилт" },
{ NULL, NULL }
};
static imv_lang_string_t reason_tpm_quote_fail[] = {
{ "en", "Invalid TPM Quote signature received" },
{ "de", "Falsche TPM Quote Signature erhalten" },
{ "mn", "Буруу TPM Quote гарын үсэг" },
{ NULL, NULL }
};
METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
private_imv_attestation_state_t *this)
{
return this->connection_id;
}
METHOD(imv_state_t, has_long, bool,
private_imv_attestation_state_t *this)
{
return this->has_long;
}
METHOD(imv_state_t, has_excl, bool,
private_imv_attestation_state_t *this)
{
return this->has_excl;
}
METHOD(imv_state_t, set_flags, void,
private_imv_attestation_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imv_state_t, set_max_msg_len, void,
private_imv_attestation_state_t *this, uint32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imv_state_t, get_max_msg_len, uint32_t,
private_imv_attestation_state_t *this)
{
return this->max_msg_len;
}
METHOD(imv_state_t, set_action_flags, void,
private_imv_attestation_state_t *this, uint32_t flags)
{
this->action_flags |= flags;
}
METHOD(imv_state_t, get_action_flags, uint32_t,
private_imv_attestation_state_t *this)
{
return this->action_flags;
}
METHOD(imv_state_t, set_session, void,
private_imv_attestation_state_t *this, imv_session_t *session)
{
this->session = session;
}
METHOD(imv_state_t, get_session, imv_session_t*,
private_imv_attestation_state_t *this)
{
return this->session;
}
METHOD(imv_state_t, get_contracts, seg_contract_manager_t*,
private_imv_attestation_state_t *this)
{
return this->contracts;
}
METHOD(imv_state_t, change_state, void,
private_imv_attestation_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imv_state_t, get_recommendation, void,
private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation *rec,
TNC_IMV_Evaluation_Result *eval)
{
*rec = this->rec;
*eval = this->eval;
}
METHOD(imv_state_t, set_recommendation, void,
private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = rec;
this->eval = eval;
}
METHOD(imv_state_t, update_recommendation, void,
private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = tncif_policy_update_recommendation(this->rec, rec);
this->eval = tncif_policy_update_evaluation(this->eval, eval);
}
METHOD(imv_attestation_state_t, add_file_meas_reasons, void,
private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
{
if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL)
{
reason_string->add_reason(reason_string, reason_file_meas_fail);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_PEND)
{
reason_string->add_reason(reason_string, reason_file_meas_pend);
}
}
METHOD(imv_attestation_state_t, add_comp_evid_reasons, void,
private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
{
if (this->measurement_error & IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK)
{
reason_string->add_reason(reason_string, reason_no_trusted_aik);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_FAIL)
{
reason_string->add_reason(reason_string, reason_comp_evid_fail);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_PEND)
{
reason_string->add_reason(reason_string, reason_comp_evid_pend);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL)
{
reason_string->add_reason(reason_string, reason_tpm_quote_fail);
}
}
METHOD(imv_state_t, get_reason_string, bool,
private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
chunk_t *reason_string, char **reason_language)
{
*reason_language = imv_lang_string_select_lang(language_enumerator,
languages, countof(languages));
/* Instantiate a TNC Reason String object */
DESTROY_IF(this->reason_string);
this->reason_string = imv_reason_string_create(*reason_language, "\n");
add_file_meas_reasons(this, this->reason_string);
add_comp_evid_reasons(this, this->reason_string);
*reason_string = this->reason_string->get_encoding(this->reason_string);
return TRUE;
}
METHOD(imv_state_t, get_remediation_instructions, bool,
private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
chunk_t *string, char **lang_code, char **uri)
{
return FALSE;
}
METHOD(imv_state_t, destroy, void,
private_imv_attestation_state_t *this)
{
DESTROY_IF(this->session);
DESTROY_IF(this->reason_string);
this->components->destroy_function(this->components, (void *)free_func_comp);
this->pts->destroy(this->pts);
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imv_attestation_state_t, get_handshake_state,
imv_attestation_handshake_state_t, private_imv_attestation_state_t *this)
{
return this->handshake_state;
}
METHOD(imv_attestation_state_t, set_handshake_state, void,
private_imv_attestation_state_t *this,
imv_attestation_handshake_state_t new_state)
{
this->handshake_state = new_state;
}
METHOD(imv_attestation_state_t, get_pts, pts_t*,
private_imv_attestation_state_t *this)
{
return this->pts;
}
METHOD(imv_attestation_state_t, create_component, pts_component_t*,
private_imv_attestation_state_t *this, pts_comp_func_name_t *name,
uint32_t depth, pts_database_t *pts_db)
{
enumerator_t *enumerator;
func_comp_t *entry, *new_entry;
pts_component_t *component;
bool found = FALSE;
enumerator = this->components->create_enumerator(this->components);
while (enumerator->enumerate(enumerator, &entry))
{
if (name->equals(name, entry->comp->get_comp_func_name(entry->comp)))
{
found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
if (found)
{
if (name->equals(name, entry->name))
{
/* duplicate entry */
return NULL;
}
new_entry = malloc_thing(func_comp_t);
new_entry->name = name->clone(name);
new_entry->comp = entry->comp->get_ref(entry->comp);
this->components->insert_last(this->components, new_entry);
return entry->comp;
}
else
{
component = imcv_pts_components->create(imcv_pts_components,
name, depth, pts_db);
if (!component)
{
/* unsupported component */
return NULL;
}
new_entry = malloc_thing(func_comp_t);
new_entry->name = name->clone(name);
new_entry->comp = component;
this->components->insert_last(this->components, new_entry);
return component;
}
}
/**
* Enumerate file measurement entries
*/
static bool entry_filter(void *null, func_comp_t **entry, uint8_t *flags,
void *i2, uint32_t *depth,
void *i3, pts_comp_func_name_t **comp_name)
{
pts_component_t *comp;
pts_comp_func_name_t *name;
comp = (*entry)->comp;
name = (*entry)->name;
*flags = comp->get_evidence_flags(comp);
*depth = comp->get_depth(comp);
*comp_name = name;
return TRUE;
}
METHOD(imv_attestation_state_t, create_component_enumerator, enumerator_t*,
private_imv_attestation_state_t *this)
{
return enumerator_create_filter(
this->components->create_enumerator(this->components),
(void*)entry_filter, NULL, NULL);
}
METHOD(imv_attestation_state_t, get_component, pts_component_t*,
private_imv_attestation_state_t *this, pts_comp_func_name_t *name)
{
enumerator_t *enumerator;
func_comp_t *entry;
pts_component_t *found = NULL;
enumerator = this->components->create_enumerator(this->components);
while (enumerator->enumerate(enumerator, &entry))
{
if (name->equals(name, entry->name))
{
found = entry->comp;
break;
}
}
enumerator->destroy(enumerator);
return found;
}
METHOD(imv_attestation_state_t, get_measurement_error, uint32_t,
private_imv_attestation_state_t *this)
{
return this->measurement_error;
}
METHOD(imv_attestation_state_t, set_measurement_error, void,
private_imv_attestation_state_t *this, uint32_t error)
{
this->measurement_error |= error;
}
METHOD(imv_attestation_state_t, finalize_components, void,
private_imv_attestation_state_t *this, bio_writer_t *result)
{
func_comp_t *entry;
bool first = TRUE;
while (this->components->remove_last(this->components,
(void**)&entry) == SUCCESS)
{
if (first)
{
first = FALSE;
}
else
{
result->write_data(result, chunk_from_str("; "));
}
if (!entry->comp->finalize(entry->comp,
entry->name->get_qualifier(entry->name),
result))
{
set_measurement_error(this, IMV_ATTESTATION_ERROR_COMP_EVID_PEND);
}
free_func_comp(entry);
}
}
/**
* Described in header.
*/
imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
{
private_imv_attestation_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.set_action_flags = _set_action_flags,
.get_action_flags = _get_action_flags,
.set_session = _set_session,
.get_session = _get_session,
.get_contracts = _get_contracts,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
.update_recommendation = _update_recommendation,
.get_reason_string = _get_reason_string,
.get_remediation_instructions = _get_remediation_instructions,
.destroy = _destroy,
},
.get_handshake_state = _get_handshake_state,
.set_handshake_state = _set_handshake_state,
.get_pts = _get_pts,
.create_component = _create_component,
.create_component_enumerator = _create_component_enumerator,
.get_component = _get_component,
.finalize_components = _finalize_components,
.get_measurement_error = _get_measurement_error,
.set_measurement_error = _set_measurement_error,
.add_file_meas_reasons = _add_file_meas_reasons,
.add_comp_evid_reasons = _add_comp_evid_reasons,
},
.connection_id = connection_id,
.state = TNC_CONNECTION_STATE_CREATE,
.handshake_state = IMV_ATTESTATION_STATE_INIT,
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.contracts = seg_contract_manager_create(),
.components = linked_list_create(),
.pts = pts_create(FALSE),
);
return &this->public.interface;
}
@@ -0,0 +1,191 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation imv_attestation
* @ingroup libimcv_plugins
*
* @defgroup imv_attestation_state_t imv_attestation_state
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_STATE_H_
#define IMV_ATTESTATION_STATE_H_
#include <imv/imv_state.h>
#include <imv/imv_reason_string.h>
#include <pts/pts.h>
#include <pts/pts_database.h>
#include <pts/components/pts_component.h>
#include <library.h>
#include <bio/bio_writer.h>
typedef struct imv_attestation_state_t imv_attestation_state_t;
typedef enum imv_attestation_flag_t imv_attestation_flag_t;
typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t;
typedef enum imv_meas_error_t imv_meas_error_t;
/**
* IMV Attestation Flags set for completed actions
*/
enum imv_attestation_flag_t {
IMV_ATTESTATION_ATTR_PRODUCT_INFO = (1<<0),
IMV_ATTESTATION_ATTR_STRING_VERSION = (1<<1),
IMV_ATTESTATION_ATTR_DEVICE_ID = (1<<2),
IMV_ATTESTATION_ATTR_MUST = (1<<3)-1,
IMV_ATTESTATION_ATTR_REQ = (1<<3),
IMV_ATTESTATION_ALGO = (1<<4),
IMV_ATTESTATION_DH_NONCE = (1<<5),
IMV_ATTESTATION_FILE_MEAS = (1<<6),
IMV_ATTESTATION_REC = (1<<7)
};
/**
* IMV Attestation Handshake States (state machine)
*/
enum imv_attestation_handshake_state_t {
IMV_ATTESTATION_STATE_INIT,
IMV_ATTESTATION_STATE_DISCOVERY,
IMV_ATTESTATION_STATE_NONCE_REQ,
IMV_ATTESTATION_STATE_TPM_INIT,
IMV_ATTESTATION_STATE_COMP_EVID,
IMV_ATTESTATION_STATE_EVID_FINAL,
IMV_ATTESTATION_STATE_END,
};
/**
* IMV Measurement Error Types
*/
enum imv_meas_error_t {
IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL = 1,
IMV_ATTESTATION_ERROR_FILE_MEAS_PEND = 2,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK = 4,
IMV_ATTESTATION_ERROR_COMP_EVID_FAIL = 8,
IMV_ATTESTATION_ERROR_COMP_EVID_PEND = 16,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL = 32
};
/**
* Internal state of an imv_attestation_t connection instance
*/
struct imv_attestation_state_t {
/**
* imv_state_t interface
*/
imv_state_t interface;
/**
* Get state of the handshake
*
* @return the handshake state of IMV
*/
imv_attestation_handshake_state_t (*get_handshake_state)(
imv_attestation_state_t *this);
/**
* Set state of the handshake
*
* @param new_state the handshake state of IMV
*/
void (*set_handshake_state)(imv_attestation_state_t *this,
imv_attestation_handshake_state_t new_state);
/**
* Get the PTS object
*
* @return PTS object
*/
pts_t* (*get_pts)(imv_attestation_state_t *this);
/**
* Create and add an entry to the list of Functional Components
*
* @param name Component Functional Name
* @param depth Sub-component Depth
* @param pts_db PTS measurement database
* @return created functional component instance or NULL
*/
pts_component_t* (*create_component)(imv_attestation_state_t *this,
pts_comp_func_name_t *name,
uint32_t depth,
pts_database_t *pts_db);
/**
* Enumerate over all Functional Components
*
* @return Functional Component enumerator
*/
enumerator_t* (*create_component_enumerator)(imv_attestation_state_t *this);
/**
* Get a Functional Component with a given name
*
* @param name Name of the requested Functional Component
* @return Functional Component if found, NULL otherwise
*/
pts_component_t* (*get_component)(imv_attestation_state_t *this,
pts_comp_func_name_t *name);
/**
* Tell the Functional Components to finalize any measurement registrations
* and to check if all expected measurements were received
*
* @param result Writer appending component measurement results
*/
void (*finalize_components)(imv_attestation_state_t *this,
bio_writer_t *result);
/**
* Indicates the types of measurement errors that occurred
*
* @return Measurement error flags
*/
uint32_t (*get_measurement_error)(imv_attestation_state_t *this);
/**
* Call if a measurement error is encountered
*
* @param error Measurement error type
*/
void (*set_measurement_error)(imv_attestation_state_t *this,
uint32_t error);
/**
* Returns a concatenation of File Measurement reason strings
*
* @param reason_string Concatenated reason strings
*/
void (*add_file_meas_reasons)(imv_attestation_state_t *this,
imv_reason_string_t *reason_string);
/**
* Returns a concatenation of Component Evidence reason strings
*
* @param reason_string Concatenated reason strings
*/
void (*add_comp_evid_reasons)(imv_attestation_state_t *this,
imv_reason_string_t *reason_string);
};
/**
* Create an imv_attestation_state_t instance
*
* @param id connection ID
*/
imv_state_t* imv_attestation_state_create(TNC_ConnectionID id);
#endif /** IMV_ATTESTATION_STATE_H_ @}*/
+21
View File
@@ -0,0 +1,21 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv
AM_CFLAGS = \
$(PLUGIN_CFLAGS) $(json_CFLAGS)
imcv_LTLIBRARIES = imv-swid.la
imv_swid_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(json_LIBS)
imv_swid_la_SOURCES = \
imv_swid.c imv_swid_state.h imv_swid_state.c \
imv_swid_agent.h imv_swid_agent.c \
imv_swid_rest.h imv_swid_rest.c
imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_swid_agent.h"
static const char imv_name[] = "SWID";
static const imv_agent_create_t imv_agent_create = imv_swid_agent_create;
/* include generic TGC TNC IF-IMV API code below */
#include <imv/imv_if.h>
@@ -0,0 +1,751 @@
/*
* Copyright (C) 2013-2014 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "imv_swid_agent.h"
#include "imv_swid_state.h"
#include "imv_swid_rest.h"
#include <imcv.h>
#include <imv/imv_agent.h>
#include <imv/imv_msg.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_angel.h>
#include "tcg/seg/tcg_seg_attr_max_size.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include "tcg/swid/tcg_swid_attr_req.h"
#include "tcg/swid/tcg_swid_attr_tag_inv.h"
#include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
#include "swid/swid_error.h"
#include "swid/swid_inventory.h"
#include <tncif_names.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <bio/bio_reader.h>
typedef struct private_imv_swid_agent_t private_imv_swid_agent_t;
#define SWID_MAX_ATTR_SIZE 1000000000
/* Subscribed PA-TNC message subtypes */
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_SWID }
};
/**
* Flag set when corresponding attribute has been received
*/
enum imv_swid_attr_t {
IMV_SWID_ATTR_TAG_INV = (1<<0),
IMV_SWID_ATTR_TAG_ID_INV = (1<<1)
};
/**
* Private data of an imv_swid_agent_t object.
*/
struct private_imv_swid_agent_t {
/**
* Public members of imv_swid_agent_t
*/
imv_agent_if_t public;
/**
* IMV agent responsible for generic functions
*/
imv_agent_t *agent;
/**
* REST API to strongTNC manager
*/
imv_swid_rest_t *rest_api;
};
METHOD(imv_agent_if_t, bind_functions, TNC_Result,
private_imv_swid_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
{
return this->agent->bind_functions(this->agent, bind_function);
}
METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id,
TNC_ConnectionState new_state)
{
imv_state_t *state;
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imv_swid_state_create(id);
return this->agent->create_state(this->agent, state);
case TNC_CONNECTION_STATE_DELETE:
return this->agent->delete_state(this->agent, id);
default:
return this->agent->change_state(this->agent, id, new_state, NULL);
}
}
/**
* Process a received message
*/
static TNC_Result receive_msg(private_imv_swid_agent_t *this,
imv_state_t *state, imv_msg_t *in_msg)
{
imv_swid_state_t *swid_state;
imv_msg_t *out_msg;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imv_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
swid_state = (imv_swid_state_t*)state;
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
uint32_t request_id = 0, last_eid, eid_epoch;
swid_inventory_t *inventory;
pen_type_t type;
type = attr->get_type(attr);
if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
{
ietf_attr_pa_tnc_error_t *error_attr;
pen_type_t error_code;
chunk_t msg_info, description;
bio_reader_t *reader;
uint32_t max_attr_size;
bool success;
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
error_code = error_attr->get_error_code(error_attr);
if (error_code.vendor_id == PEN_TCG)
{
fatal_error = TRUE;
msg_info = error_attr->get_msg_info(error_attr);
reader = bio_reader_create(msg_info);
success = reader->read_uint32(reader, &request_id);
DBG1(DBG_IMV, "received TCG error '%N' for request %d",
swid_error_code_names, error_code.type, request_id);
if (!success)
{
reader->destroy(reader);
continue;
}
if (error_code.type == TCG_SWID_RESPONSE_TOO_LARGE)
{
if (!reader->read_uint32(reader, &max_attr_size))
{
reader->destroy(reader);
continue;
}
DBG1(DBG_IMV, " maximum PA-TNC attribute size is %u bytes",
max_attr_size);
}
description = reader->peek(reader);
if (description.len)
{
DBG1(DBG_IMV, " description: %.*s", description.len,
description.ptr);
}
reader->destroy(reader);
}
}
else if (type.vendor_id == PEN_ITA)
{
switch (type.type)
{
case ITA_ATTR_START_ANGEL:
swid_state->set_angel_count(swid_state, TRUE);
continue;
case ITA_ATTR_STOP_ANGEL:
swid_state->set_angel_count(swid_state, FALSE);
continue;
default:
continue;
}
}
else if (type.vendor_id != PEN_TCG)
{
continue;
}
switch (type.type)
{
case TCG_SWID_TAG_ID_INVENTORY:
{
tcg_swid_attr_tag_id_inv_t *attr_cast;
int tag_id_count;
state->set_action_flags(state, IMV_SWID_ATTR_TAG_ID_INV);
attr_cast = (tcg_swid_attr_tag_id_inv_t*)attr;
request_id = attr_cast->get_request_id(attr_cast);
last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch);
inventory = attr_cast->get_inventory(attr_cast);
tag_id_count = inventory->get_count(inventory);
DBG2(DBG_IMV, "received SWID tag ID inventory with %d item%s "
"for request %d at eid %d of epoch 0x%08x",
tag_id_count, (tag_id_count == 1) ? "" : "s",
request_id, last_eid, eid_epoch);
if (request_id == swid_state->get_request_id(swid_state))
{
swid_state->set_swid_inventory(swid_state, inventory);
swid_state->set_count(swid_state, tag_id_count, 0);
}
else
{
DBG1(DBG_IMV, "no workitem found for SWID tag ID inventory "
"with request ID %d", request_id);
}
break;
}
case TCG_SWID_TAG_INVENTORY:
{
tcg_swid_attr_tag_inv_t *attr_cast;
swid_tag_t *tag;
chunk_t tag_encoding;
json_object *jobj, *jarray, *jstring;
char *tag_str;
int tag_count;
enumerator_t *e;
state->set_action_flags(state, IMV_SWID_ATTR_TAG_INV);
attr_cast = (tcg_swid_attr_tag_inv_t*)attr;
request_id = attr_cast->get_request_id(attr_cast);
last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch);
inventory = attr_cast->get_inventory(attr_cast);
tag_count = inventory->get_count(inventory);
DBG2(DBG_IMV, "received SWID tag inventory with %d item%s for "
"request %d at eid %d of epoch 0x%08x",
tag_count, (tag_count == 1) ? "" : "s",
request_id, last_eid, eid_epoch);
if (request_id == swid_state->get_request_id(swid_state))
{
swid_state->set_count(swid_state, 0, tag_count);
if (this->rest_api)
{
jobj = json_object_new_object();
jarray = json_object_new_array();
json_object_object_add(jobj, "data", jarray);
e = inventory->create_enumerator(inventory);
while (e->enumerate(e, &tag))
{
tag_encoding = tag->get_encoding(tag);
tag_str = strndup(tag_encoding.ptr, tag_encoding.len);
DBG3(DBG_IMV, "%s", tag_str);
jstring = json_object_new_string(tag_str);
json_object_array_add(jarray, jstring);
free(tag_str);
}
e->destroy(e);
if (this->rest_api->post(this->rest_api,
"swid/add-tags/", jobj, NULL) != SUCCESS)
{
DBG1(DBG_IMV, "error in REST API add-tags request");
}
json_object_put(jobj);
}
}
else
{
DBG1(DBG_IMV, "no workitem found for SWID tag inventory "
"with request ID %d", request_id);
}
}
default:
continue;
}
}
enumerator->destroy(enumerator);
if (fatal_error)
{
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
result = out_msg->send_assessment(out_msg);
if (result == TNC_RESULT_SUCCESS)
{
result = this->agent->provide_recommendation(this->agent, state);
}
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id,
TNC_MessageType msg_type, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id,
TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_long_data(this->agent, state, id,
src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, batch_ending, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id)
{
imv_msg_t *out_msg;
imv_state_t *state;
imv_session_t *session;
imv_workitem_t *workitem;
imv_swid_state_t *swid_state;
imv_swid_handshake_state_t handshake_state;
pa_tnc_attr_t *attr;
TNC_IMVID imv_id;
TNC_Result result = TNC_RESULT_SUCCESS;
bool no_workitems = TRUE;
uint32_t request_id, received;
uint8_t flags;
enumerator_t *enumerator;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
swid_state = (imv_swid_state_t*)state;
handshake_state = swid_state->get_handshake_state(swid_state);
session = state->get_session(state);
imv_id = this->agent->get_id(this->agent);
if (handshake_state == IMV_SWID_STATE_END)
{
return TNC_RESULT_SUCCESS;
}
/* Create an empty out message - we might need it */
out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
msg_types[0]);
if (!imcv_db)
{
DBG2(DBG_IMV, "no workitems available - no evaluation possible");
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
swid_state->set_handshake_state(swid_state, IMV_SWID_STATE_END);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* Look for SWID tag workitem and create SWID tag request */
if (handshake_state == IMV_SWID_STATE_INIT &&
session->get_policy_started(session))
{
size_t max_attr_size = SWID_MAX_ATTR_SIZE;
size_t max_seg_size;
seg_contract_t *contract;
seg_contract_manager_t *contracts;
char buf[BUF_LEN];
enumerator = session->create_workitem_enumerator(session);
if (enumerator)
{
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY ||
workitem->get_type(workitem) != IMV_WORKITEM_SWID_TAGS)
{
continue;
}
flags = TCG_SWID_ATTR_REQ_FLAG_NONE;
if (strchr(workitem->get_arg_str(workitem), 'R'))
{
flags |= TCG_SWID_ATTR_REQ_FLAG_R;
}
if (strchr(workitem->get_arg_str(workitem), 'S'))
{
flags |= TCG_SWID_ATTR_REQ_FLAG_S;
}
if (strchr(workitem->get_arg_str(workitem), 'C'))
{
flags |= TCG_SWID_ATTR_REQ_FLAG_C;
}
/* Determine maximum PA-TNC attribute segment size */
max_seg_size = state->get_max_msg_len(state)
- PA_TNC_HEADER_SIZE
- PA_TNC_ATTR_HEADER_SIZE
- TCG_SEG_ATTR_SEG_ENV_HEADER;
/* Announce support of PA-TNC segmentation to IMC */
contract = seg_contract_create(msg_types[0], max_attr_size,
max_seg_size, TRUE, imv_id, FALSE);
contract->get_info_string(contract, buf, BUF_LEN, TRUE);
DBG2(DBG_IMV, "%s", buf);
contracts = state->get_contracts(state);
contracts->add_contract(contracts, contract);
attr = tcg_seg_attr_max_size_create(max_attr_size,
max_seg_size, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Issue a SWID request */
request_id = workitem->get_id(workitem);
swid_state->set_request_id(swid_state, request_id);
attr = tcg_swid_attr_req_create(flags, request_id, 0);
out_msg->add_attribute(out_msg, attr);
workitem->set_imv_id(workitem, imv_id);
no_workitems = FALSE;
DBG2(DBG_IMV, "IMV %d issues SWID request %d",
imv_id, request_id);
break;
}
enumerator->destroy(enumerator);
if (no_workitems)
{
DBG2(DBG_IMV, "IMV %d has no workitems - "
"no evaluation requested", imv_id);
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
}
handshake_state = IMV_SWID_STATE_WORKITEMS;
swid_state->set_handshake_state(swid_state, handshake_state);
}
}
received = state->get_action_flags(state);
if (handshake_state == IMV_SWID_STATE_WORKITEMS &&
(received & (IMV_SWID_ATTR_TAG_INV|IMV_SWID_ATTR_TAG_ID_INV)) &&
swid_state->get_angel_count(swid_state) <= 0)
{
TNC_IMV_Evaluation_Result eval;
TNC_IMV_Action_Recommendation rec;
char result_str[BUF_LEN], *error_str = "", *command;
char *target, *separator;
int tag_id_count, tag_count, i;
size_t max_attr_size, attr_size, entry_size;
chunk_t tag_creator, unique_sw_id;
json_object *jrequest, *jresponse, *jvalue;
tcg_swid_attr_req_t *cast_attr;
swid_tag_id_t *tag_id;
status_t status = SUCCESS;
if (this->rest_api && (received & IMV_SWID_ATTR_TAG_ID_INV))
{
if (asprintf(&command, "sessions/%d/swid-measurement/",
session->get_session_id(session, NULL, NULL)) < 0)
{
error_str = "allocation of command string failed";
status = FAILED;
}
else
{
jrequest = swid_state->get_swid_inventory(swid_state);
status = this->rest_api->post(this->rest_api, command,
jrequest, &jresponse);
if (status == FAILED)
{
error_str = "error in REST API swid-measurement request";
}
free(command);
}
}
switch (status)
{
case SUCCESS:
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
{
swid_state->get_count(swid_state, &tag_id_count,
&tag_count);
snprintf(result_str, BUF_LEN, "received inventory of "
"%d SWID tag ID%s and %d SWID tag%s",
tag_id_count, (tag_id_count == 1) ? "" : "s",
tag_count, (tag_count == 1) ? "" : "s");
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
break;
}
}
enumerator->destroy(enumerator);
break;
case NEED_MORE:
if (received & IMV_SWID_ATTR_TAG_INV)
{
error_str = "not all requested SWID tags were received";
status = FAILED;
json_object_put(jresponse);
break;
}
if (json_object_get_type(jresponse) != json_type_array)
{
error_str = "response was not a json_array";
status = FAILED;
json_object_put(jresponse);
break;
}
/* Compute the maximum TCG SWID Request attribute size */
max_attr_size = state->get_max_msg_len(state) -
PA_TNC_HEADER_SIZE;
/* Create the [first] TCG SWID Request attribute */
attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_REQ_MIN_SIZE;
attr = tcg_swid_attr_req_create(TCG_SWID_ATTR_REQ_FLAG_NONE,
swid_state->get_request_id(swid_state), 0);
tag_id_count = json_object_array_length(jresponse);
DBG1(DBG_IMV, "%d SWID tag target%s", tag_id_count,
(tag_id_count == 1) ? "" : "s");
for (i = 0; i < tag_id_count; i++)
{
jvalue = json_object_array_get_idx(jresponse, i);
if (json_object_get_type(jvalue) != json_type_string)
{
error_str = "json_string element expected in json_array";
status = FAILED;
json_object_put(jresponse);
break;
}
target = (char*)json_object_get_string(jvalue);
DBG1(DBG_IMV, " %s", target);
/* Separate target into tag_creator and unique_sw_id */
separator = strchr(target, '_');
if (!separator)
{
error_str = "separation of regid from "
"unique software ID failed";
break;
}
tag_creator = chunk_create(target, separator - target);
separator++;
unique_sw_id = chunk_create(separator, strlen(target) -
tag_creator.len - 1);
tag_id = swid_tag_id_create(tag_creator, unique_sw_id,
chunk_empty);
entry_size = 2 + tag_creator.len + 2 + unique_sw_id.len;
/* Have we reached the maximum attribute size? */
if (attr_size + entry_size > max_attr_size)
{
out_msg->add_attribute(out_msg, attr);
attr_size = PA_TNC_ATTR_HEADER_SIZE +
TCG_SWID_REQ_MIN_SIZE;
attr = tcg_swid_attr_req_create(
TCG_SWID_ATTR_REQ_FLAG_NONE,
swid_state->get_request_id(swid_state), 0);
}
cast_attr = (tcg_swid_attr_req_t*)attr;
cast_attr->add_target(cast_attr, tag_id);
}
json_object_put(jresponse);
out_msg->add_attribute(out_msg, attr);
break;
case FAILED:
default:
break;
}
if (status == FAILED)
{
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
{
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
rec = workitem->set_result(workitem, error_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
break;
}
}
enumerator->destroy(enumerator);
}
}
/* finalized all workitems ? */
if (handshake_state == IMV_SWID_STATE_WORKITEMS &&
session->get_workitem_count(session, imv_id) == 0)
{
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
swid_state->set_handshake_state(swid_state, IMV_SWID_STATE_END);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* send non-empty PA-TNC message with excl flag not set */
if (out_msg->get_attribute_count(out_msg))
{
result = out_msg->send(out_msg, FALSE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id)
{
imv_state_t *state;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
return this->agent->provide_recommendation(this->agent, state);
}
METHOD(imv_agent_if_t, destroy, void,
private_imv_swid_agent_t *this)
{
DESTROY_IF(this->rest_api);
this->agent->destroy(this->agent);
free(this);
}
/**
* Described in header.
*/
imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id,
TNC_Version *actual_version)
{
private_imv_swid_agent_t *this;
imv_agent_t *agent;
char *rest_api_uri;
u_int rest_api_timeout;
agent = imv_agent_create(name, msg_types, countof(msg_types), id,
actual_version);
if (!agent)
{
return NULL;
}
agent->add_non_fatal_attr_type(agent,
pen_type_create(PEN_TCG, TCG_SEG_MAX_ATTR_SIZE_REQ));
INIT(this,
.public = {
.bind_functions = _bind_functions,
.notify_connection_change = _notify_connection_change,
.receive_message = _receive_message,
.receive_message_long = _receive_message_long,
.batch_ending = _batch_ending,
.solicit_recommendation = _solicit_recommendation,
.destroy = _destroy,
},
.agent = agent,
);
rest_api_uri = lib->settings->get_str(lib->settings,
"%s.plugins.imv-swid.rest_api_uri", NULL, lib->ns);
rest_api_timeout = lib->settings->get_int(lib->settings,
"%s.plugins.imv-swid.rest_api_timeout", 120, lib->ns);
if (rest_api_uri)
{
this->rest_api = imv_swid_rest_create(rest_api_uri, rest_api_timeout);
}
return &this->public;
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_swid_agent_t imv_swid_agent
* @{ @ingroup imv_swid
*/
#ifndef IMV_SWID_AGENT_H_
#define IMV_SWID_AGENT_H_
#include <imv/imv_agent_if.h>
/**
* Creates an SWID IMV agent
*
* @param name Name of the IMV
* @param id ID of the IMV
* @param actual_version TNC IF-IMV version
*/
imv_agent_if_t* imv_swid_agent_create(const char* name, TNC_IMVID id,
TNC_Version *actual_version);
#endif /** IMV_SWID_AGENT_H_ @}*/
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2014 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "imv_swid_rest.h"
typedef struct private_imv_swid_rest_t private_imv_swid_rest_t;
/**
* Private data of an imv_swid_rest_t object.
*/
struct private_imv_swid_rest_t {
/**
* Public members of imv_swid_rest_t
*/
imv_swid_rest_t public;
/**
* URI of REST API
*/
char *uri;
/**
* Timeout of REST API connection
*/
u_int timeout;
};
#define HTTP_STATUS_CODE_PRECONDITION_FAILED 412
METHOD(imv_swid_rest_t, post, status_t,
private_imv_swid_rest_t *this, char *command, json_object *jrequest,
json_object **jresponse)
{
struct json_tokener *tokener;
chunk_t data, response = chunk_empty;
status_t status;
char *uri;
int code;
if (asprintf(&uri, "%s%s",this->uri, command) < 0)
{
return FAILED;
}
data = chunk_from_str((char*)json_object_to_json_string(jrequest));
status = lib->fetcher->fetch(lib->fetcher, uri, &response,
FETCH_TIMEOUT, this->timeout,
FETCH_REQUEST_DATA, data,
FETCH_REQUEST_TYPE, "application/json; charset=utf-8",
FETCH_REQUEST_HEADER, "Accept: application/json",
FETCH_REQUEST_HEADER, "Expect:",
FETCH_RESPONSE_CODE, &code,
FETCH_END);
free(uri);
if (status == SUCCESS)
{
return SUCCESS;
}
if (code != HTTP_STATUS_CODE_PRECONDITION_FAILED || !response.ptr)
{
DBG2(DBG_IMV, "REST http request failed with status code: %d", code);
return FAILED;
}
if (jresponse)
{
/* Parse HTTP response into a JSON object */
tokener = json_tokener_new();
*jresponse = json_tokener_parse_ex(tokener, response.ptr, response.len);
json_tokener_free(tokener);
}
free(response.ptr);
return NEED_MORE;
}
METHOD(imv_swid_rest_t, destroy, void,
private_imv_swid_rest_t *this)
{
free(this->uri);
free(this);
}
/**
* Described in header.
*/
imv_swid_rest_t *imv_swid_rest_create(char *uri, u_int timeout)
{
private_imv_swid_rest_t *this;
INIT(this,
.public = {
.post = _post,
.destroy = _destroy,
},
.uri = strdup(uri),
.timeout = timeout,
);
return &this->public;
}
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_swid imv_swid
* @ingroup libimcv_plugins
*
* @defgroup imv_swid_rest_t imv_swid_rest
* @{ @ingroup imv_swid
*/
#ifndef IMV_SWID_REST_H_
#define IMV_SWID_REST_H_
#include <library.h>
#include <json.h>
typedef struct imv_swid_rest_t imv_swid_rest_t;
/**
* Public REST interface
*/
struct imv_swid_rest_t {
/**
* Post a HTTP request including a JSON object
*
* @param jreq JSON object in HTTP request
* @param jresp JSON object in HTTP response if NEED_MORE
* @return Status (SUCCESS, NEED_MORE or FAILED)
*/
status_t (*post)(imv_swid_rest_t *this, char *command, json_object *jreq,
json_object **jresp);
/**
* Destroy imv_swid_rest_t object
*/
void (*destroy)(imv_swid_rest_t *this);
};
/**
* Create an imv_swid_rest_t instance
*
* @param uri REST URI (http://username:password@hostname[:port]/api/)
* @param timeout Timeout of the REST connection
*/
imv_swid_rest_t* imv_swid_rest_create(char *uri, u_int timeout);
#endif /** IMV_SWID_REST_H_ @}*/
@@ -0,0 +1,402 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_swid_state.h"
#include <imv/imv_lang_string.h>
#include <imv/imv_reason_string.h>
#include <imv/imv_remediation_string.h>
#include <swid/swid_tag_id.h>
#include <tncif_policy.h>
#include <utils/lexparser.h>
#include <utils/debug.h>
typedef struct private_imv_swid_state_t private_imv_swid_state_t;
/**
* Private data of an imv_swid_state_t object.
*/
struct private_imv_swid_state_t {
/**
* Public members of imv_swid_state_t
*/
imv_swid_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
uint32_t max_msg_len;
/**
* Flags set for completed actions
*/
uint32_t action_flags;
/**
* IMV database session associated with TNCCS connection
*/
imv_session_t *session;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* IMV action recommendation
*/
TNC_IMV_Action_Recommendation rec;
/**
* IMV evaluation result
*/
TNC_IMV_Evaluation_Result eval;
/**
* IMV Scanner handshake state
*/
imv_swid_handshake_state_t handshake_state;
/**
* TNC Reason String
*/
imv_reason_string_t *reason_string;
/**
* IETF Remediation Instructions String
*/
imv_remediation_string_t *remediation_string;
/**
* SWID Tag Request ID
*/
uint32_t request_id;
/**
* Number of processed SWID Tag IDs
*/
int tag_id_count;
/**
* Number of processed SWID Tags
*/
int tag_count;
/**
* Top level JSON object
*/
json_object *jobj;
/**
* JSON array containing an inventory of SWID Tag IDs
*/
json_object *jarray;
/**
* Angel count
*/
int angel_count;
};
METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
private_imv_swid_state_t *this)
{
return this->connection_id;
}
METHOD(imv_state_t, has_long, bool,
private_imv_swid_state_t *this)
{
return this->has_long;
}
METHOD(imv_state_t, has_excl, bool,
private_imv_swid_state_t *this)
{
return this->has_excl;
}
METHOD(imv_state_t, set_flags, void,
private_imv_swid_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imv_state_t, set_max_msg_len, void,
private_imv_swid_state_t *this, uint32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imv_state_t, get_max_msg_len, uint32_t,
private_imv_swid_state_t *this)
{
return this->max_msg_len;
}
METHOD(imv_state_t, set_action_flags, void,
private_imv_swid_state_t *this, uint32_t flags)
{
this->action_flags |= flags;
}
METHOD(imv_state_t, get_action_flags, uint32_t,
private_imv_swid_state_t *this)
{
return this->action_flags;
}
METHOD(imv_state_t, set_session, void,
private_imv_swid_state_t *this, imv_session_t *session)
{
this->session = session;
}
METHOD(imv_state_t, get_session, imv_session_t*,
private_imv_swid_state_t *this)
{
return this->session;
}
METHOD(imv_state_t, get_contracts, seg_contract_manager_t*,
private_imv_swid_state_t *this)
{
return this->contracts;
}
METHOD(imv_state_t, change_state, void,
private_imv_swid_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imv_state_t, get_recommendation, void,
private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation *rec,
TNC_IMV_Evaluation_Result *eval)
{
*rec = this->rec;
*eval = this->eval;
}
METHOD(imv_state_t, set_recommendation, void,
private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = rec;
this->eval = eval;
}
METHOD(imv_state_t, update_recommendation, void,
private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = tncif_policy_update_recommendation(this->rec, rec);
this->eval = tncif_policy_update_evaluation(this->eval, eval);
}
METHOD(imv_state_t, get_reason_string, bool,
private_imv_swid_state_t *this, enumerator_t *language_enumerator,
chunk_t *reason_string, char **reason_language)
{
return FALSE;
}
METHOD(imv_state_t, get_remediation_instructions, bool,
private_imv_swid_state_t *this, enumerator_t *language_enumerator,
chunk_t *string, char **lang_code, char **uri)
{
return FALSE;
}
METHOD(imv_state_t, destroy, void,
private_imv_swid_state_t *this)
{
json_object_put(this->jobj);
DESTROY_IF(this->session);
DESTROY_IF(this->reason_string);
DESTROY_IF(this->remediation_string);
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imv_swid_state_t, set_handshake_state, void,
private_imv_swid_state_t *this, imv_swid_handshake_state_t new_state)
{
this->handshake_state = new_state;
}
METHOD(imv_swid_state_t, get_handshake_state, imv_swid_handshake_state_t,
private_imv_swid_state_t *this)
{
return this->handshake_state;
}
METHOD(imv_swid_state_t, set_request_id, void,
private_imv_swid_state_t *this, uint32_t request_id)
{
this->request_id = request_id;
}
METHOD(imv_swid_state_t, get_request_id, uint32_t,
private_imv_swid_state_t *this)
{
return this->request_id;
}
METHOD(imv_swid_state_t, set_swid_inventory, void,
private_imv_swid_state_t *this, swid_inventory_t *inventory)
{
chunk_t tag_creator, unique_sw_id;
char software_id[256];
json_object *jstring;
swid_tag_id_t *tag_id;
enumerator_t *enumerator;
enumerator = inventory->create_enumerator(inventory);
while (enumerator->enumerate(enumerator, &tag_id))
{
/* Construct software ID from tag creator and unique software ID */
tag_creator = tag_id->get_tag_creator(tag_id);
unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
snprintf(software_id, 256, "%.*s_%.*s",
tag_creator.len, tag_creator.ptr,
unique_sw_id.len, unique_sw_id.ptr);
DBG3(DBG_IMV, " %s", software_id);
/* Add software ID to JSON array */
jstring = json_object_new_string(software_id);
json_object_array_add(this->jarray, jstring);
}
enumerator->destroy(enumerator);
}
METHOD(imv_swid_state_t, get_swid_inventory, json_object*,
private_imv_swid_state_t *this)
{
return this->jobj;
}
METHOD(imv_swid_state_t, set_count, void,
private_imv_swid_state_t *this, int tag_id_count, int tag_count)
{
this->tag_id_count += tag_id_count;
this->tag_count += tag_count;
}
METHOD(imv_swid_state_t, get_count, void,
private_imv_swid_state_t *this, int *tag_id_count, int *tag_count)
{
if (tag_id_count)
{
*tag_id_count = this->tag_id_count;
}
if (tag_count)
{
*tag_count = this->tag_count;
}
}
METHOD(imv_swid_state_t, set_angel_count, void,
private_imv_swid_state_t *this, bool start)
{
this->angel_count += start ? 1 : -1;
}
METHOD(imv_swid_state_t, get_angel_count, int,
private_imv_swid_state_t *this)
{
return this->angel_count;
}
/**
* Described in header.
*/
imv_state_t *imv_swid_state_create(TNC_ConnectionID connection_id)
{
private_imv_swid_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.set_action_flags = _set_action_flags,
.get_action_flags = _get_action_flags,
.set_session = _set_session,
.get_session= _get_session,
.get_contracts = _get_contracts,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
.update_recommendation = _update_recommendation,
.get_reason_string = _get_reason_string,
.get_remediation_instructions = _get_remediation_instructions,
.destroy = _destroy,
},
.set_handshake_state = _set_handshake_state,
.get_handshake_state = _get_handshake_state,
.set_request_id = _set_request_id,
.get_request_id = _get_request_id,
.set_swid_inventory = _set_swid_inventory,
.get_swid_inventory = _get_swid_inventory,
.set_count = _set_count,
.get_count = _get_count,
.set_angel_count = _set_angel_count,
.get_angel_count = _get_angel_count,
},
.state = TNC_CONNECTION_STATE_CREATE,
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.contracts = seg_contract_manager_create(),
.jobj = json_object_new_object(),
.jarray = json_object_new_array(),
);
json_object_object_add(this->jobj, "data", this->jarray);
return &this->public.interface;
}
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_swid imv_swid
* @ingroup libimcv_plugins
*
* @defgroup imv_swid_state_t imv_swid_state
* @{ @ingroup imv_swid
*/
#ifndef IMV_SWID_STATE_H_
#define IMV_SWID_STATE_H_
#include <imv/imv_state.h>
#include <swid/swid_inventory.h>
#include <library.h>
#include <json.h>
typedef struct imv_swid_state_t imv_swid_state_t;
typedef enum imv_swid_handshake_state_t imv_swid_handshake_state_t;
/**
* IMV OS Handshake States (state machine)
*/
enum imv_swid_handshake_state_t {
IMV_SWID_STATE_INIT,
IMV_SWID_STATE_WORKITEMS,
IMV_SWID_STATE_END
};
/**
* Internal state of an imv_swid_t connection instance
*/
struct imv_swid_state_t {
/**
* imv_state_t interface
*/
imv_state_t interface;
/**
* Set state of the handshake
*
* @param new_state the handshake state of IMV
*/
void (*set_handshake_state)(imv_swid_state_t *this,
imv_swid_handshake_state_t new_state);
/**
* Get state of the handshake
*
* @return the handshake state of IMV
*/
imv_swid_handshake_state_t (*get_handshake_state)(imv_swid_state_t *this);
/**
* Set the SWID request ID
*
* @param request_id SWID request ID to be set
*/
void (*set_request_id)(imv_swid_state_t *this, uint32_t request_id);
/**
* Get the SWID request ID
*
* @return SWID request ID
*/
uint32_t (*get_request_id)(imv_swid_state_t *this);
/**
* Set or extend the SWID Tag ID inventory in the state
*
* @param inventory SWID Tags ID inventory to be added
*/
void (*set_swid_inventory)(imv_swid_state_t *this, swid_inventory_t *inventory);
/**
* Get the encoding of the complete SWID Tag ID inventory
*
* @return SWID Tags ID inventory as a JSON array
*/
json_object* (*get_swid_inventory)(imv_swid_state_t *this);
/**
* Set [or with multiple attributes increment] SWID Tag [ID] counters
*
* @param tag_id_count Number of received SWID Tag IDs
* @param tag_count Number of received SWID Tags
*/
void (*set_count)(imv_swid_state_t *this, int tag_id_count, int tag_count);
/**
* Set [or with multiple attributes increment] SWID Tag [ID] counters
*
* @param tag_id_count Number of received SWID Tag IDs
* @param tag_count Number of received SWID Tags
*/
void (*get_count)(imv_swid_state_t *this, int *tag_id_count, int *tag_count);
/**
* Increase/Decrease the ITA Angel count
*
* @param start TRUE increases and FALSE decreases count by one
*/
void (*set_angel_count)(imv_swid_state_t *this, bool start);
/**
* Get the ITA Angel count
*
* @return ITA Angel count
*/
int (*get_angel_count)(imv_swid_state_t *this);
};
/**
* Create an imv_swid_state_t instance
*
* @param id connection ID
*/
imv_state_t* imv_swid_state_create(TNC_ConnectionID id);
#endif /** IMV_SWID_STATE_H_ @}*/
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ita_comp_func_name.h"
char pts_ita_qualifier_flag_names[] = { 'K', 'S' };
ENUM_BEGIN(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_UNKNOWN,
PTS_ITA_QUALIFIER_TYPE_TNC,
"Unknown",
"Trusted Platform",
"Operating System",
"Graphical User Interface",
"Application",
"Networking",
"Library",
"TNC Defined Component"
);
ENUM_NEXT(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL,
PTS_ITA_QUALIFIER_TYPE_ALL,
PTS_ITA_QUALIFIER_TYPE_TNC,
"All Matching Components"
);
ENUM_END(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL);
ENUM(pts_ita_comp_func_names, PTS_ITA_COMP_FUNC_NAME_IGNORE,
PTS_ITA_COMP_FUNC_NAME_IMA,
"Ignore",
"Trusted GRUB Boot Loader",
"Trusted Boot",
"Linux IMA"
);
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_ita_comp_func_name pts_ita_comp_func_name
* @{ @ingroup pts
*/
#ifndef PTS_ITA_COMP_FUNC_NAME_H_
#define PTS_ITA_COMP_FUNC_NAME_H_
typedef enum pts_ita_qualifier_type_t pts_ita_qualifier_type_t;
typedef enum pts_ita_comp_func_name_t pts_ita_comp_func_name_t;
#include <library.h>
/**
* PTS Component Functional Name Qualifier Flags for the ITA namespace
*/
#define PTS_ITA_QUALIFIER_FLAG_KERNEL (1<<5)
#define PTS_ITA_QUALIFIER_FLAG_SUB (1<<4)
extern char pts_ita_qualifier_flag_names[];
/**
* Size of the PTS Component Functional Name Qualifier Type field
*/
#define PTS_ITA_QUALIFIER_TYPE_SIZE 4
/**
* PTS Component Functional Name Qualifier Types for the ITA namespace
* equal to section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum pts_ita_qualifier_type_t {
/** Unknown */
PTS_ITA_QUALIFIER_TYPE_UNKNOWN = 0x0,
/** Trusted Platform */
PTS_ITA_QUALIFIER_TYPE_TRUSTED = 0x1,
/** Operating System */
PTS_ITA_QUALIFIER_TYPE_OS = 0x2,
/** Graphical User Interface */
PTS_ITA_QUALIFIER_TYPE_GUI = 0x3,
/** Application */
PTS_ITA_QUALIFIER_TYPE_APP = 0x4,
/** Networking */
PTS_ITA_QUALIFIER_TYPE_NET = 0x5,
/** Library */
PTS_ITA_QUALIFIER_TYPE_LIB = 0x6,
/** TNC Defined Component */
PTS_ITA_QUALIFIER_TYPE_TNC = 0x7,
/** All Matching Components */
PTS_ITA_QUALIFIER_TYPE_ALL = 0xF,
};
extern enum_name_t *pts_ita_qualifier_type_names;
/**
* PTS Component Functional Name Binary Enumeration for the ITA namespace
*/
enum pts_ita_comp_func_name_t {
/** Ignore */
PTS_ITA_COMP_FUNC_NAME_IGNORE = 0x0000,
/** Trusted GRUB Boot Loader */
PTS_ITA_COMP_FUNC_NAME_TGRUB = 0x0001,
/** Trusted Boot */
PTS_ITA_COMP_FUNC_NAME_TBOOT = 0x0002,
/** Linux Integrity Measurement Architecture */
PTS_ITA_COMP_FUNC_NAME_IMA = 0x0003,
};
extern enum_name_t *pts_ita_comp_func_names;
#endif /** PTS_ITA_COMP_FUNC_NAME_H_ @}*/
@@ -0,0 +1,914 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ita_comp_ima.h"
#include "ita_comp_func_name.h"
#include "imcv.h"
#include "pts/pts_pcr.h"
#include "pts/pts_ima_bios_list.h"
#include "pts/pts_ima_event_list.h"
#include "pts/components/pts_component.h"
#include <utils/debug.h>
#include <crypto/hashers/hasher.h>
#include <pen/pen.h>
#define SECURITY_DIR "/sys/kernel/security/"
#define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements"
#define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements"
#define IMA_FILENAME_LEN_MAX 255
typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
typedef enum ima_state_t ima_state_t;
enum ima_state_t {
IMA_STATE_INIT,
IMA_STATE_BIOS,
IMA_STATE_BOOT_AGGREGATE,
IMA_STATE_RUNTIME,
IMA_STATE_END
};
/**
* Private data of a pts_ita_comp_ima_t object.
*
*/
struct pts_ita_comp_ima_t {
/**
* Public pts_component_t interface.
*/
pts_component_t public;
/**
* Component Functional Name
*/
pts_comp_func_name_t *name;
/**
* Sub-component depth
*/
uint32_t depth;
/**
* PTS measurement database
*/
pts_database_t *pts_db;
/**
* Primary key for AIK database entry
*/
int aik_id;
/**
* Primary key for IMA BIOS Component Functional Name database entry
*/
int bios_cid;
/**
* Primary key for IMA Runtime Component Functional Name database entry
*/
int ima_cid;
/**
* Component is registering IMA BIOS measurements
*/
bool is_bios_registering;
/**
* Component is registering IMA boot aggregate measurement
*/
bool is_ima_registering;
/**
* Measurement sequence number
*/
int seq_no;
/**
* Expected IMA BIOS measurement count
*/
int bios_count;
/**
* IMA BIOS measurements
*/
pts_ima_bios_list_t *bios_list;
/**
* IMA runtime file measurements
*/
pts_ima_event_list_t *ima_list;
/**
* Whether to send pcr_before and pcr_after info
*/
bool pcr_info;
/**
* Creation time of measurement
*/
time_t creation_time;
/**
* IMA state machine
*/
ima_state_t state;
/**
* Total number of component measurements
*/
int count;
/**
* Number of successful component measurements
*/
int count_ok;
/**
* Number of unknown component measurements
*/
int count_unknown;
/**
* Number of differing component measurements
*/
int count_differ;
/**
* Number of failed component measurements
*/
int count_failed;
/**
* Reference count
*/
refcount_t ref;
};
/**
* Extend measurement into PCR and create evidence
*/
static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
uint8_t qualifier, pts_pcr_t *pcrs,
uint32_t pcr, chunk_t measurement)
{
size_t pcr_len;
pts_pcr_transform_t pcr_transform;
pts_meas_algorithms_t hash_algo;
pts_comp_func_name_t *name;
pts_comp_evidence_t *evidence;
chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty;
hash_algo = PTS_MEAS_ALGO_SHA1;
pcr_len = HASH_SIZE_SHA1;
pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
if (this->pcr_info)
{
pcr_before = chunk_clone(pcrs->get(pcrs, pcr));
}
pcr_after = pcrs->extend(pcrs, pcr, measurement);
if (!pcr_after.ptr)
{
free(pcr_before.ptr);
return NULL;
}
name = this->name->clone(this->name);
name->set_qualifier(name, qualifier);
evidence = pts_comp_evidence_create(name, this->depth, pcr, hash_algo,
pcr_transform, this->creation_time, measurement);
if (this->pcr_info)
{
pcr_after =chunk_clone(pcrs->get(pcrs, pcr));
evidence->set_pcr_info(evidence, pcr_before, pcr_after);
}
return evidence;
}
/**
* Generate an IMA or IMA-NG hash from an event digest and event name
*
* @param digest event digest
* @param ima_algo hash algorithm string ("sha1:", "sha256:", etc.)
* @param ima_name event name
* @param little_endian endianness of client platform
* @param algo hash algorithm used by TPM
* @param hash_buf hash value to be compared with TPM measurement
*/
static bool ima_hash(chunk_t digest, char *ima_algo, char *ima_name,
bool little_endian, pts_meas_algorithms_t algo,
char *hash_buf)
{
hash_algorithm_t hash_alg;
hasher_t *hasher;
bool success;
hash_alg = pts_meas_algo_to_hash(algo);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
if (!hasher)
{
DBG1(DBG_PTS, "%N hasher could not be created",
hash_algorithm_short_names, hash_alg);
return FALSE;
}
if (ima_algo)
{
uint32_t d_len, n_len;
chunk_t algo_name, event_name, digest_len, name_len;
/* IMA-NG hash */
algo_name = chunk_create(ima_algo, strlen(ima_algo) + 1);
event_name = chunk_create(ima_name, strlen(ima_name) + 1);
d_len = algo_name.len + digest.len;
digest_len = chunk_create((uint8_t*)&d_len, sizeof(d_len));
/* TODO handle endianness of both client and server platforms */
n_len = event_name.len;
name_len = chunk_create((uint8_t*)&n_len, sizeof(n_len));
/* TODO handle endianness of both client and server platforms */
success = hasher->get_hash(hasher, digest_len, NULL) &&
hasher->get_hash(hasher, algo_name, NULL) &&
hasher->get_hash(hasher, digest, NULL) &&
hasher->get_hash(hasher, name_len, NULL) &&
hasher->get_hash(hasher, event_name, hash_buf);
}
else
{
u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
chunk_t file_name;
/* IMA legacy hash */
memset(filename_buffer, 0, sizeof(filename_buffer));
strncpy(filename_buffer, ima_name, IMA_FILENAME_LEN_MAX);
file_name = chunk_create (filename_buffer, sizeof(filename_buffer));
success = hasher->get_hash(hasher, digest, NULL) &&
hasher->get_hash(hasher, file_name, hash_buf);
}
hasher->destroy(hasher);
return success;
}
/**
* Compute and check boot aggregate value by hashing PCR0 to PCR7
*/
static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement,
char *algo)
{
u_char pcr_buffer[HASH_SIZE_SHA1];
chunk_t boot_aggregate;
hasher_t *hasher;
uint32_t i;
bool success, pcr_ok = TRUE;
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (!hasher)
{
DBG1(DBG_PTS, "%N hasher could not be created",
hash_algorithm_short_names, HASH_SHA1);
return FALSE;
}
for (i = 0; i < 8 && pcr_ok; i++)
{
pcr_ok = hasher->get_hash(hasher, pcrs->get(pcrs, i), NULL);
}
if (pcr_ok)
{
pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer);
}
hasher->destroy(hasher);
if (pcr_ok)
{
boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer));
/* TODO handle endianness of client platform */
pcr_ok = ima_hash(boot_aggregate, algo, "boot_aggregate",
TRUE, PTS_MEAS_ALGO_SHA1, pcr_buffer);
}
if (pcr_ok)
{
success = chunk_equals(boot_aggregate, measurement);
DBG1(DBG_PTS, "boot aggregate value is %scorrect",
success ? "":"in");
return success;
}
else
{
DBG1(DBG_PTS, "failed to compute boot aggregate value");
return FALSE;
}
}
METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
pts_ita_comp_ima_t *this)
{
return this->name;
}
METHOD(pts_component_t, get_evidence_flags, uint8_t,
pts_ita_comp_ima_t *this)
{
return PTS_REQ_FUNC_COMP_EVID_PCR;
}
METHOD(pts_component_t, get_depth, uint32_t,
pts_ita_comp_ima_t *this)
{
return this->depth;
}
METHOD(pts_component_t, measure, status_t,
pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
pts_comp_evidence_t **evidence)
{
pts_pcr_t *pcrs;
pts_comp_evidence_t *evid = NULL;
size_t algo_len, name_len;
chunk_t measurement;
char *uri, *algo, *name;
uint32_t pcr;
status_t status;
pcrs = pts->get_pcrs(pts);
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
{
switch (this->state)
{
case IMA_STATE_INIT:
this->bios_list = pts_ima_bios_list_create(
IMA_BIOS_MEASUREMENTS);
if (!this->bios_list)
{
return FAILED;
}
this->creation_time = this->bios_list->get_time(this->bios_list);
this->bios_count = this->bios_list->get_count(this->bios_list);
this->state = IMA_STATE_BIOS;
/* fall through to next state */
case IMA_STATE_BIOS:
status = this->bios_list->get_next(this->bios_list, &pcr,
&measurement);
if (status != SUCCESS)
{
DBG1(DBG_PTS, "could not retrieve bios measurement entry");
return status;
}
evid = extend_pcr(this, qualifier, pcrs, pcr, measurement);
this->state = this->bios_list->get_count(this->bios_list) ?
IMA_STATE_BIOS : IMA_STATE_INIT;
break;
default:
return FAILED;
}
}
else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_OS))
{
switch (this->state)
{
case IMA_STATE_INIT:
this->ima_list = pts_ima_event_list_create(
IMA_RUNTIME_MEASUREMENTS);
if (!this->ima_list)
{
return FAILED;
}
this->creation_time = this->ima_list->get_time(this->ima_list);
this->count = this->ima_list->get_count(this->ima_list);
this->state = IMA_STATE_BOOT_AGGREGATE;
/* fall through to next state */
case IMA_STATE_BOOT_AGGREGATE:
case IMA_STATE_RUNTIME:
status = this->ima_list->get_next(this->ima_list, &measurement,
&algo, &name);
if (status != SUCCESS)
{
DBG1(DBG_PTS, "could not retrieve ima measurement entry");
return status;
}
if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count)
{
if (!check_boot_aggregate(pcrs, measurement, algo))
{
return FAILED;
}
}
evid = extend_pcr(this, qualifier, pcrs, IMA_PCR,
measurement);
if (evid)
{
if (algo)
{
algo_len = strlen(algo);
name_len = strlen(name);
uri = malloc(algo_len + name_len + 1);
memcpy(uri, algo, algo_len);
strcpy(uri + algo_len, name);
}
else
{
uri = strdup(name);
}
evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
uri);
free(uri);
}
free(name);
free(algo);
this->state = this->ima_list->get_count(this->ima_list) ?
IMA_STATE_RUNTIME : IMA_STATE_END;
break;
default:
return FAILED;
}
}
else
{
DBG1(DBG_PTS, "unsupported functional component name qualifier");
return FAILED;
}
*evidence = evid;
if (!evid)
{
return FAILED;
}
return (this->state == IMA_STATE_INIT || this->state == IMA_STATE_END) ?
SUCCESS : NEED_MORE;
}
/**
* Parse a validation URI of the form <hash algorithm>:<event name>
* into its components
*/
static pts_meas_algorithms_t parse_validation_uri(pts_comp_evidence_t *evidence,
char **ima_name, char **ima_algo, char *algo_buf)
{
pts_meas_algorithms_t hash_algo;
char *uri, *pos, *algo, *name;
evidence->get_validation(evidence, &uri);
/* IMA-NG format? */
pos = strchr(uri, ':');
if (pos && (pos - uri + 1) < IMA_ALGO_LEN_MAX)
{
memset(algo_buf, '\0', IMA_ALGO_LEN_MAX);
memcpy(algo_buf, uri, pos - uri + 1);
algo = algo_buf;
name = pos + 1;
if (streq(algo, "sha1:") || streq(algo, ":"))
{
hash_algo = PTS_MEAS_ALGO_SHA1;
}
else if (streq(algo, "sha256:"))
{
hash_algo = PTS_MEAS_ALGO_SHA256;
}
else if (streq(algo, "sha384:"))
{
hash_algo = PTS_MEAS_ALGO_SHA384;
}
else
{
hash_algo = PTS_MEAS_ALGO_NONE;
}
}
else
{
algo = NULL;
name = uri;
hash_algo = PTS_MEAS_ALGO_SHA1;
}
if (ima_name)
{
*ima_name = name;
}
if (ima_algo)
{
*ima_algo = algo;
}
return hash_algo;
}
METHOD(pts_component_t, verify, status_t,
pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
pts_comp_evidence_t *evidence)
{
bool has_pcr_info;
uint32_t pcr;
pts_meas_algorithms_t algo;
pts_pcr_transform_t transform;
pts_pcr_t *pcrs;
time_t creation_time;
chunk_t measurement, pcr_before, pcr_after;
status_t status = NOT_FOUND;
this->aik_id = pts->get_aik_id(pts);
pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
&creation_time);
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
{
switch (this->state)
{
case IMA_STATE_INIT:
this->name->set_qualifier(this->name, qualifier);
status = this->pts_db->get_comp_measurement_count(this->pts_db,
this->name, this->aik_id, algo,
&this->bios_cid, &this->bios_count);
this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
if (status != SUCCESS)
{
return status;
}
if (this->bios_count)
{
DBG1(DBG_PTS, "checking %d BIOS evidence measurements",
this->bios_count);
}
else
{
DBG1(DBG_PTS, "registering BIOS evidence measurements");
this->is_bios_registering = TRUE;
}
this->state = IMA_STATE_BIOS;
/* fall through to next state */
case IMA_STATE_BIOS:
if (this->is_bios_registering)
{
status = this->pts_db->insert_comp_measurement(this->pts_db,
measurement, this->bios_cid, this->aik_id,
++this->seq_no, pcr, algo);
if (status != SUCCESS)
{
return status;
}
this->bios_count = this->seq_no + 1;
}
else
{
status = this->pts_db->check_comp_measurement(this->pts_db,
measurement, this->bios_cid, this->aik_id,
++this->seq_no, pcr, algo);
if (status == FAILED)
{
return status;
}
}
break;
default:
return FAILED;
}
}
else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_OS))
{
int ima_count;
char *ima_algo, *ima_name;
char algo_buf[IMA_ALGO_LEN_MAX];
pts_meas_algorithms_t hash_algo;
hash_algo = parse_validation_uri(evidence, &ima_name, &ima_algo,
algo_buf);
switch (this->state)
{
case IMA_STATE_BIOS:
this->state = IMA_STATE_RUNTIME;
if (!streq(ima_name, "boot_aggregate"))
{
DBG1(DBG_PTS, "ima: name must be 'boot_aggregate' "
"but is '%s'", ima_name);
return FAILED;
}
if (hash_algo != PTS_MEAS_ALGO_SHA1)
{
DBG1(DBG_PTS, "ima: boot_aggregate algorithm must be %N "
"but is %N",
pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1,
pts_meas_algorithm_names, hash_algo);
return FAILED;
}
if (!check_boot_aggregate(pcrs, measurement, ima_algo))
{
return FAILED;
}
this->state = IMA_STATE_INIT;
/* fall through to next state */
case IMA_STATE_INIT:
this->name->set_qualifier(this->name, qualifier);
status = this->pts_db->get_comp_measurement_count(this->pts_db,
this->name, this->aik_id, algo,
&this->ima_cid, &ima_count);
this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
if (status != SUCCESS)
{
return status;
}
if (ima_count)
{
DBG1(DBG_PTS, "checking boot aggregate evidence "
"measurement");
status = this->pts_db->check_comp_measurement(this->pts_db,
measurement, this->ima_cid,
this->aik_id, 1, pcr, algo);
}
else
{
DBG1(DBG_PTS, "registering boot aggregate evidence "
"measurement");
this->is_ima_registering = TRUE;
status = this->pts_db->insert_comp_measurement(this->pts_db,
measurement, this->ima_cid,
this->aik_id, 1, pcr, algo);
}
this->state = IMA_STATE_RUNTIME;
if (status != SUCCESS)
{
return status;
}
break;
case IMA_STATE_RUNTIME:
{
uint8_t hash_buf[HASH_SIZE_SHA512];
chunk_t digest, hash;
enumerator_t *e;
this->count++;
if (evidence->get_validation(evidence, NULL) !=
PTS_COMP_EVID_VALIDATION_PASSED)
{
DBG1(DBG_PTS, "evidence validation failed");
this->count_failed++;
return FAILED;
}
hash = chunk_create(hash_buf, pts_meas_algo_hash_size(algo));
e = this->pts_db->create_file_meas_enumerator(this->pts_db,
pts->get_platform_id(pts),
hash_algo, ima_name);
if (e)
{
while (e->enumerate(e, &digest))
{
if (!ima_hash(digest, ima_algo, ima_name,
FALSE, algo, hash_buf))
{
status = FAILED;
break;
}
if (chunk_equals(measurement, hash))
{
status = SUCCESS;
break;
}
else
{
status = VERIFY_ERROR;
}
}
e->destroy(e);
}
else
{
status = FAILED;
}
switch (status)
{
case SUCCESS:
DBG3(DBG_PTS, "%#B for '%s' is ok",
&measurement, ima_name);
this->count_ok++;
break;
case NOT_FOUND:
DBG2(DBG_PTS, "%#B for '%s' not found",
&measurement, ima_name);
this->count_unknown++;
break;
case VERIFY_ERROR:
DBG1(DBG_PTS, "%#B for '%s' differs",
&measurement, ima_name);
this->count_differ++;
break;
case FAILED:
default:
DBG1(DBG_PTS, "%#B for '%s' failed",
&measurement, ima_name);
this->count_failed++;
}
break;
}
default:
return FAILED;
}
}
else
{
DBG1(DBG_PTS, "unsupported functional component name qualifier");
return FAILED;
}
has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
if (has_pcr_info)
{
if (!chunk_equals(pcr_before, pcrs->get(pcrs, pcr)))
{
DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
pcr);
}
if (pcrs->set(pcrs, pcr, pcr_after))
{
return status;
}
}
else
{
pcr_after = pcrs->extend(pcrs, pcr, measurement);
if (pcr_after.ptr)
{
return status;
}
}
return FAILED;
}
METHOD(pts_component_t, finalize, bool,
pts_ita_comp_ima_t *this, uint8_t qualifier, bio_writer_t *result)
{
char result_buf[BUF_LEN];
char *pos = result_buf;
size_t len = BUF_LEN;
int written;
bool success = TRUE;
this->name->set_qualifier(this->name, qualifier);
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
{
/* finalize BIOS measurements */
if (this->is_bios_registering)
{
/* close registration */
this->is_bios_registering = FALSE;
snprintf(pos, len, "registered %d BIOS evidence measurements",
this->seq_no);
}
else if (this->seq_no < this->bios_count)
{
snprintf(pos, len, "%d of %d BIOS evidence measurements missing",
this->bios_count - this->seq_no, this->bios_count);
success = FALSE;
}
else
{
snprintf(pos, len, "%d BIOS evidence measurements are ok",
this->bios_count);
}
}
else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_OS))
{
/* finalize IMA file measurements */
if (this->is_ima_registering)
{
/* close registration */
this->is_ima_registering = FALSE;
written = snprintf(pos, len, "registered IMA boot aggregate "
"evidence measurement; ");
pos += written;
len -= written;
}
if (this->count)
{
snprintf(pos, len, "processed %d IMA file evidence measurements: "
"%d ok, %d unknown, %d differ, %d failed",
this->count, this->count_ok, this->count_unknown,
this->count_differ, this->count_failed);
}
else
{
snprintf(pos, len, "no IMA file evidence measurements");
success = FALSE;
}
}
else
{
snprintf(pos, len, "unsupported functional component name qualifier");
success = FALSE;
}
this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
DBG1(DBG_PTS, "%s", result_buf);
result->write_data(result, chunk_from_str(result_buf));
return success;
}
METHOD(pts_component_t, get_ref, pts_component_t*,
pts_ita_comp_ima_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(pts_component_t, destroy, void,
pts_ita_comp_ima_t *this)
{
int count;
if (ref_put(&this->ref))
{
if (this->is_bios_registering)
{
count = this->pts_db->delete_comp_measurements(this->pts_db,
this->bios_cid, this->aik_id);
DBG1(DBG_PTS, "deleted %d registered BIOS evidence measurements",
count);
}
if (this->is_ima_registering)
{
count = this->pts_db->delete_comp_measurements(this->pts_db,
this->ima_cid, this->aik_id);
DBG1(DBG_PTS, "deleted registered boot aggregate evidence "
"measurement");
}
DESTROY_IF(this->bios_list);
DESTROY_IF(this->ima_list);
this->name->destroy(this->name);
free(this);
}
}
/**
* See header
*/
pts_component_t *pts_ita_comp_ima_create(uint32_t depth,
pts_database_t *pts_db)
{
pts_ita_comp_ima_t *this;
INIT(this,
.public = {
.get_comp_func_name = _get_comp_func_name,
.get_evidence_flags = _get_evidence_flags,
.get_depth = _get_depth,
.measure = _measure,
.verify = _verify,
.finalize = _finalize,
.get_ref = _get_ref,
.destroy = _destroy,
},
.name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
PTS_QUALIFIER_UNKNOWN),
.depth = depth,
.pts_db = pts_db,
.pcr_info = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-attestation.pcr_info", FALSE, lib->ns),
.ref = 1,
);
return &this->public;
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2011-2012 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 pts_ita_comp_func_name pts_ita_comp_func_name
* @{ @ingroup pts
*/
#ifndef PTS_ITA_COMP_IMA_H_
#define PTS_ITA_COMP_IMA_H_
#include "pts/components/pts_component.h"
/**
* Create a PTS ITS Functional Component object
*
* @param depth Sub-component depth
* @param pts_db PTS measurement database
*/
pts_component_t* pts_ita_comp_ima_create(u_int32_t depth,
pts_database_t *pts_db);
#endif /** PTS_ITA_COMP_IMA_H_ @}*/
@@ -0,0 +1,362 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ita_comp_tboot.h"
#include "ita_comp_func_name.h"
#include "imcv.h"
#include "pts/components/pts_component.h"
#include <utils/debug.h>
#include <pen/pen.h>
typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t;
/**
* Private data of a pts_ita_comp_tboot_t object.
*
*/
struct pts_ita_comp_tboot_t {
/**
* Public pts_component_t interface.
*/
pts_component_t public;
/**
* Component Functional Name
*/
pts_comp_func_name_t *name;
/**
* Sub-component depth
*/
u_int32_t depth;
/**
* PTS measurement database
*/
pts_database_t *pts_db;
/**
* Primary key for AIK database entry
*/
int aik_id;
/**
* Primary key for Component Functional Name database entry
*/
int cid;
/**
* Primary key for AIK database entry
*/
int kid;
/**
* Component is registering measurements
*/
bool is_registering;
/**
* Time of TBOOT measurement
*/
time_t measurement_time;
/**
* Expected measurement count
*/
int count;
/**
* Measurement sequence number
*/
int seq_no;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
pts_ita_comp_tboot_t *this)
{
return this->name;
}
METHOD(pts_component_t, get_evidence_flags, u_int8_t,
pts_ita_comp_tboot_t *this)
{
return PTS_REQ_FUNC_COMP_EVID_PCR;
}
METHOD(pts_component_t, get_depth, u_int32_t,
pts_ita_comp_tboot_t *this)
{
return this->depth;
}
METHOD(pts_component_t, measure, status_t,
pts_ita_comp_tboot_t *this, u_int8_t qualifier, pts_t *pts,
pts_comp_evidence_t **evidence)
{
size_t pcr_len;
pts_pcr_t *pcrs;
pts_pcr_transform_t pcr_transform;
pts_meas_algorithms_t hash_algo;
pts_comp_evidence_t *evid;
char *meas_hex, *pcr_before_hex, *pcr_after_hex;
chunk_t measurement, pcr_before, pcr_after;
u_int32_t extended_pcr;
switch (this->seq_no++)
{
case 0:
/* dummy data since currently the TBOOT log is not retrieved */
time(&this->measurement_time);
meas_hex = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.pcr17_meas", NULL, lib->ns);
pcr_before_hex = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.pcr17_before", NULL, lib->ns);
pcr_after_hex = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.pcr17_after", NULL, lib->ns);
extended_pcr = PCR_TBOOT_POLICY;
break;
case 1:
/* dummy data since currently the TBOOT log is not retrieved */
meas_hex = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.pcr18_meas", NULL, lib->ns);
pcr_before_hex = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.pcr18_before", NULL, lib->ns);
pcr_after_hex = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.pcr18_after", NULL, lib->ns);
extended_pcr = PCR_TBOOT_MLE;
break;
default:
return FAILED;
}
if (meas_hex == NULL || pcr_before_hex == NULL || pcr_after_hex == NULL)
{
return FAILED;
}
hash_algo = PTS_MEAS_ALGO_SHA1;
pcr_len = HASH_SIZE_SHA1;
pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
/* get and check the measurement data */
measurement = chunk_from_hex(
chunk_create(meas_hex, strlen(meas_hex)), NULL);
pcr_before = chunk_from_hex(
chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL);
pcr_after = chunk_from_hex(
chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL);
if (pcr_before.len != pcr_len || pcr_after.len != pcr_len ||
measurement.len != pcr_len)
{
DBG1(DBG_PTS, "TBOOT measurement or PCR data have the wrong size");
free(measurement.ptr);
free(pcr_before.ptr);
free(pcr_after.ptr);
return FAILED;
}
pcrs = pts->get_pcrs(pts);
pcrs->set(pcrs, extended_pcr, pcr_after);
evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
this->depth, extended_pcr, hash_algo, pcr_transform,
this->measurement_time, measurement);
evid->set_pcr_info(evid, pcr_before, pcr_after);
return (this->seq_no < 2) ? NEED_MORE : SUCCESS;
}
METHOD(pts_component_t, verify, status_t,
pts_ita_comp_tboot_t *this, u_int8_t qualifier,pts_t *pts,
pts_comp_evidence_t *evidence)
{
bool has_pcr_info;
u_int32_t extended_pcr, vid, name;
enum_name_t *names;
pts_meas_algorithms_t algo;
pts_pcr_transform_t transform;
pts_pcr_t *pcrs;
time_t measurement_time;
chunk_t measurement, pcr_before, pcr_after;
status_t status;
this->aik_id = pts->get_aik_id(pts);
pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &extended_pcr,
&algo, &transform, &measurement_time);
status = this->pts_db->get_comp_measurement_count(this->pts_db,
this->name, this->aik_id, algo,
&this->cid, &this->count);
if (status != SUCCESS)
{
return status;
}
vid = this->name->get_vendor_id(this->name);
name = this->name->get_name(this->name);
names = imcv_pts_components->get_comp_func_names(imcv_pts_components, vid);
if (this->count)
{
DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
"measurements", this->count, pen_names, vid, names, name);
}
else
{
DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
"measurements", pen_names, vid, names, name);
this->is_registering = TRUE;
}
if (this->is_registering)
{
status = this->pts_db->insert_comp_measurement(this->pts_db,
measurement, this->cid, this->aik_id,
++this->seq_no, extended_pcr, algo);
if (status != SUCCESS)
{
return status;
}
this->count = this->seq_no + 1;
}
else
{
status = this->pts_db->check_comp_measurement(this->pts_db,
measurement, this->cid, this->kid,
++this->seq_no, extended_pcr, algo);
if (status != SUCCESS)
{
return status;
}
}
has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
if (has_pcr_info)
{
if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr)))
{
DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
extended_pcr);
}
if (pcrs->set(pcrs, extended_pcr, pcr_after))
{
return SUCCESS;
}
}
return SUCCESS;
}
METHOD(pts_component_t, finalize, bool,
pts_ita_comp_tboot_t *this, u_int8_t qualifier, bio_writer_t *result)
{
char result_buf[BUF_LEN];
if (this->is_registering)
{
/* close registration */
this->is_registering = FALSE;
snprintf(result_buf, BUF_LEN, "registered %d evidence measurements",
this->seq_no);
}
else if (this->seq_no < this->count)
{
snprintf(result_buf, BUF_LEN, "%d of %d evidence measurements "
"missing", this->count - this->seq_no, this->count);
return FALSE;
}
else
{
snprintf(result_buf, BUF_LEN, "%d evidence measurements are ok",
this->count);
}
DBG1(DBG_PTS, "%s", result_buf);
result->write_data(result, chunk_from_str(result_buf));
return TRUE;
}
METHOD(pts_component_t, get_ref, pts_component_t*,
pts_ita_comp_tboot_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(pts_component_t, destroy, void,
pts_ita_comp_tboot_t *this)
{
int count;
u_int32_t vid, name;
enum_name_t *names;
if (ref_put(&this->ref))
{
if (this->is_registering)
{
count = this->pts_db->delete_comp_measurements(this->pts_db,
this->cid, this->aik_id);
vid = this->name->get_vendor_id(this->name);
name = this->name->get_name(this->name);
names = imcv_pts_components->get_comp_func_names(imcv_pts_components,
vid);
DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
"evidence measurements", count, pen_names, vid, names, name);
}
this->name->destroy(this->name);
free(this);
}
}
/**
* See header
*/
pts_component_t *pts_ita_comp_tboot_create(u_int32_t depth,
pts_database_t *pts_db)
{
pts_ita_comp_tboot_t *this;
INIT(this,
.public = {
.get_comp_func_name = _get_comp_func_name,
.get_evidence_flags = _get_evidence_flags,
.get_depth = _get_depth,
.measure = _measure,
.verify = _verify,
.finalize = _finalize,
.get_ref = _get_ref,
.destroy = _destroy,
},
.name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED),
.depth = depth,
.pts_db = pts_db,
.ref = 1,
);
return &this->public;
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu, 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 pts_ita_comp_func_name pts_ita_comp_func_name
* @{ @ingroup pts
*/
#ifndef PTS_ITA_COMP_TBOOT_H_
#define PTS_ITA_COMP_TBOOT_H_
#include "pts/components/pts_component.h"
/**
* Create a PTS ITS Functional Component object
*
* @param depth Sub-component depth
* @param pts_db PTS measurement database
*/
pts_component_t* pts_ita_comp_tboot_create(u_int32_t depth,
pts_database_t *pts_db);
#endif /** PTS_ITA_COMP_TBOOT_H_ @}*/
@@ -0,0 +1,208 @@
/*
* Copyright (C) 2011-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "ita_comp_tgrub.h"
#include "ita_comp_func_name.h"
#include "pts/components/pts_component.h"
#include <utils/debug.h>
#include <pen/pen.h>
typedef struct pts_ita_comp_tgrub_t pts_ita_comp_tgrub_t;
/**
* Private data of a pts_ita_comp_tgrub_t object.
*
*/
struct pts_ita_comp_tgrub_t {
/**
* Public pts_component_t interface.
*/
pts_component_t public;
/**
* Component Functional Name
*/
pts_comp_func_name_t *name;
/**
* Sub-component depth
*/
u_int32_t depth;
/**
* PTS measurement database
*/
pts_database_t *pts_db;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
pts_ita_comp_tgrub_t *this)
{
return this->name;
}
METHOD(pts_component_t, get_evidence_flags, u_int8_t,
pts_ita_comp_tgrub_t *this)
{
return PTS_REQ_FUNC_COMP_EVID_PCR;
}
METHOD(pts_component_t, get_depth, u_int32_t,
pts_ita_comp_tgrub_t *this)
{
return this->depth;
}
METHOD(pts_component_t, measure, status_t,
pts_ita_comp_tgrub_t *this, u_int8_t qualifier, pts_t *pts,
pts_comp_evidence_t **evidence)
{
size_t pcr_len;
pts_pcr_transform_t pcr_transform;
pts_meas_algorithms_t hash_algo;
pts_comp_evidence_t *evid;
u_int32_t extended_pcr;
time_t measurement_time;
chunk_t measurement, pcr_before, pcr_after;
/* Provisional implementation for TGRUB */
extended_pcr = PCR_DEBUG;
time(&measurement_time);
if (!pts->read_pcr(pts, extended_pcr, &pcr_after))
{
DBG1(DBG_PTS, "error occurred while reading PCR: %d", extended_pcr);
return FAILED;
}
hash_algo = PTS_MEAS_ALGO_SHA1;
pcr_len = HASH_SIZE_SHA1;
pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
measurement = chunk_alloc(pcr_len);
memset(measurement.ptr, 0x00, measurement.len);
pcr_before = chunk_alloc(pcr_len);
memset(pcr_before.ptr, 0x00, pcr_before.len);
evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
this->depth, extended_pcr,
hash_algo, pcr_transform,
measurement_time, measurement);
evid->set_pcr_info(evid, pcr_before, pcr_after);
return SUCCESS;
}
METHOD(pts_component_t, verify, status_t,
pts_ita_comp_tgrub_t *this, u_int8_t qualifier, pts_t *pts,
pts_comp_evidence_t *evidence)
{
bool has_pcr_info;
u_int32_t extended_pcr;
pts_meas_algorithms_t algo;
pts_pcr_transform_t transform;
pts_pcr_t *pcrs;
time_t measurement_time;
chunk_t pcr_before, pcr_after;
chunk_t measurement __attribute__((unused));
pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &extended_pcr,
&algo, &transform, &measurement_time);
if (extended_pcr != PCR_DEBUG)
{
return FAILED;
}
/* TODO check measurement in database */
has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
if (has_pcr_info)
{
if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr)))
{
DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to pcr value");
}
if (pcrs->set(pcrs, extended_pcr, pcr_after))
{
return SUCCESS;
}
}
return SUCCESS;
}
METHOD(pts_component_t, finalize, bool,
pts_ita_comp_tgrub_t *this, u_int8_t qualifier, bio_writer_t *result)
{
return FALSE;
}
METHOD(pts_component_t, get_ref, pts_component_t*,
pts_ita_comp_tgrub_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(pts_component_t, destroy, void,
pts_ita_comp_tgrub_t *this)
{
if (ref_put(&this->ref))
{
this->name->destroy(this->name);
free(this);
}
}
/**
* See header
*/
pts_component_t *pts_ita_comp_tgrub_create(u_int32_t depth,
pts_database_t *pts_db)
{
pts_ita_comp_tgrub_t *this;
INIT(this,
.public = {
.get_comp_func_name = _get_comp_func_name,
.get_evidence_flags = _get_evidence_flags,
.get_depth = _get_depth,
.measure = _measure,
.verify = _verify,
.finalize = _finalize,
.get_ref = _get_ref,
.destroy = _destroy,
},
.name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TGRUB,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED),
.depth = depth,
.pts_db = pts_db,
.ref = 1,
);
return &this->public;
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu, 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 pts_ita_comp_func_name pts_ita_comp_func_name
* @{ @ingroup pts
*/
#ifndef PTS_ITA_COMP_TGRUB_H_
#define PTS_ITA_COMP_TGRUB_H_
#include "pts/components/pts_component.h"
/**
* Create a PTS ITS Functional Component object
*
* @param depth Sub-component depth
* @param pts_db PTS measurement database
*/
pts_component_t* pts_ita_comp_tgrub_create(u_int32_t depth,
pts_database_t *pts_db);
#endif /** PTS_ITA_COMP_TGRUB_H_ @}*/
@@ -0,0 +1,255 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu, 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 "pts/components/pts_comp_evidence.h"
#include <utils/debug.h>
typedef struct private_pts_comp_evidence_t private_pts_comp_evidence_t;
/**
* Private data of a pts_comp_evidence_t object.
*/
struct private_pts_comp_evidence_t {
/**
* Public pts_comp_evidence_t interface.
*/
pts_comp_evidence_t public;
/**
* Component Functional Name
*/
pts_comp_func_name_t *name;
/**
* Sub-Component Depth
*/
u_int32_t depth;
/**
* Measurement Time
*/
time_t measurement_time;
/**
* Measurement Time
*/
chunk_t measurement;
/**
* Measurement Hash Algorithm
*/
pts_meas_algorithms_t hash_algorithm;
/**
* Is PCR Information included?
*/
bool has_pcr_info;
/**
* PCR the measurement was extended into
*/
u_int32_t extended_pcr;
/**
* PCR value before extension
*/
chunk_t pcr_before;
/**
* PCR value after extension
*/
chunk_t pcr_after;
/**
* Transformation used for extending measurement into PCR
*/
pts_pcr_transform_t transform;
/**
* Component Validation Result
*/
pts_comp_evid_validation_t validation;
/**
* Verification Policy URI
*/
char *policy_uri;
};
METHOD(pts_comp_evidence_t, get_comp_func_name, pts_comp_func_name_t*,
private_pts_comp_evidence_t *this, u_int32_t *depth)
{
if (depth)
{
*depth = this->depth;
}
return this->name;
}
METHOD(pts_comp_evidence_t, get_extended_pcr, u_int32_t,
private_pts_comp_evidence_t *this)
{
return this->extended_pcr;
}
METHOD(pts_comp_evidence_t, get_measurement, chunk_t,
private_pts_comp_evidence_t *this, u_int32_t *extended_pcr,
pts_meas_algorithms_t *algo, pts_pcr_transform_t *transform,
time_t *measurement_time)
{
if (extended_pcr)
{
*extended_pcr = this->extended_pcr;
}
if (algo)
{
*algo = this->hash_algorithm;
}
if (transform)
{
*transform = this->transform;
}
if (measurement_time)
{
*measurement_time = this->measurement_time;
}
return this->measurement;
}
METHOD(pts_comp_evidence_t, get_pcr_info, bool,
private_pts_comp_evidence_t *this, chunk_t *pcr_before, chunk_t *pcr_after)
{
if (pcr_before)
{
*pcr_before = this->pcr_before;
}
if (pcr_after)
{
*pcr_after = this->pcr_after;
}
return this->has_pcr_info;
}
METHOD(pts_comp_evidence_t, set_pcr_info, void,
private_pts_comp_evidence_t *this, chunk_t pcr_before, chunk_t pcr_after)
{
this->has_pcr_info = TRUE;
this->pcr_before = pcr_before;
this->pcr_after = pcr_after;
DBG3(DBG_PTS, "PCR %2d before value : %#B", this->extended_pcr, &pcr_before);
DBG3(DBG_PTS, "PCR %2d after value : %#B", this->extended_pcr, &pcr_after);
}
METHOD(pts_comp_evidence_t, get_validation, pts_comp_evid_validation_t,
private_pts_comp_evidence_t *this, char **uri)
{
if (uri)
{
*uri = this->policy_uri;
}
return this->validation;
}
METHOD(pts_comp_evidence_t, set_validation, void,
private_pts_comp_evidence_t *this, pts_comp_evid_validation_t validation,
char *uri)
{
this->validation = validation;
if (uri)
{
this->policy_uri = strdup(uri);
DBG3(DBG_PTS, "'%s'", uri);
}
}
METHOD(pts_comp_evidence_t, destroy, void,
private_pts_comp_evidence_t *this)
{
this->name->destroy(this->name);
free(this->measurement.ptr);
free(this->pcr_before.ptr);
free(this->pcr_after.ptr);
free(this->policy_uri);
free(this);
}
/**
* See header
*/
pts_comp_evidence_t *pts_comp_evidence_create(pts_comp_func_name_t *name,
u_int32_t depth,
u_int32_t extended_pcr,
pts_meas_algorithms_t algo,
pts_pcr_transform_t transform,
time_t measurement_time,
chunk_t measurement)
{
private_pts_comp_evidence_t *this;
INIT(this,
.public = {
.get_comp_func_name = _get_comp_func_name,
.get_extended_pcr = _get_extended_pcr,
.get_measurement = _get_measurement,
.get_pcr_info = _get_pcr_info,
.set_pcr_info = _set_pcr_info,
.get_validation = _get_validation,
.set_validation = _set_validation,
.destroy = _destroy,
},
.name = name,
.depth = depth,
.extended_pcr = extended_pcr,
.hash_algorithm = algo,
.transform = transform,
.measurement_time = measurement_time,
.measurement = measurement,
);
name->log(name, "");
DBG3(DBG_PTS, "measurement time: %T", &measurement_time, FALSE);
DBG3(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement);
return &this->public;
}
/**
* See header
*/
pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo,
size_t pcr_len)
{
size_t hash_size;
hash_size = pts_meas_algo_hash_size(algo);
if (hash_size == 0)
{
return PTS_PCR_TRANSFORM_NO;
}
if (hash_size == pcr_len)
{
return PTS_PCR_TRANSFORM_MATCH;
}
if (hash_size > pcr_len)
{
return PTS_PCR_TRANSFORM_LONG;
}
return PTS_PCR_TRANSFORM_SHORT;
}
@@ -0,0 +1,170 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu, 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 pts_comp_evidence pts_comp_evidence
* @{ @ingroup pts
*/
#ifndef PTS_COMP_EVIDENCE_H_
#define PTS_COMP_EVIDENCE_H_
typedef struct pts_comp_evidence_t pts_comp_evidence_t;
typedef enum pts_pcr_transform_t pts_pcr_transform_t;
typedef enum pts_comp_evid_validation_t pts_comp_evid_validation_t;
#include "pts/pts_meas_algo.h"
#include "pts/components/pts_comp_func_name.h"
#include <library.h>
/**
* PTS PCR Transformations
*/
enum pts_pcr_transform_t {
/** No Transformation */
PTS_PCR_TRANSFORM_NO = 0,
/** Hash Value matched PCR size */
PTS_PCR_TRANSFORM_MATCH = 1,
/** Hash value shorter than PCR size */
PTS_PCR_TRANSFORM_SHORT = 2,
/** Hash value longer than PCR size */
PTS_PCR_TRANSFORM_LONG = 3,
};
/**
* PTS Component Evidence Validation Result Flags
*/
enum pts_comp_evid_validation_t {
/** No Validation was attempted */
PTS_COMP_EVID_VALIDATION_NONE = 0x00,
/** Attempted validation, unable to verify */
PTS_COMP_EVID_VALIDATION_UNABLE = 0x20,
/** Attempted validation, verification failed */
PTS_COMP_EVID_VALIDATION_FAILED = 0x40,
/** Attempted validation, verification passed */
PTS_COMP_EVID_VALIDATION_PASSED = 0x60,
};
/**
* PTS Functional Component Interface
*/
struct pts_comp_evidence_t {
/**
* Gets the Component Functional Name and Sub-Component Depth
*
* @param depth Sub-Component Depth
* @result Component Functional Name
*/
pts_comp_func_name_t* (*get_comp_func_name)(pts_comp_evidence_t *this,
u_int32_t *depth);
/**
* Gets the PCR the measurement was extended into
*
* @result PCR the measurement was extended into
*/
u_int32_t (*get_extended_pcr)(pts_comp_evidence_t *this);
/**
* Gets the measurement and the algorithms used
*
* @param extended_pcr PCR the measurement was extended into
* @param algo Measurement hash algorithm
* @param transform Transformation used for PCR extension
* @param measurement_time Time the measurement was taken
* @result Measurement hash value
*/
chunk_t (*get_measurement)(pts_comp_evidence_t *this,
u_int32_t *extended_pcr,
pts_meas_algorithms_t *algo,
pts_pcr_transform_t *transform,
time_t *measurement_time);
/**
* Gets the PCR information if available
*
* @param pcr_before PCR value before extension
* @param pcr_after PCR value after extension
* @result TRUE if PCR information is available
*/
bool (*get_pcr_info)(pts_comp_evidence_t *this, chunk_t *pcr_before,
chunk_t *pcr_after);
/**
* Sets PCR information if available
*
* @param pcr_before PCR value before extension
* @param pcr_after PCR value after extension
*/
void (*set_pcr_info)(pts_comp_evidence_t *this, chunk_t pcr_before,
chunk_t pcr_after);
/**
* Gets Validation Result if available
*
* @param uri Verification Policy URI
* @return validation Validation Result
*/
pts_comp_evid_validation_t (*get_validation)(pts_comp_evidence_t *this,
char **uri);
/**
* Sets Validation Result if available
*
* @param validation Validation Result
* @param uri Verification Policy URI
*/
void (*set_validation)(pts_comp_evidence_t *this,
pts_comp_evid_validation_t validation, char* uri);
/**
* Destroys a pts_comp_evidence_t object.
*/
void (*destroy)(pts_comp_evidence_t *this);
};
/**
* Creates a pts_comp_evidence_t object
*
* @param name Component Functional Name
* @param depth Sub-component depth
* @param extended_pcr PCR the measurement was extended into
* @param algo Measurement hash algorithm
* @param transform Transformation used for PCR extension
* @param measurement_time Time the measurement was taken, 0 if unknown
* @param measurement Measurement hash value
*/
pts_comp_evidence_t* pts_comp_evidence_create(pts_comp_func_name_t *name,
u_int32_t depth,
u_int32_t extended_pcr,
pts_meas_algorithms_t algo,
pts_pcr_transform_t transform,
time_t measurement_time,
chunk_t measurement);
/**
* Determine transform to fit measurement hash into PCR register
*
* @param algo Measurement hash algorithm
* @param pcr_len Length of the PCR registers in bytes
* @return PCR transform type
*/
pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo,
size_t pcr_len);
#endif /** PTS_COMP_EVIDENCE_H_ @}*/
@@ -0,0 +1,162 @@
/*
* Copyright (C) 2011-2014 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 "imcv.h"
#include "pts/components/pts_comp_func_name.h"
#include <utils/debug.h>
typedef struct private_pts_comp_func_name_t private_pts_comp_func_name_t;
/**
* Private data of a pts_comp_func_name_t object.
*
*/
struct private_pts_comp_func_name_t {
/**
* Public pts_comp_func_name_t interface.
*/
pts_comp_func_name_t public;
/**
* PTS Component Functional Name Vendor ID
*/
u_int32_t vid;
/**
* PTS Component Functional Name
*/
u_int32_t name;
/**
* PTS Component Functional Name Qualifier
*/
u_int8_t qualifier;
};
METHOD(pts_comp_func_name_t, get_vendor_id, u_int32_t,
private_pts_comp_func_name_t *this)
{
return this->vid;
}
METHOD(pts_comp_func_name_t, get_name, u_int32_t,
private_pts_comp_func_name_t *this)
{
return this->name;
}
METHOD(pts_comp_func_name_t, get_qualifier, u_int8_t,
private_pts_comp_func_name_t *this)
{
return this->qualifier;
}
METHOD(pts_comp_func_name_t, set_qualifier, void,
private_pts_comp_func_name_t *this, u_int8_t qualifier)
{
this->qualifier = qualifier;
}
static bool equals(private_pts_comp_func_name_t *this,
private_pts_comp_func_name_t *other)
{
if (this->vid != other->vid || this->name != other->name)
{
return FALSE;
}
if (this->qualifier == PTS_QUALIFIER_UNKNOWN ||
other->qualifier == PTS_QUALIFIER_UNKNOWN)
{
return TRUE;
}
/* TODO handle qualifier wildcards */
return this->qualifier == other->qualifier;
}
METHOD(pts_comp_func_name_t, clone_, pts_comp_func_name_t*,
private_pts_comp_func_name_t *this)
{
private_pts_comp_func_name_t *clone;
clone = malloc_thing(private_pts_comp_func_name_t);
memcpy(clone, this, sizeof(private_pts_comp_func_name_t));
return &clone->public;
}
METHOD(pts_comp_func_name_t, log_, void,
private_pts_comp_func_name_t *this, char *label)
{
enum_name_t *names, *types;
char flags[8];
int type;
names = imcv_pts_components->get_comp_func_names(imcv_pts_components,
this->vid);
types = imcv_pts_components->get_qualifier_type_names(imcv_pts_components,
this->vid);
type = imcv_pts_components->get_qualifier(imcv_pts_components,
&this->public, flags);
if (names && types)
{
DBG2(DBG_PTS, "%s%N functional component '%N' [%s] '%N'",
label, pen_names, this->vid, names, this->name, flags, types, type);
}
else
{
DBG2(DBG_PTS, "%s0x%06x functional component 0x%08x 0x%02x",
label, this->vid, this->name, this->qualifier);
}
}
METHOD(pts_comp_func_name_t, destroy, void,
private_pts_comp_func_name_t *this)
{
free(this);
}
/**
* See header
*/
pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name,
u_int8_t qualifier)
{
private_pts_comp_func_name_t *this;
INIT(this,
.public = {
.get_vendor_id = _get_vendor_id,
.get_name = _get_name,
.get_qualifier = _get_qualifier,
.set_qualifier = _set_qualifier,
.equals = (bool(*)(pts_comp_func_name_t*,pts_comp_func_name_t*))equals,
.clone = _clone_,
.log = _log_,
.destroy = _destroy,
},
.vid = vid,
.name = name,
.qualifier = qualifier,
);
return &this->public;
}
@@ -0,0 +1,103 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu, 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 pts_comp_func_name pts_comp_func_name
* @{ @ingroup pts
*/
#ifndef PTS_FUNC_COMP_NAME_H_
#define PTS_FUNC_COMP_NAME_H_
typedef struct pts_comp_func_name_t pts_comp_func_name_t;
#include <library.h>
#define PTS_QUALIFIER_UNKNOWN 0x00
#define PTS_QUALIFIER_WILDCARD 0x3F
/**
* PTS Component Functional Name object
*/
struct pts_comp_func_name_t {
/**
* Get the PTS Component Functional Name Vendor ID
*
* @return PTS Component Functional Name Vendor ID
*/
u_int32_t (*get_vendor_id)(pts_comp_func_name_t *this);
/**
* Get the PTS Component Functional Name
*
* @return PTS Component Functional Name
*/
u_int32_t (*get_name)(pts_comp_func_name_t *this);
/**
* Get the PTS Component Functional Name Qualifier
*
* @return PTS Component Functional Name Qualifier
*/
u_int8_t (*get_qualifier)(pts_comp_func_name_t *this);
/**
* Set the PTS Component Functional Name Qualifier
*
* @param qualifier PTS Component Functional Name Qualifier to be set
*/
void (*set_qualifier)(pts_comp_func_name_t *this, u_int8_t qualifier);
/**
* Check to PTS Component Functional Names for equality
*
* @param other Other PTS Component Functional Name
* @return TRUE if equal
*/
bool (*equals)(pts_comp_func_name_t *this, pts_comp_func_name_t *other);
/**
* Clone a PTS Component Functional Name
*
* @return Cloned PTS Component Functional Name
*/
pts_comp_func_name_t* (*clone)(pts_comp_func_name_t *this);
/**
* Write PTS Component Functional Name information to the standard logfile
*
* @param label Label added to log output
*/
void (*log)(pts_comp_func_name_t *this, char *label);
/**
* Destroys a pts_component_t object.
*/
void (*destroy)(pts_comp_func_name_t *this);
};
/**
* Create a PTS Component Functional Name object
*
* @param vid PTS Component Functional Name Vendor ID
* @param name PTS Component Functional Name
* @param qualifier PTS Component Functional Name Qualifier
*/
pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name,
u_int8_t qualifier);
#endif /** PTS_FUNC_COMP_NAME_H_ @}*/
+109
View File
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2011-2012 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 pts_component pts_component
* @{ @ingroup pts
*/
#ifndef PTS_COMPONENT_H_
#define PTS_COMPONENT_H_
typedef struct pts_component_t pts_component_t;
#include "pts/pts.h"
#include "pts/pts_database.h"
#include "pts/pts_file_meas.h"
#include "pts/components/pts_comp_func_name.h"
#include "pts/components/pts_comp_evidence.h"
#include <library.h>
#include <bio/bio_writer.h>
/**
* PTS Functional Component Interface
*/
struct pts_component_t {
/**
* Get the PTS Component Functional Name
*
* @return PTS Component Functional Name
*/
pts_comp_func_name_t* (*get_comp_func_name)(pts_component_t *this);
/**
* Get the PTS Component Evidence Flags
*
* @return PTS Component Functional Name
*/
u_int8_t (*get_evidence_flags)(pts_component_t *this);
/**
* Get the PTS Sub-component Depth
*
* @return PTS Sub-component Depth
*/
u_int32_t (*get_depth)(pts_component_t *this);
/**
* Do evidence measurements on the PTS Functional Component
*
* @param qualifier PTS Component Functional Name Qualifier
* @param pts PTS interface
* @param evidence returns component evidence measureemt
* @param measurements additional file measurements (NULL if not present)
* @return status return code
*/
status_t (*measure)(pts_component_t *this, u_int8_t qualifier, pts_t *pts,
pts_comp_evidence_t** evidence);
/**
* Verify the evidence measurements of the PTS Functional Component
*
* @param qualifier PTS Component Functional Name Qualifier
* @param pts PTS interface
* @param evidence component evidence measurement to be verified
* @return status return code
*/
status_t (*verify)(pts_component_t *this, u_int8_t qualifier, pts_t *pts,
pts_comp_evidence_t *evidence);
/**
* Tell the PTS Functional Component to finalize pending registrations
* and check for missing measurements
*
* @param qualifier PTS Component Functional Name Qualifier
* @param result writer appending concise measurement result
* @return TRUE if finalization successful
*/
bool (*finalize)(pts_component_t *this, u_int8_t qualifier,
bio_writer_t *result);
/**
* Get a new reference to the PTS Functional Component
*
* @return this, with an increased refcount
*/
pts_component_t* (*get_ref)(pts_component_t *this);
/**
* Destroys a pts_component_t object.
*/
void (*destroy)(pts_component_t *this);
};
#endif /** PTS_COMPONENT_H_ @}*/
@@ -0,0 +1,315 @@
/*
* Copyright (C) 2011-2012 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 "pts/components/pts_component_manager.h"
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_pts_component_manager_t private_pts_component_manager_t;
typedef struct vendor_entry_t vendor_entry_t;
typedef struct component_entry_t component_entry_t;
#define PTS_QUALIFIER_SIZE 6
/**
* Vendor-specific namespace information and list of registered components
*/
struct vendor_entry_t {
/**
* Vendor ID
*/
pen_t vendor_id;
/**
* Vendor-specific Component Functional names
*/
enum_name_t *comp_func_names;
/**
* Vendor-specific Qualifier Type names
*/
enum_name_t *qualifier_type_names;
/**
* Vendor-specific Qualifier Flag names
*/
char *qualifier_flag_names;
/**
* Vendor-specific size of Qualfiier Type field
*/
int qualifier_type_size;
/**
* List of vendor-specific registered Functional Components
*/
linked_list_t *components;
};
/**
* Destroy a vendor_entry_t object
*/
static void vendor_entry_destroy(vendor_entry_t *entry)
{
entry->components->destroy_function(entry->components, free);
free(entry);
}
/**
* Creation method for a vendor-specific Functional Component
*/
struct component_entry_t {
/**
* Vendor-Specific Component Functional Name
*/
u_int32_t name;
/**
* Functional Component creation method
*/
pts_component_create_t create;
};
/**
* Private data of a pts_component_manager_t object.
*
*/
struct private_pts_component_manager_t {
/**
* Public pts_component_manager_t interface.
*/
pts_component_manager_t public;
/**
* List of vendor-specific namespaces and registered components
*/
linked_list_t *list;
};
METHOD(pts_component_manager_t, add_vendor, void,
private_pts_component_manager_t *this, pen_t vendor_id,
enum_name_t *comp_func_names, int qualifier_type_size,
char *qualifier_flag_names, enum_name_t *qualifier_type_names)
{
vendor_entry_t *entry;
entry = malloc_thing(vendor_entry_t);
entry->vendor_id = vendor_id;
entry->comp_func_names = comp_func_names;
entry->qualifier_type_size = qualifier_type_size;
entry->qualifier_flag_names = qualifier_flag_names;
entry->qualifier_type_names = qualifier_type_names;
entry->components = linked_list_create();
this->list->insert_last(this->list, entry);
DBG2(DBG_PTS, "added %N functional component namespace",
pen_names, vendor_id);
}
METHOD(pts_component_manager_t, get_comp_func_names, enum_name_t*,
private_pts_component_manager_t *this, pen_t vendor_id)
{
enumerator_t *enumerator;
vendor_entry_t *entry;
enum_name_t *names = NULL;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->vendor_id == vendor_id)
{
names = entry->comp_func_names;
break;
}
}
enumerator->destroy(enumerator);
return names;
}
METHOD(pts_component_manager_t, get_qualifier_type_names, enum_name_t*,
private_pts_component_manager_t *this, pen_t vendor_id)
{
enumerator_t *enumerator;
vendor_entry_t *entry;
enum_name_t *names = NULL;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->vendor_id == vendor_id)
{
names = entry->qualifier_type_names;
break;
}
}
enumerator->destroy(enumerator);
return names;
}
METHOD(pts_component_manager_t, add_component, void,
private_pts_component_manager_t *this, pen_t vendor_id, u_int32_t name,
pts_component_create_t create)
{
enumerator_t *enumerator;
vendor_entry_t *entry;
component_entry_t *component;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->vendor_id == vendor_id)
{
component = malloc_thing(component_entry_t);
component->name = name;
component->create = create;
entry->components->insert_last(entry->components, component);
DBG2(DBG_PTS, "added %N functional component '%N'",
pen_names, vendor_id,
get_comp_func_names(this, vendor_id), name);
}
}
enumerator->destroy(enumerator);
}
METHOD(pts_component_manager_t, remove_vendor, void,
private_pts_component_manager_t *this, pen_t vendor_id)
{
enumerator_t *enumerator;
vendor_entry_t *entry;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->vendor_id == vendor_id)
{
this->list->remove_at(this->list, enumerator);
vendor_entry_destroy(entry);
DBG2(DBG_PTS, "removed %N functional component namespace",
pen_names, vendor_id);
}
}
enumerator->destroy(enumerator);
}
METHOD(pts_component_manager_t, get_qualifier, u_int8_t,
private_pts_component_manager_t *this, pts_comp_func_name_t *name,
char *flags)
{
enumerator_t *enumerator;
vendor_entry_t *entry;
u_int8_t qualifier, size, flag, type = 0;
int i;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->vendor_id == name->get_vendor_id(name))
{
qualifier = name->get_qualifier(name);
size = entry->qualifier_type_size;
/* mask qualifier type field */
type = qualifier & ((1 << size) - 1);
/* determine flags */
size = PTS_QUALIFIER_SIZE - size;
flag = (1 << (PTS_QUALIFIER_SIZE - 1));
if (flags)
{
for (i = 0 ; i < size; i++)
{
flags[i] = (qualifier & flag) ?
entry->qualifier_flag_names[i] : '.';
flag >>= 1;
}
flags[size] = '\0';
}
}
}
enumerator->destroy(enumerator);
return type;
}
METHOD(pts_component_manager_t, create, pts_component_t*,
private_pts_component_manager_t *this,
pts_comp_func_name_t *name, u_int32_t depth, pts_database_t *pts_db)
{
enumerator_t *enumerator, *e2;
vendor_entry_t *entry;
component_entry_t *entry2;
pts_component_t *component = NULL;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->vendor_id == name->get_vendor_id(name))
{
e2 = entry->components->create_enumerator(entry->components);
while (e2->enumerate(e2, &entry2))
{
if (entry2->name == name->get_name(name) && entry2->create)
{
component = entry2->create(depth, pts_db);
break;
}
}
e2->destroy(e2);
break;
}
}
enumerator->destroy(enumerator);
return component;
}
METHOD(pts_component_manager_t, destroy, void,
private_pts_component_manager_t *this)
{
this->list->destroy_function(this->list, (void *)vendor_entry_destroy);
free(this);
}
/**
* See header
*/
pts_component_manager_t *pts_component_manager_create(void)
{
private_pts_component_manager_t *this;
INIT(this,
.public = {
.add_vendor = _add_vendor,
.add_component = _add_component,
.remove_vendor = _remove_vendor,
.get_comp_func_names = _get_comp_func_names,
.get_qualifier_type_names = _get_qualifier_type_names,
.get_qualifier = _get_qualifier,
.create = _create,
.destroy = _destroy,
},
.list = linked_list_create(),
);
return &this->public;
}
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup pts_component_manager pts_component_manager
* @{ @ingroup pts
*/
#ifndef PTS_COMPONENT_MANAGER_H_
#define PTS_COMPONENT_MANAGER_H_
typedef struct pts_component_manager_t pts_component_manager_t;
#include "pts/pts_database.h"
#include "pts/components/pts_component.h"
#include "pts/components/pts_comp_func_name.h"
#include <library.h>
#include <pen/pen.h>
typedef pts_component_t* (*pts_component_create_t)(u_int32_t depth,
pts_database_t *pts_db);
/**
* Manages PTS Functional Components
*/
struct pts_component_manager_t {
/**
* Add vendor-specific functional component names
*
* @param vendor_id Private Enterprise Number (PEN)
* @param comp_func_names Vendor-specific Component Functional names
* @param qualifier_type_size Vendor-specific Qualifier Type size
* @param qualifier_flag_names Vendor-specific Qualifier Flag names
* @param qualifier_type_names Vendor-specific Qualifier Type names
*/
void (*add_vendor)(pts_component_manager_t *this, pen_t vendor_id,
enum_name_t *comp_func_names,
int qualifier_type_size,
char *qualifier_flag_names,
enum_name_t *qualifier_type_names);
/**
* Add vendor-specific functional component
*
* @param vendor_id Private Enterprise Number (PEN)
* @param names Component Functional Name
* @param create Functional Component creation method
*/
void (*add_component)(pts_component_manager_t *this, pen_t vendor_id,
u_int32_t name, pts_component_create_t create);
/**
* Remove vendor-specific components and associated namespace
*
* @param vendor_id Private Enterprise Number (PEN)
*/
void (*remove_vendor)(pts_component_manager_t *this, pen_t vendor_id);
/**
* Return the Functional Component names for a given vendor ID
*
* @param vendor_id Private Enterprise Number (PEN)
* @return Comp. Func. names if found, NULL else
*/
enum_name_t* (*get_comp_func_names)(pts_component_manager_t *this,
pen_t vendor_id);
/**
* Return the Functional Component Qualifier Type names for a given vendor ID
*
* @param vendor_id Private Enterprise Number (PEN)
* @return Qualifier Type names if found, NULL else
*/
enum_name_t* (*get_qualifier_type_names)(pts_component_manager_t *this,
pen_t vendor_id);
/**
* Return the Qualifier Type and Flags
*
* @param name Component Functional Name
* @param flags Qualifier Flags as a string in a char buffer
* @return Qualifier Type
*/
u_int8_t (*get_qualifier)(pts_component_manager_t *this,
pts_comp_func_name_t *name, char *flags);
/**
* Create a PTS Component object from a Functional Component Name object
*
* @param name Component Functional Name
* @param depth Sub-component Depth
* @param pts_db PTS measurement database
* @return Component object if supported, NULL else
*/
pts_component_t* (*create)(pts_component_manager_t *this,
pts_comp_func_name_t *name, u_int32_t depth,
pts_database_t *pts_db);
/**
* Destroys a pts_component_manager_t object.
*/
void (*destroy)(pts_component_manager_t *this);
};
/**
* Create a PA-TNC attribute manager
*/
pts_component_manager_t* pts_component_manager_create(void);
#endif /** PTS_COMPONENT_MANAGER_H_ @}*/
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "tcg_comp_func_name.h"
char pts_tcg_qualifier_flag_names[] = { 'K', 'S' };
ENUM_BEGIN(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_UNKNOWN,
PTS_TCG_QUALIFIER_TYPE_TNC,
"Unknown",
"Trusted Platform",
"Operating System",
"Graphical User Interface",
"Application",
"Networking",
"Library",
"TNC Defined Component"
);
ENUM_NEXT(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL,
PTS_TCG_QUALIFIER_TYPE_ALL,
PTS_TCG_QUALIFIER_TYPE_TNC,
"All Matching Components"
);
ENUM_END(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL);
ENUM(pts_tcg_comp_func_names, PTS_TCG_COMP_FUNC_NAME_IGNORE,
PTS_TCG_COMP_FUNC_NAME_OPT_ROMS,
"Ignore",
"CRTM",
"BIOS",
"Platform Extensions",
"Motherboard Firmware",
"Initial Program Loader",
"Option ROMs"
);
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_tcg_comp_func_name pts_tcg_comp_func_name
* @{ @ingroup pts
*/
#ifndef PTS_TCG_COMP_FUNC_NAME_H_
#define PTS_TCG_COMP_FUNC_NAME_H_
typedef enum pts_tcg_qualifier_type_t pts_tcg_qualifier_type_t;
typedef enum pts_tcg_comp_func_name_t pts_tcp_comp_func_name_t;
#include <library.h>
/**
* PTS Component Functional Name Qualifier Flags for the TCG namespace
* see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
*
* 0 1 2 3 4 5
* +-+-+-+-+-+-+
* |K|S| Type |
* +-+-+-+-+-+-+
*/
#define PTS_TCG_QUALIFIER_FLAG_KERNEL (1<<5)
#define PTS_TCG_QUALIFIER_FLAG_SUB (1<<4)
extern char pts_tcg_qualifier_flag_names[];
/**
* Size of the PTS Component Functional Name Qualifier Type field
*/
#define PTS_TCG_QUALIFIER_TYPE_SIZE 4
/**
* PTS Component Functional Name Qualifier Types for the TCG namespace
* see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum pts_tcg_qualifier_type_t {
/** Unknown */
PTS_TCG_QUALIFIER_TYPE_UNKNOWN = 0x0,
/** Trusted Platform */
PTS_TCG_QUALIFIER_TYPE_TRUSTED = 0x1,
/** Operating System */
PTS_TCG_QUALIFIER_TYPE_OS = 0x2,
/** Graphical User Interface */
PTS_TCG_QUALIFIER_TYPE_GUI = 0x3,
/** Application */
PTS_TCG_QUALIFIER_TYPE_APP = 0x4,
/** Networking */
PTS_TCG_QUALIFIER_TYPE_NET = 0x5,
/** Library */
PTS_TCG_QUALIFIER_TYPE_LIB = 0x6,
/** TNC Defined Component */
PTS_TCG_QUALIFIER_TYPE_TNC = 0x7,
/** All matching Components */
PTS_TCG_QUALIFIER_TYPE_ALL = 0xF,
};
extern enum_name_t *pts_tcg_qualifier_type_names;
/**
* PTS Component Functional Name Binary Enumeration for the TCG namespace
* see section 5.3 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum pts_tcg_comp_func_name_t {
/** Ignore */
PTS_TCG_COMP_FUNC_NAME_IGNORE = 0x0000,
/** CRTM */
PTS_TCG_COMP_FUNC_NAME_CRTM = 0x0001,
/** BIOS */
PTS_TCG_COMP_FUNC_NAME_BIOS = 0x0002,
/** Platform Extensions */
PTS_TCG_COMP_FUNC_NAME_PLATFORM_EXT = 0x0003,
/** Motherboard Firmware */
PTS_TCG_COMP_FUNC_NAME_BOARD = 0x0004,
/** Initial Program Loader */
PTS_TCG_COMP_FUNC_NAME_INIT_LOADER = 0x0005,
/** Option ROMs */
PTS_TCG_COMP_FUNC_NAME_OPT_ROMS = 0x0006,
};
extern enum_name_t *pts_tcg_comp_func_names;
#endif /** PTS_TCG_COMP_FUNC_NAME_H_ @}*/
File diff suppressed because it is too large Load Diff
+315
View File
@@ -0,0 +1,315 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* Copyright (C) 2012-2014 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 pts pts
* @{ @ingroup libpts
*/
#ifndef PTS_H_
#define PTS_H_
typedef struct pts_t pts_t;
#include "pts_error.h"
#include "pts_proto_caps.h"
#include "pts_meas_algo.h"
#include "pts_file_meas.h"
#include "pts_file_meta.h"
#include "pts_dh_group.h"
#include "pts_pcr.h"
#include "pts_req_func_comp_evid.h"
#include "pts_simple_evid_final.h"
#include "components/pts_comp_func_name.h"
#include <library.h>
#include <collections/linked_list.h>
/**
* UTF-8 encoding of the character used to delimiter the filename
*/
#define SOLIDUS_UTF 0x2F
#define REVERSE_SOLIDUS_UTF 0x5C
/**
* PCR indices used for measurements of various functional components
*/
#define PCR_BIOS 0
#define PCR_PLATFORM_EXT 1
#define PCR_MOTHERBOARD 1
#define PCR_OPTION_ROMS 2
#define PCR_IPL 4
#define PCR_TBOOT_POLICY 17
#define PCR_TBOOT_MLE 18
#define PCR_TGRUB_MBR_STAGE1 4
#define PCR_TGRUB_STAGE2_PART1 8
#define PCR_TGRUB_STAGE2_PART2 9
#define PCR_TGRUB_CMD_LINE_ARGS 12
#define PCR_TGRUB_CHECKFILE 13
#define PCR_TGRUB_LOADED_FILES 14
#define PCR_DEBUG 16
/**
* Length of the generated nonce used for calculation of shared secret
*/
#define ASSESSMENT_SECRET_LEN 20
/**
* Length of the TPM_QUOTE_INFO structure, TPM Spec 1.2
*/
#define TPM_QUOTE_INFO_LEN 48
/**
* Hashing algorithm used by tboot and trustedGRUB
*/
#define TRUSTED_HASH_ALGO PTS_MEAS_ALGO_SHA1
/**
* Class implementing the TCG Platform Trust Service (PTS)
*
*/
struct pts_t {
/**
* Get PTS Protocol Capabilities
*
* @return Protocol capabilities flags
*/
pts_proto_caps_flag_t (*get_proto_caps)(pts_t *this);
/**
* Set PTS Protocol Capabilities
*
* @param flags Protocol capabilities flags
*/
void (*set_proto_caps)(pts_t *this, pts_proto_caps_flag_t flags);
/**
* Get PTS Measurement Algorithm
*
* @return PTS measurement algorithm
*/
pts_meas_algorithms_t (*get_meas_algorithm)(pts_t *this);
/**
* Set PTS Measurement Algorithm
*
* @param algorithm PTS measurement algorithm
*/
void (*set_meas_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm);
/**
* Get DH Hash Algorithm
*
* @return DH hash algorithm
*/
pts_meas_algorithms_t (*get_dh_hash_algorithm)(pts_t *this);
/**
* Set DH Hash Algorithm
*
* @param algorithm DH hash algorithm
*/
void (*set_dh_hash_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm);
/**
* Create PTS Diffie-Hellman object and nonce
*
* @param group PTS DH group
* @param nonce_len Nonce length
* @return TRUE if creation was successful
*
*/
bool (*create_dh_nonce)(pts_t *this, pts_dh_group_t group, int nonce_len);
/**
* Get my Diffie-Hellman public value
*
* @param value My public DH value
* @param nonce My DH nonce
*/
void (*get_my_public_value)(pts_t *this, chunk_t *value, chunk_t *nonce);
/**
* Set peer Diffie.Hellman public value
*
* @param value Peer public DH value
* @param nonce Peer DH nonce
*/
void (*set_peer_public_value) (pts_t *this, chunk_t value, chunk_t nonce);
/**
* Calculates assessment secret to be used for TPM Quote as ExternalData
*
* @return TRUE unless both DH public values
* and nonces are set
*/
bool (*calculate_secret) (pts_t *this);
/**
* Get primary key of platform entry in database
*
* @return Platform and OS info
*/
int (*get_platform_id)(pts_t *this);
/**
* Set primary key of platform entry in database
*
* @param pid Primary key of platform entry in database
*/
void (*set_platform_id)(pts_t *this, int pid);
/**
* Get TPM 1.2 Version Info
*
* @param info chunk containing a TPM_CAP_VERSION_INFO struct
* @return TRUE if TPM Version Info available
*/
bool (*get_tpm_version_info)(pts_t *this, chunk_t *info);
/**
* Set TPM 1.2 Version Info
*
* @param info chunk containing a TPM_CAP_VERSION_INFO struct
*/
void (*set_tpm_version_info)(pts_t *this, chunk_t info);
/**
* Get Attestation Identity Certificate or Public Key
*
* @return AIK Certificate or Public Key
*/
certificate_t* (*get_aik)(pts_t *this);
/**
* Set Attestation Identity Certificate or Public Key
*
* @param aik AIK Certificate or Public Key
* @param aik_id Primary key referencing AIK in database
*/
void (*set_aik)(pts_t *this, certificate_t *aik, int aik_id);
/**
* Get primary key referencing AIK in database
*
* @return Primary key referencing AIK in database
*/
int (*get_aik_id)(pts_t *this);
/**
* Check whether path is valid file/directory on filesystem
*
* @param path Absolute path
* @param error_code Output variable for PTS error code
* @return TRUE if path is valid or file/directory
* doesn't exist or path is invalid
* FALSE if local error occurred within stat function
*/
bool (*is_path_valid)(pts_t *this, char *path, pts_error_code_t *error_code);
/**
* Obtain file metadata
*
* @param pathname Absolute pathname of file/directory
* @param is_dir TRUE if directory contents are requested
* @return PTS File Metadata or NULL if FAILED
*/
pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir);
/**
* Reads given PCR value and returns it
* Expects owner secret to be WELL_KNOWN_SECRET
*
* @param pcr_num Number of PCR to read
* @param pcr_value Chunk to save pcr read output
* @return NULL in case of TSS error, PCR value otherwise
*/
bool (*read_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value);
/**
* Extends given PCR with given value
* Expects owner secret to be WELL_KNOWN_SECRET
*
* @param pcr_num Number of PCR to extend
* @param input Value to extend
* @param output Chunk to save PCR value after extension
* @return FALSE in case of TSS error, TRUE otherwise
*/
bool (*extend_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t input,
chunk_t *output);
/**
* Quote over PCR's
* Expects owner and SRK secret to be WELL_KNOWN_SECRET and no password set for AIK
*
* @param use_quote2 Version of the Quote function to be used
* @param pcr_comp Chunk to save PCR composite structure
* @param quote_sig Chunk to save quote operation output
* without external data (anti-replay protection)
* @return FALSE in case of TSS error, TRUE otherwise
*/
bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp,
chunk_t *quote_sig);
/**
* Get the shadow PCR set
*
* @return shadow PCR set
*/
pts_pcr_t* (*get_pcrs)(pts_t *this);
/**
* Constructs and returns TPM Quote Info structure expected from IMC
*
* @param use_quote2 Version of the TPM_QUOTE_INFO to be constructed
* @param use_ver_info Version info is concatenated to TPM_QUOTE_INFO2
* @param comp_hash_algo Composite Hash Algorithm
* @param pcr_comp Output variable to store PCR Composite
* @param quote_info Output variable to store TPM Quote Info
* @return FALSE in case of any error, TRUE otherwise
*/
bool (*get_quote_info)(pts_t *this, bool use_quote2, bool ver_info_included,
pts_meas_algorithms_t comp_hash_algo,
chunk_t *pcr_comp, chunk_t *quote_info);
/**
* Constructs and returns PCR Quote Digest structure expected from IMC
*
* @param data Calculated TPM Quote Digest
* @param signature TPM Quote Signature received from IMC
* @return FALSE if signature is not verified
*/
bool (*verify_quote_signature)(pts_t *this, chunk_t data, chunk_t signature);
/**
* Destroys a pts_t object.
*/
void (*destroy)(pts_t *this);
};
/**
* Creates an pts_t object
*
* @param is_imc TRUE if running on an IMC
*/
pts_t* pts_create(bool is_imc);
#endif /** PTS_H_ @}*/
+136
View File
@@ -0,0 +1,136 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "pts_creds.h"
#include <utils/debug.h>
#include <credentials/certificates/x509.h>
#include <credentials/sets/mem_cred.h>
#include <sys/stat.h>
typedef struct private_pts_creds_t private_pts_creds_t;
/**
* Private data of a pts_creds_t object.
*
*/
struct private_pts_creds_t {
/**
* Public pts_creds_t interface.
*/
pts_creds_t public;
/**
* Credential set
*/
mem_cred_t *creds;
};
METHOD(pts_creds_t, get_set, credential_set_t*,
private_pts_creds_t *this)
{
return &this->creds->set;
}
METHOD(pts_creds_t, destroy, void,
private_pts_creds_t *this)
{
this->creds->destroy(this->creds);
free(this);
}
/**
* Load trusted PTS CA certificates from a directory
*/
static void load_cacerts(private_pts_creds_t *this, char *path)
{
enumerator_t *enumerator;
struct stat st;
char *file;
DBG1(DBG_PTS, "loading PTS ca certificates from '%s'", path);
enumerator = enumerator_create_directory(path);
if (!enumerator)
{
return;
}
while (enumerator->enumerate(enumerator, NULL, &file, &st))
{
certificate_t *cert;
if (!S_ISREG(st.st_mode))
{
/* skip special file */
continue;
}
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, file, BUILD_END);
if (cert)
{
x509_t *x509 = (x509_t*)cert;
if (!(x509->get_flags(x509) & X509_CA))
{
DBG1(DBG_PTS, " ca certificate \"%Y\" lacks ca basic constraint"
", discarded", cert->get_subject(cert));
cert->destroy(cert);
}
else
{
DBG1(DBG_PTS, " loaded ca certificate \"%Y\" from '%s'",
cert->get_subject(cert), file);
this->creds->add_cert(this->creds, TRUE, cert);
}
}
else
{
DBG1(DBG_PTS, " loading ca certificate from '%s' failed", file);
}
}
enumerator->destroy(enumerator);
}
/**
* See header
*/
pts_creds_t *pts_creds_create(char *path)
{
private_pts_creds_t *this;
if (!path)
{
DBG1(DBG_PTS, "no PTS cacerts directory defined");
return NULL;
}
INIT(this,
.public = {
.get_set = _get_set,
.destroy = _destroy,
},
.creds = mem_cred_create(),
);
load_cacerts(this, path);
return &this->public;
}
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup pts_creds pts_creds
* @{ @ingroup pts
*/
#ifndef PTS_CREDS_H_
#define PTS_CREDS_H_
typedef struct pts_creds_t pts_creds_t;
#include <library.h>
#include <credentials/credential_set.h>
/**
* Class implementing a PTS credentials set
*/
struct pts_creds_t {
/**
* Get the credential set
*
* @return credential set
*/
credential_set_t* (*get_set)(pts_creds_t *this);
/**
* Destroys a pts_creds_t object.
*/
void (*destroy)(pts_creds_t *this);
};
/**
* Creates an pts_creds_t object
*
* @param path path to the PTS cacerts directory
*/
pts_creds_t* pts_creds_create(char *path);
#endif /** PTS_CREDS_H_ @}*/
+432
View File
@@ -0,0 +1,432 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2012-2014 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.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <libgen.h>
#include "pts_database.h"
#include <utils/debug.h>
#include <crypto/hashers/hasher.h>
typedef struct private_pts_database_t private_pts_database_t;
/**
* Private data of a pts_database_t object.
*
*/
struct private_pts_database_t {
/**
* Public pts_database_t interface.
*/
pts_database_t public;
/**
* database instance
*/
database_t *db;
};
METHOD(pts_database_t, get_pathname, char*,
private_pts_database_t *this, bool is_dir, int id)
{
enumerator_t *e;
char *path, *name, *sep, *pathname = NULL;
if (is_dir)
{
e = this->db->query(this->db,
"SELECT path FROM directories WHERE id = ?",
DB_INT, id, DB_TEXT);
if (!e || !e->enumerate(e, &path))
{
pathname = NULL;
}
else
{
pathname = strdup(path);
}
}
else
{
e = this->db->query(this->db,
"SELECT d.path, f.name FROM files AS f "
"JOIN directories AS d ON d.id = f.dir WHERE f.id = ?",
DB_INT, id, DB_TEXT, DB_TEXT);
if (e && e->enumerate(e, &path, &name))
{
if (path[0] == '/')
{ /* Unix style absolute path */
sep = "/";
}
else
{ /* Windows absolute path */
sep = "\\";
}
if (asprintf(&pathname, "%s%s%s",
path, streq(path, "/") ? "" : sep, name) == -1)
{
pathname = NULL;
}
}
}
DESTROY_IF(e);
return pathname;
}
METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
bool is_dir, int id)
{
enumerator_t *e;
if (is_dir)
{
e = this->db->query(this->db,
"SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"JOIN directories as d ON d.id = f.dir "
"WHERE fh.product = ? AND fh.algo = ? AND d.id = ? "
"ORDER BY f.name",
DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB);
}
else
{
e = this->db->query(this->db,
"SELECT f.id, f.name, fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?",
DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB);
}
return e;
}
METHOD(pts_database_t, add_file_measurement, status_t,
private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
chunk_t measurement, char *filename, bool is_dir, int id)
{
enumerator_t *e;
char *name;
chunk_t hash_value;
int hash_id, fid;
status_t status = SUCCESS;
if (is_dir)
{
/* does filename entry already exist? */
e = this->db->query(this->db,
"SELECT id FROM files WHERE name = ? AND dir = ?",
DB_TEXT, filename, DB_INT, id, DB_INT);
if (!e)
{
return FAILED;
}
if (!e->enumerate(e, &fid))
{
/* create filename entry */
if (this->db->execute(this->db, &fid,
"INSERT INTO files (name, dir) VALUES (?, ?)",
DB_TEXT, filename, DB_INT, id) != 1)
{
DBG1(DBG_PTS, "could not insert filename into database");
status = FAILED;
}
}
e->destroy(e);
}
else
{
fid = id;
/* verify filename */
e = this->db->query(this->db,
"SELECT name FROM files WHERE id = ?", DB_INT, fid, DB_TEXT);
if (!e)
{
return FAILED;
}
if (!e->enumerate(e, &name) || !streq(name, filename))
{
DBG1(DBG_PTS, "filename of reference measurement does not match");
status = FAILED;
}
e->destroy(e);
}
if (status != SUCCESS)
{
return status;
}
/* does hash measurement value already exist? */
e = this->db->query(this->db,
"SELECT fh.id, fh.hash FROM file_hashes AS fh "
"WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?",
DB_INT, pid, DB_INT, algo, DB_INT, fid, DB_INT, DB_BLOB);
if (!e)
{
return FAILED;
}
if (e->enumerate(e, &hash_id, &hash_value))
{
if (!chunk_equals(measurement, hash_value))
{
/* update hash measurement value */
if (this->db->execute(this->db, &hash_id,
"UPDATE file_hashes SET hash = ? WHERE id = ?",
DB_BLOB, measurement, DB_INT, hash_id) != 1)
{
status = FAILED;
}
}
}
else
{
/* insert hash measurement value */
if (this->db->execute(this->db, &hash_id,
"INSERT INTO file_hashes (file, product, algo, hash) "
"VALUES (?, ?, ?, ?)", DB_INT, fid, DB_INT, pid,
DB_INT, algo, DB_BLOB, measurement) != 1)
{
status = FAILED;
}
}
e->destroy(e);
return status;
}
METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
char *filename)
{
enumerator_t *e;
char *dir, *file;
if (strlen(filename) < 1)
{
return NULL;
}
/* separate filename into directory and basename components */
dir = path_dirname(filename);
file = path_basename(filename);
if (*dir == '.')
{ /* relative pathname */
e = this->db->query(this->db,
"SELECT fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"WHERE fh.product = ? AND f.name = ? AND fh.algo = ?",
DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_BLOB);
}
else
{ /* absolute pathname */
int did;
/* find directory entry first */
e = this->db->query(this->db,
"SELECT id FROM directories WHERE path = ?",
DB_TEXT, dir, DB_INT);
if (!e || !e->enumerate(e, &did))
{
goto err;
}
e->destroy(e);
e = this->db->query(this->db,
"SELECT fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON f.id = fh.file "
"WHERE fh.product = ? AND f.dir = ? AND f.name = ? AND fh.algo = ?",
DB_INT, pid, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_BLOB);
}
err:
free(file);
free(dir);
return e;
}
METHOD(pts_database_t, check_comp_measurement, status_t,
private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
int seq_no, int pcr, pts_meas_algorithms_t algo)
{
enumerator_t *e;
chunk_t hash;
status_t status = NOT_FOUND;
e = this->db->query(this->db,
"SELECT hash FROM component_hashes "
"WHERE component = ? AND key = ? "
"AND seq_no = ? AND pcr = ? AND algo = ? ",
DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no,
DB_INT, pcr, DB_INT, algo, DB_BLOB);
if (!e)
{
DBG1(DBG_PTS, "no database query enumerator returned");
return FAILED;
}
while (e->enumerate(e, &hash))
{
if (chunk_equals(hash, measurement))
{
status = SUCCESS;
break;
}
else
{
DBG1(DBG_PTS, "PCR %2d no matching component measurement #%d "
"found in database", pcr, seq_no);
DBG1(DBG_PTS, " expected: %#B", &hash);
DBG1(DBG_PTS, " received: %#B", &measurement);
status = VERIFY_ERROR;
break;
}
}
e->destroy(e);
if (status == NOT_FOUND)
{
DBG1(DBG_PTS, "PCR %2d no measurement #%d "
"found in database", pcr, seq_no);
}
return status;
}
METHOD(pts_database_t, insert_comp_measurement, status_t,
private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
int seq_no, int pcr, pts_meas_algorithms_t algo)
{
int id;
if (this->db->execute(this->db, &id,
"INSERT INTO component_hashes "
"(component, key, seq_no, pcr, algo, hash) "
"VALUES (?, ?, ?, ?, ?, ?)",
DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, DB_INT, pcr,
DB_INT, algo, DB_BLOB, measurement) == 1)
{
return SUCCESS;
}
DBG1(DBG_PTS, "could not insert component measurement into database");
return FAILED;
}
METHOD(pts_database_t, delete_comp_measurements, int,
private_pts_database_t *this, int cid, int aik_id)
{
return this->db->execute(this->db, NULL,
"DELETE FROM component_hashes "
"WHERE component = ? AND key = ?",
DB_INT, cid, DB_INT, aik_id);
}
METHOD(pts_database_t, get_comp_measurement_count, status_t,
private_pts_database_t *this, pts_comp_func_name_t *comp_name,
int aik_id, pts_meas_algorithms_t algo, int *cid, int *count)
{
enumerator_t *e;
status_t status = SUCCESS;
/* Initialize count */
*count = 0;
/* Get the primary key of the Component Functional Name */
e = this->db->query(this->db,
"SELECT id FROM components "
" WHERE vendor_id = ? AND name = ? AND qualifier = ?",
DB_INT, comp_name->get_vendor_id(comp_name),
DB_INT, comp_name->get_name(comp_name),
DB_INT, comp_name->get_qualifier(comp_name),
DB_INT);
if (!e)
{
DBG1(DBG_PTS, "no database query enumerator returned");
return FAILED;
}
if (!e->enumerate(e, cid))
{
DBG1(DBG_PTS, "component functional name not found in database");
e->destroy(e);
return FAILED;
}
e->destroy(e);
/* Get the number of stored measurements for a given AIK and component */
e = this->db->query(this->db,
"SELECT COUNT(*) FROM component_hashes AS ch "
"WHERE component = ? AND key = ? AND algo = ?",
DB_INT, *cid, DB_INT, aik_id, DB_INT, algo, DB_INT);
if (!e)
{
DBG1(DBG_PTS, "no database query enumerator returned");
return FAILED;
}
if (!e->enumerate(e, count))
{
DBG1(DBG_PTS, "no component measurement count returned from database");
status = FAILED;
}
e->destroy(e);
return status;
}
METHOD(pts_database_t, destroy, void,
private_pts_database_t *this)
{
free(this);
}
/**
* See header
*/
pts_database_t *pts_database_create(imv_database_t *imv_db)
{
private_pts_database_t *this;
if (!imv_db)
{
return NULL;
}
INIT(this,
.public = {
.get_pathname = _get_pathname,
.create_file_hash_enumerator = _create_file_hash_enumerator,
.add_file_measurement = _add_file_measurement,
.create_file_meas_enumerator = _create_file_meas_enumerator,
.check_comp_measurement = _check_comp_measurement,
.insert_comp_measurement = _insert_comp_measurement,
.delete_comp_measurements = _delete_comp_measurements,
.get_comp_measurement_count = _get_comp_measurement_count,
.destroy = _destroy,
},
.db = imv_db->get_database(imv_db),
);
return &this->public;
}
+155
View File
@@ -0,0 +1,155 @@
/*
* Copyright (C) 2011-2014 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 pts_database pts_database
* @{ @ingroup pts
*/
#ifndef PTS_DATABASE_H_
#define PTS_DATABASE_H_
typedef struct pts_database_t pts_database_t;
#include "pts_meas_algo.h"
#include "components/pts_comp_func_name.h"
#include <imv/imv_database.h>
#include <library.h>
/**
* Class implementing the PTS File Measurement database
*
*/
struct pts_database_t {
/**
* Get absolute pathname for file or directory measurement
*
* @param is_dir TRUE if dir, FALSE if file
* @param id Primary key into directories or files table
* @return Absolute pathname as a text string
*/
char* (*get_pathname)(pts_database_t *this, bool is_dir, int id);
/**
* Get stored measurement hash for single file or directory entries
*
* @param pid Primary key of software product in database
* @param algo Hash algorithm used for measurement
* @param is_dir TRUE if directory was measured
* @param id Primary key of measured file/directory
* @return Enumerator over all matching measurement hashes
*/
enumerator_t* (*create_file_hash_enumerator)(pts_database_t *this,
int pid, pts_meas_algorithms_t algo,
bool is_dir, int id);
/**
* Add PTS file measurement reference value
*
* @param pid Primary key of software product in database
* @param algo File measurement hash algorithm used
* @param measurement File measurement hash
* @param filename Optional name of the file to be checked
* @param is_dir TRUE if part of directory measurement
* @param id Primary key into direcories/files table
* @return Status
*/
status_t (*add_file_measurement)(pts_database_t *this, int pid,
pts_meas_algorithms_t algo,
chunk_t measurement, char *filename,
bool is_dir, int id);
/**
* Get PTS measurement[s] for a given filename stored in database
*
* @param pid Primary key of software product in database
* @param algo File measurement hash algorithm used
* @param filename Name of the file to be checked
* @return Enumerator over all matching measurement hashes
*/
enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this, int pid,
pts_meas_algorithms_t algo,
char *filename);
/**
* Check a functional component measurement against value stored in database
*
* @param measurement measurement hash
* @param cid Primary key of Component Functional Name entry
* @param aik_id Primary key of AIK entry in database
* @param seq_no Measurement sequence number
* @param prc Number of the PCR the measurement was extended into
* @param algo Hash algorithm used for measurement
* @return SUCCESS if check was successful
*/
status_t (*check_comp_measurement)(pts_database_t *this, chunk_t measurement,
int cid, int aik_id, int seq_no, int pcr,
pts_meas_algorithms_t algo);
/**
* Insert a functional component measurement into the database
*
* @param measurement Measurement hash
* @param cid Primary key of Component Functional Name entry
* @param aik_id Primary key of AIK entry in database
* @param seq_no Measurement sequence number
* @param prc Number of the PCR the measurement was extended into
* @param algo Hash algorithm used for measurement
* @return SUCCESS if INSERT was successful
*/
status_t (*insert_comp_measurement)(pts_database_t *this, chunk_t measurement,
int cid, int aik_id, int seq_no, int pcr,
pts_meas_algorithms_t algo);
/**
* Delete functional component measurements from the database
*
* @param cid Primary key of Component Functional Name entry
* @param aik_id Primary key of AIK entry in database
* @return number of deleted measurement entries
*/
int (*delete_comp_measurements)(pts_database_t *this, int cid, int aik_id);
/**
* Get the number of measurements for a functional component and AIK
*
* @param comp_name Component Functional Name
* @param aik_id Primary key of AIK entry in database
* @param algo Hash algorithm used for measurement
* @param cid Primary key of Component Functional Name entry
* @param count measurement count
* @return SUCCESS if COUNT was successful
*/
status_t (*get_comp_measurement_count)(pts_database_t *this,
pts_comp_func_name_t *comp_name, int aik_id,
pts_meas_algorithms_t algo, int *cid, int *count);
/**
* Destroys a pts_database_t object.
*/
void (*destroy)(pts_database_t *this);
};
/**
* Creates an pts_database_t object
*
* @param imv_db Already attached IMV database
*/
pts_database_t* pts_database_create(imv_database_t *imv_db);
#endif /** PTS_DATABASE_H_ @}*/
+184
View File
@@ -0,0 +1,184 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 "pts_dh_group.h"
#include <utils/debug.h>
/**
* Described in header.
*/
bool pts_dh_group_probe(pts_dh_group_t *dh_groups, bool mandatory_dh_groups)
{
enumerator_t *enumerator;
diffie_hellman_group_t dh_group;
const char *plugin_name;
char format1[] = " %s PTS DH group %N[%s] available";
char format2[] = " %s PTS DH group %N not available";
*dh_groups = PTS_DH_GROUP_NONE;
enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &dh_group, &plugin_name))
{
if (dh_group == MODP_1024_BIT)
{
*dh_groups |= PTS_DH_GROUP_IKE2;
DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
dh_group, plugin_name);
}
else if (dh_group == MODP_1536_BIT)
{
*dh_groups |= PTS_DH_GROUP_IKE5;
DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
dh_group, plugin_name);
}
else if (dh_group == MODP_2048_BIT)
{
*dh_groups |= PTS_DH_GROUP_IKE14;
DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
dh_group, plugin_name);
}
else if (dh_group == ECP_256_BIT)
{
*dh_groups |= PTS_DH_GROUP_IKE19;
DBG2(DBG_PTS, format1, "mandatory", diffie_hellman_group_names,
dh_group, plugin_name);
}
else if (dh_group == ECP_384_BIT)
{
*dh_groups |= PTS_DH_GROUP_IKE20;
DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names,
dh_group, plugin_name);
}
}
enumerator->destroy(enumerator);
if (*dh_groups & PTS_DH_GROUP_IKE19)
{
/* mandatory PTS DH group is available */
return TRUE;
}
if (*dh_groups == PTS_DH_GROUP_NONE)
{
DBG1(DBG_PTS, "no PTS DH group available");
return FALSE;
}
if (mandatory_dh_groups)
{
DBG1(DBG_PTS, format2, "mandatory", diffie_hellman_group_names,
ECP_256_BIT);
return FALSE;
}
/* at least one optional PTS DH group is available */
return TRUE;
}
/**
* Described in header.
*/
bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups)
{
if (strcaseeq(dh_group, "ecp384"))
{
/* nothing to update, all groups are supported */
return TRUE;
}
if (strcaseeq(dh_group, "ecp256"))
{
/* remove DH group 20 */
*dh_groups &= ~PTS_DH_GROUP_IKE20;
return TRUE;
}
if (strcaseeq(dh_group, "modp2048"))
{
/* remove DH groups 19 and 20 */
*dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19);
return TRUE;
}
if (strcaseeq(dh_group, "modp1536"))
{
/* remove DH groups 14, 19 and 20 */
*dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 |
PTS_DH_GROUP_IKE14);
return TRUE;
}
if (strcaseeq(dh_group, "modp1024"))
{
/* remove DH groups 5, 14, 19 and 20 */
*dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 |
PTS_DH_GROUP_IKE14 | PTS_DH_GROUP_IKE5);
return TRUE;
}
DBG1(DBG_PTS, "unknown DH group '%s' configured", dh_group);
return FALSE;
}
/**
* Described in header.
*/
pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_dh_groups,
pts_dh_group_t offered_dh_groups)
{
if ((supported_dh_groups & PTS_DH_GROUP_IKE20) &&
(offered_dh_groups & PTS_DH_GROUP_IKE20))
{
return PTS_DH_GROUP_IKE20;
}
if ((supported_dh_groups & PTS_DH_GROUP_IKE19) &&
(offered_dh_groups & PTS_DH_GROUP_IKE19))
{
return PTS_DH_GROUP_IKE19;
}
if ((supported_dh_groups & PTS_DH_GROUP_IKE14) &&
(offered_dh_groups & PTS_DH_GROUP_IKE14))
{
return PTS_DH_GROUP_IKE14;
}
if ((supported_dh_groups & PTS_DH_GROUP_IKE5) &&
(offered_dh_groups & PTS_DH_GROUP_IKE5))
{
return PTS_DH_GROUP_IKE5;
}
if ((supported_dh_groups & PTS_DH_GROUP_IKE2) &&
(offered_dh_groups & PTS_DH_GROUP_IKE2))
{
return PTS_DH_GROUP_IKE2;
}
return PTS_DH_GROUP_NONE;
}
/**
* Described in header.
*/
diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group)
{
switch (dh_group)
{
case PTS_DH_GROUP_IKE2:
return MODP_1024_BIT;
case PTS_DH_GROUP_IKE5:
return MODP_1536_BIT;
case PTS_DH_GROUP_IKE14:
return MODP_2048_BIT;
case PTS_DH_GROUP_IKE19:
return ECP_256_BIT;
case PTS_DH_GROUP_IKE20:
return ECP_384_BIT;
default:
return MODP_NONE;
}
}
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_dh_group pts_dh_group
* @{ @ingroup pts
*/
#ifndef PTS_DH_GROUP_H_
#define PTS_DH_GROUP_H_
#include <library.h>
#include <crypto/diffie_hellman.h>
typedef enum pts_dh_group_t pts_dh_group_t;
/**
* PTS Diffie Hellman Group Values
*/
enum pts_dh_group_t {
/** No DH Group */
PTS_DH_GROUP_NONE = 0,
/** IKE Group 2 */
PTS_DH_GROUP_IKE2 = (1<<15),
/** IKE Group 5 */
PTS_DH_GROUP_IKE5 = (1<<14),
/** IKE Group 14 */
PTS_DH_GROUP_IKE14 = (1<<13),
/** IKE Group 19 */
PTS_DH_GROUP_IKE19 = (1<<12),
/** IKE Group 20 */
PTS_DH_GROUP_IKE20 = (1<<11),
};
/**
* Diffie-Hellman Group Values
* see section 3.8.6 of PTS Protocol: Binding to TNC IF-M Specification
*
* 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |1|2|3|4|5|R|R|R|R|R|R|R|R|R|R|R|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
/**
* Probe available PTS Diffie-Hellman groups
*
* @param dh_groups returns set of available DH groups
* @param mandatory_dh_groups if TRUE enforce mandatory PTS DH groups
* @return TRUE if mandatory DH groups are available
* or at least one optional DH group if
* mandatory_dh_groups is set to FALSE.
*/
bool pts_dh_group_probe(pts_dh_group_t *dh_groups, bool mandatory_dh_groups);
/**
* Update supported Diffie-Hellman groups according to configuration
*
* modp1024: PTS_DH_GROUP_IKE2
* modp1536: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5
* modp2048: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14
* ecp256: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
* PTS_DH_GROUP_IKE19
* ecp384: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
* PTS_DH_GROUP_IKE19 | PTS_DH_GROUP_IKE20
*
* The PTS-IMC is expected to select the strongest supported group
*
* @param dh_group configured DH group
* @param dh_groups returns set of available DH groups
*/
bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups);
/**
* Select the strongest supported Diffie-Hellman group
* among a set of offered DH groups
*
* @param supported_groups set of supported DH groups
* @param offered_groups set of offered DH groups
* @return selected DH group
*/
pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_groups,
pts_dh_group_t offered_groups);
/**
* Convert pts_dh_group_t to diffie_hellman_group_t
*
* @param dh_group PTS DH group type
* @return IKE DH group type
*/
diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group);
#endif /** PTS_DH_GROUP_H_ @}*/
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 "pts_error.h"
#include <bio/bio_writer.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
ENUM(pts_error_code_names, TCG_PTS_RESERVED_ERROR, TCG_PTS_UNABLE_DET_PCR,
"Reserved Error",
"Hash Algorithm Not Supported",
"Invalid Path",
"File Not Found",
"Registry Not Supported",
"Registry Key Not Found",
"D-H Group Not Supported",
"DH-PN Nonce Not Acceptable",
"Invalid Functional Name Family",
"TPM Version Information Unavailable",
"Invalid File Pathname Delimiter",
"PTS Operation Not Supported",
"Unable To Update Reference Manifest",
"Unable To Perform Local Validation",
"Unable To Collect Current Evidence",
"Unable To Determine Transitive Trust Chain",
"Unable To Determine PCR"
);
/**
* Described in header.
*/
pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms)
{
bio_writer_t *writer;
chunk_t msg_info;
pa_tnc_attr_t *attr;
pen_type_t error_code = { PEN_TCG, TCG_PTS_HASH_ALG_NOT_SUPPORTED };
writer = bio_writer_create(4);
writer->write_uint16(writer, 0x0000);
writer->write_uint16(writer, algorithms);
msg_info = writer->get_buf(writer);
attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
}
/**
* Described in header.
*/
pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups)
{
bio_writer_t *writer;
chunk_t msg_info;
pa_tnc_attr_t *attr;
pen_type_t error_code = { PEN_TCG, TCG_PTS_DH_GRPS_NOT_SUPPORTED };
writer = bio_writer_create(4);
writer->write_uint16(writer, 0x0000);
writer->write_uint16(writer, dh_groups);
msg_info = writer->get_buf(writer);
attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
}
/**
* Described in header.
*/
pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len)
{
bio_writer_t *writer;
chunk_t msg_info;
pa_tnc_attr_t *attr;
pen_type_t error_code = { PEN_TCG, TCG_PTS_BAD_NONCE_LENGTH };
writer = bio_writer_create(4);
writer->write_uint16(writer, min_nonce_len);
writer->write_uint16(writer, max_nonce_len);
msg_info = writer->get_buf(writer);
attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
}
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_error pts_error
* @{ @ingroup pts
*/
#ifndef PTS_ERROR_H_
#define PTS_ERROR_H_
typedef enum pts_error_code_t pts_error_code_t;
#include "pts_meas_algo.h"
#include "pts_dh_group.h"
#include "pa_tnc/pa_tnc_attr.h"
#include <library.h>
#define PTS_MIN_NONCE_LEN 17
#define PTS_MAX_NONCE_LEN 0xffff
/**
* PTS Attestation Error Codes
* see section 3.14.2 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum pts_error_code_t {
TCG_PTS_RESERVED_ERROR = 0,
TCG_PTS_HASH_ALG_NOT_SUPPORTED = 1,
TCG_PTS_INVALID_PATH = 2,
TCG_PTS_FILE_NOT_FOUND = 3,
TCG_PTS_REG_NOT_SUPPORTED = 4,
TCG_PTS_REG_KEY_NOT_FOUND = 5,
TCG_PTS_DH_GRPS_NOT_SUPPORTED = 6,
TCG_PTS_BAD_NONCE_LENGTH = 7,
TCG_PTS_INVALID_NAME_FAM = 8,
TCG_PTS_TPM_VERS_NOT_SUPPORTED = 9,
TCG_PTS_INVALID_DELIMITER = 10,
TCG_PTS_OPERATION_NOT_SUPPORTED = 11,
TCG_PTS_RM_ERROR = 12,
TCG_PTS_UNABLE_LOCAL_VAL = 13,
TCG_PTS_UNABLE_CUR_EVID = 14,
TCG_PTS_UNABLE_DET_TTC = 15,
TCG_PTS_UNABLE_DET_PCR = 16,
};
/**
* enum name for pts_error_code_t.
*/
extern enum_name_t *pts_error_code_names;
/**
* Creates a PTS Hash Algorithm Not Supported Error Attribute
* see section 4.2.2 of PTS Protocol: Binding to TNC IF-M Specification
*
* @param algorithms supported measurement hash algorithms
*/
pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms);
/**
* Creates a PTS DH Group Not Supported Error Attribute
* see section 4.2.4 of PTS Protocol: Binding to TNC IF-M Specification
*
* @param dh_groups supported DH groups
*/
pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups);
/**
* Creates a PTS DH PN Nonce Not Supported Error Attribute
* see section 4.2.5 of PTS Protocol: Binding to TNC IF-M Specification
*
* @param min_nonce_len minimum nonce length
* @param max_nonce_len maximum nonce length
*/
pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len);
#endif /** PTS_ERROR_H_ @}*/
+414
View File
@@ -0,0 +1,414 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* Copyright (C) 2014 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 "pts_file_meas.h"
#include <collections/linked_list.h>
#include <utils/debug.h>
#include <sys/stat.h>
#include <libgen.h>
#include <errno.h>
typedef struct private_pts_file_meas_t private_pts_file_meas_t;
/**
* Private data of a pts_file_meas_t object.
*
*/
struct private_pts_file_meas_t {
/**
* Public pts_file_meas_t interface.
*/
pts_file_meas_t public;
/**
* ID of PTS File Measurement Request
*/
u_int16_t request_id;
/**
* List of File Measurements
*/
linked_list_t *list;
};
typedef struct entry_t entry_t;
/**
* PTS File Measurement entry
*/
struct entry_t {
char *filename;
chunk_t measurement;
};
/**
* Free an entry_t object
*/
static void free_entry(entry_t *entry)
{
if (entry)
{
free(entry->filename);
free(entry->measurement.ptr);
free(entry);
}
}
METHOD(pts_file_meas_t, get_request_id, u_int16_t,
private_pts_file_meas_t *this)
{
return this->request_id;
}
METHOD(pts_file_meas_t, get_file_count, int,
private_pts_file_meas_t *this)
{
return this->list->get_count(this->list);
}
METHOD(pts_file_meas_t, add, void,
private_pts_file_meas_t *this, char *filename, chunk_t measurement)
{
entry_t *entry;
entry = malloc_thing(entry_t);
entry->filename = strdup(filename);
entry->measurement = chunk_clone(measurement);
this->list->insert_last(this->list, entry);
}
/**
* Enumerate file measurement entries
*/
static bool entry_filter(void *null, entry_t **entry, char **filename,
void *i2, chunk_t *measurement)
{
*filename = (*entry)->filename;
*measurement = (*entry)->measurement;
return TRUE;
}
METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
private_pts_file_meas_t *this)
{
return enumerator_create_filter(this->list->create_enumerator(this->list),
(void*)entry_filter, NULL, NULL);
}
METHOD(pts_file_meas_t, check, bool,
private_pts_file_meas_t *this, pts_database_t *pts_db, int pid,
pts_meas_algorithms_t algo)
{
enumerator_t *enumerator, *e;
entry_t *entry;
chunk_t hash;
int count_ok = 0, count_not_found = 0, count_differ = 0;
status_t status;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
status = NOT_FOUND;
e = pts_db->create_file_meas_enumerator(pts_db, pid, algo,
entry->filename);
if (e)
{
while (e->enumerate(e, &hash))
{
if (chunk_equals(entry->measurement, hash))
{
status = SUCCESS;
break;
}
else
{
status = VERIFY_ERROR;
}
}
e->destroy(e);
}
else
{
status = FAILED;
}
switch (status)
{
case SUCCESS:
DBG3(DBG_PTS, " %#B for '%s' is ok", &entry->measurement,
entry->filename);
count_ok++;
break;
case NOT_FOUND:
DBG2(DBG_PTS, " %#B for '%s' not found", &entry->measurement,
entry->filename);
count_not_found++;
break;
case VERIFY_ERROR:
DBG1(DBG_PTS, " %#B for '%s' differs", &entry->measurement,
entry->filename);
count_differ++;
break;
case FAILED:
default:
DBG1(DBG_PTS, " %#B for '%s' failed", &entry->measurement,
entry->filename);
}
}
enumerator->destroy(enumerator);
DBG1(DBG_PTS, "%d measurements, %d ok, %d not found, %d differ",
this->list->get_count(this->list),
count_ok, count_not_found, count_differ);
return TRUE;
}
METHOD(pts_file_meas_t, verify, bool,
private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir)
{
int fid, fid_last = 0;
char *filename;
chunk_t measurement;
entry_t *entry;
enumerator_t *enumerator = NULL;
bool found = FALSE, match = FALSE, success = TRUE;
while (e_hash->enumerate(e_hash, &fid, &filename, &measurement))
{
if (fid != fid_last)
{
if (found && !match)
{
/* no matching hash value found for last filename */
success = FALSE;
DBG1(DBG_PTS, " %#B for '%s' is incorrect",
&entry->measurement, entry->filename);
enumerator->destroy(enumerator);
}
/* get a new filename from the database */
found = FALSE;
match = FALSE;
fid_last = fid;
/**
* check if we find an entry for this filename
* in the PTS measurement list
*/
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
if (!is_dir || streq(filename, entry->filename))
{
found = TRUE;
break;
}
}
/* no PTS measurement returned for this filename */
if (!found)
{
success = FALSE;
DBG1(DBG_PTS, " no measurement found for '%s'", filename);
enumerator->destroy(enumerator);
}
}
if (found && !match)
{
if (chunk_equals(measurement, entry->measurement))
{
match = TRUE;
DBG2(DBG_PTS, " %#B for '%s' is ok",
&entry->measurement, entry->filename);
enumerator->destroy(enumerator);
}
}
}
if (found && !match)
{
/* no matching hash value found for the very last filename */
success = FALSE;
DBG1(DBG_PTS, " %#B for '%s' is incorrect",
&entry->measurement, entry->filename);
enumerator->destroy(enumerator);
}
return success;
}
METHOD(pts_file_meas_t, destroy, void,
private_pts_file_meas_t *this)
{
this->list->destroy_function(this->list, (void *)free_entry);
free(this);
}
/**
* See header
*/
pts_file_meas_t *pts_file_meas_create(u_int16_t request_id)
{
private_pts_file_meas_t *this;
INIT(this,
.public = {
.get_request_id = _get_request_id,
.get_file_count = _get_file_count,
.add = _add,
.create_enumerator = _create_enumerator,
.check = _check,
.verify = _verify,
.destroy = _destroy,
},
.request_id = request_id,
.list = linked_list_create(),
);
return &this->public;
}
/**
* Hash a file with a given absolute pathname
*/
static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash)
{
u_char buffer[4096];
size_t bytes_read;
bool success = TRUE;
FILE *file;
file = fopen(pathname, "rb");
if (!file)
{
DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname,
strerror(errno));
return FALSE;
}
while (TRUE)
{
bytes_read = fread(buffer, 1, sizeof(buffer), file);
if (bytes_read > 0)
{
if (!hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL))
{
DBG1(DBG_PTS, " hasher increment error");
success = FALSE;
break;
}
}
else
{
if (!hasher->get_hash(hasher, chunk_empty, hash))
{
DBG1(DBG_PTS, " hasher finalize error");
success = FALSE;
}
break;
}
}
fclose(file);
return success;
}
/**
* See header
*/
pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id,
char *pathname, bool is_dir, bool use_rel_name,
pts_meas_algorithms_t alg)
{
private_pts_file_meas_t *this;
hash_algorithm_t hash_alg;
hasher_t *hasher;
u_char hash[HASH_SIZE_SHA384];
chunk_t measurement;
char* filename;
bool success = TRUE;
/* Create a hasher and a hash measurement buffer */
hash_alg = pts_meas_algo_to_hash(alg);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
if (!hasher)
{
DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg);
return NULL;
}
measurement = chunk_create(hash, hasher->get_hash_size(hasher));
this = (private_pts_file_meas_t*)pts_file_meas_create(request_id);
if (is_dir)
{
enumerator_t *enumerator;
char *rel_name, *abs_name;
struct stat st;
enumerator = enumerator_create_directory(pathname);
if (!enumerator)
{
DBG1(DBG_PTS, " directory '%s' can not be opened, %s", pathname,
strerror(errno));
success = FALSE;
goto end;
}
while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
{
/* measure regular files only */
if (S_ISREG(st.st_mode) && *rel_name != '.')
{
if (!hash_file(hasher, abs_name, hash))
{
continue;
}
filename = use_rel_name ? rel_name : abs_name;
DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
add(this, filename, measurement);
}
}
enumerator->destroy(enumerator);
}
else
{
if (!hash_file(hasher, pathname, hash))
{
success = FALSE;
goto end;
}
filename = use_rel_name ? path_basename(pathname) : strdup(pathname);
DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
add(this, filename, measurement);
free(filename);
}
end:
hasher->destroy(hasher);
if (success)
{
return &this->public;
}
else
{
destroy(this);
return NULL;
}
}
+112
View File
@@ -0,0 +1,112 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* Copyright (C) 2014 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 pts_file_meas pts_file_meas
* @{ @ingroup pts
*/
#ifndef PTS_FILE_MEAS_H_
#define PTS_FILE_MEAS_H_
#include "pts/pts_database.h"
#include <library.h>
typedef struct pts_file_meas_t pts_file_meas_t;
/**
* Class storing PTS File Measurements
*/
struct pts_file_meas_t {
/**
* Get the ID of the PTS File Measurement Request
*
* @return ID of PTS File Measurement Request
*/
u_int16_t (*get_request_id)(pts_file_meas_t *this);
/**
* Get the number of measured files
*
* @return Number of measured files
*/
int (*get_file_count)(pts_file_meas_t *this);
/**
* Add a PTS File Measurement
*
* @param filename Name of measured file or directory
* @param measurement PTS Measurement hash
*/
void (*add)(pts_file_meas_t *this, char *filename, chunk_t measurement);
/**
* Create a PTS File Measurement enumerator
*
* @return Enumerator returning filename and measurement
*/
enumerator_t* (*create_enumerator)(pts_file_meas_t *this);
/**
* Check PTS File Measurements against reference value in the database
*
* @param db PTS Measurement database
* @param pid Primary key of software product in database
* @param algo PTS Measurement algorithm used
* @return TRUE if all measurements agreed
*/
bool (*check)(pts_file_meas_t *this, pts_database_t *db, int pid,
pts_meas_algorithms_t algo);
/**
* Verify stored hashes against PTS File Measurements
*
* @param e_hash Hash enumerator
* @param is_dir TRUE for directory contents hashes
* @return TRUE if all hashes match a measurement
*/
bool (*verify)(pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir);
/**
* Destroys a pts_file_meas_t object.
*/
void (*destroy)(pts_file_meas_t *this);
};
/**
* Creates a pts_file_meas_t object
*
* @param request_id ID of PTS File Measurement Request
*/
pts_file_meas_t* pts_file_meas_create(u_int16_t request_id);
/**
* Creates a pts_file_meas_t object measuring a file/directory
*
* @param request_id ID of PTS File Measurement Request
* @param pathname Absolute file or directory pathname
* @param is_dir TRUE if directory path
* @param use_rel_name TRUE if relative filenames are to be used
* @param alg PTS hash measurement algorithm to be used
*/
pts_file_meas_t* pts_file_meas_create_from_path(u_int16_t request_id,
char* pathname, bool is_dir, bool use_rel_name,
pts_meas_algorithms_t alg);
#endif /** PTS_FILE_MEAS_H_ @}*/
+96
View File
@@ -0,0 +1,96 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 "pts_file_meta.h"
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_pts_file_meta_t private_pts_file_meta_t;
/**
* Private data of a pts_file_meta_t object.
*
*/
struct private_pts_file_meta_t {
/**
* Public pts_file_meta_t interface.
*/
pts_file_meta_t public;
/**
* List of File Metadata
*/
linked_list_t *list;
};
/**
* Free an pts_file_metadata_t object
*/
static void free_entry(pts_file_metadata_t *entry)
{
if (entry)
{
free(entry->filename);
free(entry);
}
}
METHOD(pts_file_meta_t, get_file_count, int,
private_pts_file_meta_t *this)
{
return this->list->get_count(this->list);
}
METHOD(pts_file_meta_t, add, void,
private_pts_file_meta_t *this, pts_file_metadata_t *metadata)
{
this->list->insert_last(this->list, metadata);
}
METHOD(pts_file_meta_t, create_enumerator, enumerator_t*,
private_pts_file_meta_t *this)
{
return this->list->create_enumerator(this->list);
}
METHOD(pts_file_meta_t, destroy, void,
private_pts_file_meta_t *this)
{
this->list->destroy_function(this->list, (void *)free_entry);
free(this);
}
/**
* See header
*/
pts_file_meta_t *pts_file_meta_create()
{
private_pts_file_meta_t *this;
INIT(this,
.public = {
.get_file_count = _get_file_count,
.add = _add,
.create_enumerator = _create_enumerator,
.destroy = _destroy,
},
.list = linked_list_create(),
);
return &this->public;
}
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_file_meta pts_file_meta
* @{ @ingroup pts
*/
#ifndef PTS_FILE_META_H_
#define PTS_FILE_META_H_
#include "pts_file_type.h"
#include <time.h>
#include <library.h>
typedef struct pts_file_meta_t pts_file_meta_t;
typedef struct pts_file_metadata_t pts_file_metadata_t;
/**
* Structure holding file metadata
*/
struct pts_file_metadata_t {
pts_file_type_t type;
u_int64_t filesize;
u_int64_t created;
u_int64_t modified;
u_int64_t accessed;
u_int64_t owner;
u_int64_t group;
char *filename;
};
/**
* Class storing PTS File Metadata
*/
struct pts_file_meta_t {
/**
* Get the number of files
*
* @return Number of files
*/
int (*get_file_count)(pts_file_meta_t *this);
/**
* Add PTS File Metadata
*
* @param filename Name of measured file or directory
* @param metadata File metadata
*/
void (*add)(pts_file_meta_t *this, pts_file_metadata_t *metadata);
/**
* Create a PTS File Metadata enumerator
*
* @return Enumerator returning file metadata
*/
enumerator_t* (*create_enumerator)(pts_file_meta_t *this);
/**
* Destroys a pts_file_meta_t object.
*/
void (*destroy)(pts_file_meta_t *this);
};
/**
* Creates a pts_file_meta_t object
*/
pts_file_meta_t* pts_file_meta_create();
#endif /** PTS_FILE_MEAS_H_ @}*/
+33
View File
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "pts_file_type.h"
ENUM(pts_file_type_names, PTS_FILE_OTHER, PTS_FILE_SOCKET,
"Other",
"FIFO",
"Character-Special",
"Reserved-3",
"Directory",
"Reserved-5",
"Block-Special",
"Reserved-7",
"Regular",
"Reserved-9",
"Symbolic-Link",
"Reserved-11",
"Socket"
);
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_file_type pts_file_type
* @{ @ingroup pts
*/
#ifndef PTS_FILE_TYPE_H_
#define PTS_FILE_TYPE_H_
#include <library.h>
typedef enum pts_file_type_t pts_file_type_t;
/**
* PTS File Type
* see section 3.17.3 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum pts_file_type_t {
/** Either unknown or different from standardized types */
PTS_FILE_OTHER = 0x0000,
/** Pipe communication file */
PTS_FILE_FIFO = 0x0001,
/** Character special file */
PTS_FILE_CHAR_SPEC = 0x0002,
/** Reserved */
PTS_FILE_RESERVED_3 = 0x0003,
/** Directory */
PTS_FILE_DIRECTORY = 0x0004,
/** Reserved */
PTS_FILE_RESERVED_5 = 0x0005,
/** Block special file */
PTS_FILE_BLOCK_SPEC = 0x0006,
/** Reserved */
PTS_FILE_RESERVED_7 = 0x0007,
/** Regular file */
PTS_FILE_REGULAR = 0x0008,
/** Reserved */
PTS_FILE_RESERVED_9 = 0x0009,
/** Symbolic link */
PTS_FILE_SYM_LINK = 0x000A,
/** Reserved */
PTS_FILE_RESERVED_11 = 0x000B,
/** Socket communication special file */
PTS_FILE_SOCKET = 0x000C,
};
extern enum_name_t *pts_file_type_names;
#endif /** PTS_FILE_TYPE_H_ @}*/
+294
View File
@@ -0,0 +1,294 @@
/*
* Copyright (C) 2011-2014 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 "pts_ima_bios_list.h"
#include <utils/debug.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
typedef struct private_pts_ima_bios_list_t private_pts_ima_bios_list_t;
typedef struct bios_entry_t bios_entry_t;
typedef enum event_type_t event_type_t;
enum event_type_t {
/* BIOS Events (TCG PC Client Specification for Conventional BIOS 1.21) */
EV_PREBOOT_CERT = 0x00000000,
EV_POST_CODE = 0x00000001,
EV_UNUSED = 0x00000002,
EV_NO_ACTION = 0x00000003,
EV_SEPARATOR = 0x00000004,
EV_ACTION = 0x00000005,
EV_EVENT_TAG = 0x00000006,
EV_S_CRTM_CONTENTS = 0x00000007,
EV_S_CRTM_VERSION = 0x00000008,
EV_CPU_MICROCODE = 0x00000009,
EV_PLATFORM_CONFIG_FLAGS = 0x0000000A,
EV_TABLE_OF_DEVICES = 0x0000000B,
EV_COMPACT_HASH = 0x0000000C,
EV_IPL = 0x0000000D,
EV_IPL_PARTITION_DATA = 0x0000000E,
EV_NONHOST_CODE = 0x0000000F,
EV_NONHOST_CONFIG = 0x00000010,
EV_NONHOST_INFO = 0x00000011,
EV_OMIT_BOOT_DEVICE_EVENTS = 0x00000012,
/* EFI Events (TCG EFI Platform Specification 1.22) */
EV_EFI_EVENT_BASE = 0x80000000,
EV_EFI_VARIABLE_DRIVER_CONFIG = 0x80000001,
EV_EFI_VARIABLE_BOOT = 0x80000002,
EV_EFI_BOOT_SERVICES_APPLICATION = 0x80000003,
EV_EFI_BOOT_SERVICES_DRIVER = 0x80000004,
EV_EFI_RUNTIME_SERVICES_DRIVER = 0x80000005,
EV_EFI_GPT_EVENT = 0x80000006,
EV_EFI_ACTION = 0x80000007,
EV_EFI_PLATFORM_FIRMWARE_BLOB = 0x80000008,
EV_EFI_HANDOFF_TABLES = 0x80000009,
EV_EFI_VARIABLE_AUTHORITY = 0x800000E0
};
ENUM_BEGIN(event_type_names, EV_PREBOOT_CERT, EV_OMIT_BOOT_DEVICE_EVENTS,
"Preboot Cert",
"POST Code",
"Unused",
"No Action",
"Separator",
"Action",
"Event Tag",
"S-CRTM Contents",
"S-CRTM Version",
"CPU Microcode",
"Platform Config Flags",
"Table of Devices",
"Compact Hash",
"IPL",
"IPL Partition Data",
"Nonhost Code",
"Nonhost Config",
"Nonhost Info",
"Omit Boot Device Events"
);
ENUM_NEXT(event_type_names, EV_EFI_EVENT_BASE, EV_EFI_HANDOFF_TABLES,
EV_OMIT_BOOT_DEVICE_EVENTS,
"EFI Event Base",
"EFI Variable Driver Config",
"EFI Variable Boot",
"EFI Boot Services Application",
"EFI Boot Services Driver",
"EFI Runtime Services Driver",
"EFI GPT Event",
"EFI Action",
"EFI Platform Firmware Blob",
"EFI Handoff Tables"
);
ENUM_NEXT(event_type_names, EV_EFI_VARIABLE_AUTHORITY, EV_EFI_VARIABLE_AUTHORITY,
EV_EFI_HANDOFF_TABLES,
"EFI Variable Authority"
);
ENUM_END(event_type_names, EV_EFI_VARIABLE_AUTHORITY);
/**
* Private data of a pts_ima_bios_list_t object.
*
*/
struct private_pts_ima_bios_list_t {
/**
* Public pts_ima_bios_list_t interface.
*/
pts_ima_bios_list_t public;
/**
* List of BIOS measurement entries
*/
linked_list_t *list;
/**
* Time when BIOS measurements were taken
*/
time_t creation_time;
};
/**
* Linux IMA BIOS measurement entry
*/
struct bios_entry_t {
/**
* PCR register
*/
uint32_t pcr;
/**
* SHA1 measurement hash
*/
chunk_t measurement;
};
/**
* Free a bios_entry_t object
*/
static void free_bios_entry(bios_entry_t *this)
{
free(this->measurement.ptr);
free(this);
}
METHOD(pts_ima_bios_list_t, get_time, time_t,
private_pts_ima_bios_list_t *this)
{
return this->creation_time;
}
METHOD(pts_ima_bios_list_t, get_count, int,
private_pts_ima_bios_list_t *this)
{
return this->list->get_count(this->list);
}
METHOD(pts_ima_bios_list_t, get_next, status_t,
private_pts_ima_bios_list_t *this, uint32_t *pcr, chunk_t *measurement)
{
bios_entry_t *entry;
status_t status;
status = this->list->remove_first(this->list, (void**)&entry);
*pcr = entry->pcr;
*measurement = entry->measurement;
free(entry);
return status;
}
METHOD(pts_ima_bios_list_t, destroy, void,
private_pts_ima_bios_list_t *this)
{
this->list->destroy_function(this->list, (void *)free_bios_entry);
free(this);
}
/**
* See header
*/
pts_ima_bios_list_t* pts_ima_bios_list_create(char *file)
{
private_pts_ima_bios_list_t *this;
uint32_t pcr, event_type, event_len, seek_len;
uint32_t buf_len = 2048;
uint8_t event_buf[buf_len];
chunk_t event;
bios_entry_t *entry;
struct stat st;
ssize_t res;
int fd;
fd = open(file, O_RDONLY);
if (fd == -1)
{
DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
return NULL;
}
if (fstat(fd, &st) == -1)
{
DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
strerror(errno));
close(fd);
return FALSE;
}
INIT(this,
.public = {
.get_time = _get_time,
.get_count = _get_count,
.get_next = _get_next,
.destroy = _destroy,
},
.creation_time = st.st_ctime,
.list = linked_list_create(),
);
DBG2(DBG_PTS, "PCR Event Type (Size)");
while (TRUE)
{
res = read(fd, &pcr, 4);
if (res == 0)
{
DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
file, this->list->get_count(this->list));
close(fd);
return &this->public;
}
entry = malloc_thing(bios_entry_t);
entry->pcr = pcr;
entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
if (res != 4)
{
break;
}
if (read(fd, &event_type, 4) != 4)
{
break;
}
if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
{
break;
}
if (read(fd, &event_len, 4) != 4)
{
break;
}
DBG2(DBG_PTS, "%2u %N (%u bytes)", pcr, event_type_names, event_type,
event_len);
seek_len = (event_len > buf_len) ? event_len - buf_len : 0;
event_len -= seek_len;
if (read(fd, event_buf, event_len) != event_len)
{
break;
}
event = chunk_create(event_buf, event_len);
DBG3(DBG_PTS,"%B", &event);
if (event_type == EV_ACTION || event_type == EV_EFI_ACTION)
{
DBG2(DBG_PTS, " '%.*s'", event_len, event_buf);
}
if (seek_len > 0 && lseek(fd, seek_len, SEEK_CUR) == -1)
{
break;
}
this->list->insert_last(this->list, entry);
}
DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file,
strerror(errno));
free_bios_entry(entry);
close(fd);
destroy(this);
return NULL;
}
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2014 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 pts_ima_bios_list pts_ima_bios_list
* @{ @ingroup pts
*/
#ifndef PTS_IMA_BIOS_LIST_H_
#define PTS_IMA_BIOS_LIST_H_
#include <time.h>
#include <library.h>
typedef struct pts_ima_bios_list_t pts_ima_bios_list_t;
/**
* Class retrieving Linux IMA BIOS measurements
*
*/
struct pts_ima_bios_list_t {
/**
* Get the time the BIOS measurements were taken
*
* @return Measurement time
*/
time_t (*get_time)(pts_ima_bios_list_t *this);
/**
* Get the number of non-processed BIOS measurements
*
* @return Number of measurements left
*/
int (*get_count)(pts_ima_bios_list_t *this);
/**
* Get the next BIOS measurement and remove it from the list
*
* @param pcr PCR where the measurement was extended into
* @param measurement Measurement hash
* @return Return code
*/
status_t (*get_next)(pts_ima_bios_list_t *this, uint32_t *pcr,
chunk_t *measurement);
/**
* Destroys a pts_ima_bios_list_t object.
*/
void (*destroy)(pts_ima_bios_list_t *this);
};
/**
* Create a PTS IMA BIOS measurement object
*
* @param file Pathname pointing to the BIOS measurements
*/
pts_ima_bios_list_t* pts_ima_bios_list_create(char *file);
#endif /** PTS_IMA_BIOS_LIST_H_ @}*/
+330
View File
@@ -0,0 +1,330 @@
/*
* Copyright (C) 2011-2014 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 "pts_ima_event_list.h"
#include <utils/debug.h>
#include <crypto/hashers/hasher.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
typedef struct private_pts_ima_event_list_t private_pts_ima_event_list_t;
typedef struct event_entry_t event_entry_t;
#define IMA_TYPE_LEN 3
#define IMA_NG_TYPE_LEN 6
#define IMA_TYPE_LEN_MAX 10
#define IMA_ALGO_DIGEST_LEN_MAX IMA_ALGO_LEN_MAX + HASH_SIZE_SHA512
/**
* Private data of a pts_ima_event_list_t object.
*
*/
struct private_pts_ima_event_list_t {
/**
* Public pts_ima_event_list_t interface.
*/
pts_ima_event_list_t public;
/**
* List of BIOS measurement entries
*/
linked_list_t *list;
/**
* Time when IMA runtime file measurements were taken
*/
time_t creation_time;
};
/**
* Linux IMA runtime file measurement entry
*/
struct event_entry_t {
/**
* SHA1 measurement hash
*/
chunk_t measurement;
/**
* IMA-NG hash algorithm name or NULL
*/
char *algo;
/**
* IMA-NG eventname or IMA filename
*/
char *name;
};
/**
* Free an ima_event_t object
*/
static void free_event_entry(event_entry_t *this)
{
free(this->measurement.ptr);
free(this->algo);
free(this->name);
free(this);
}
METHOD(pts_ima_event_list_t, get_time, time_t,
private_pts_ima_event_list_t *this)
{
return this->creation_time;
}
METHOD(pts_ima_event_list_t, get_count, int,
private_pts_ima_event_list_t *this)
{
return this->list->get_count(this->list);
}
METHOD(pts_ima_event_list_t, get_next, status_t,
private_pts_ima_event_list_t *this, chunk_t *measurement, char **algo,
char **name)
{
event_entry_t *entry;
status_t status;
status = this->list->remove_first(this->list, (void**)&entry);
*measurement = entry->measurement;
*algo = entry->algo;
*name = entry->name;
free(entry);
return status;
}
METHOD(pts_ima_event_list_t, destroy, void,
private_pts_ima_event_list_t *this)
{
this->list->destroy_function(this->list, (void *)free_event_entry);
free(this);
}
/**
* See header
*/
pts_ima_event_list_t* pts_ima_event_list_create(char *file)
{
private_pts_ima_event_list_t *this;
event_entry_t *entry;
uint32_t pcr, type_len, name_len, eventdata_len, algo_digest_len, algo_len;
char type[IMA_TYPE_LEN_MAX];
char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
char *pos, *error = "";
struct stat st;
ssize_t res;
bool ima_ng;
int fd;
fd = open(file, O_RDONLY);
if (fd == -1)
{
DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
return NULL;
}
if (fstat(fd, &st) == -1)
{
DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
strerror(errno));
close(fd);
return NULL;
}
INIT(this,
.public = {
.get_time = _get_time,
.get_count = _get_count,
.get_next = _get_next,
.destroy = _destroy,
},
.creation_time = st.st_ctime,
.list = linked_list_create(),
);
while (TRUE)
{
/* read 32 bit PCR number in host order */
res = read(fd, &pcr, 4);
/* exit if no more measurement data is available */
if (res == 0)
{
DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
file, this->list->get_count(this->list));
close(fd);
return &this->public;
}
/* create and initialize new IMA entry */
entry = malloc_thing(event_entry_t);
entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
entry->algo = NULL;
entry->name = NULL;
if (res != 4 || pcr != IMA_PCR)
{
error = "invalid IMA PCR field";
break;
}
/* read 20 byte SHA-1 measurement digest */
if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
{
error = "invalid SHA-1 digest field";
break;
}
/* read 32 bit length of IMA type string in host order */
if (read(fd, &type_len, 4) != 4 || type_len > IMA_TYPE_LEN_MAX)
{
error = "invalid IMA type field length";
break;
}
/* read and interpret IMA type string */
if (read(fd, type, type_len) != type_len)
{
error = "invalid IMA type field";
break;
}
if (type_len == IMA_NG_TYPE_LEN &&
memeq(type, "ima-ng", IMA_NG_TYPE_LEN))
{
ima_ng = TRUE;
}
else if (type_len == IMA_TYPE_LEN &&
memeq(type, "ima", IMA_TYPE_LEN))
{
ima_ng = FALSE;
}
else
{
error = "unknown IMA type";
break;
}
if (ima_ng)
{
/* read the 32 bit length of the event data in host order */
if (read(fd, &eventdata_len, 4) != 4 || eventdata_len < 4)
{
error = "invalid event data field length";
break;
}
/* read the 32 bit length of the algo_digest string in host order */
if (read(fd, &algo_digest_len, 4) != 4 ||
algo_digest_len > IMA_ALGO_DIGEST_LEN_MAX ||
eventdata_len < 4 + algo_digest_len + 4)
{
error = "invalid digest_with_algo field length";
break;
}
/* read the IMA algo_digest string */
if (read(fd, algo_digest, algo_digest_len) != algo_digest_len)
{
error = "invalid digest_with_algo field";
break;
}
/* extract the hash algorithm name */
pos = memchr(algo_digest, '\0', algo_digest_len);
if (!pos)
{
error = "no algo field";
break;
}
algo_len = pos - algo_digest + 1;
if (algo_len > IMA_ALGO_LEN_MAX ||
algo_len < IMA_ALGO_LEN_MIN || *(pos - 1) != ':')
{
error = "invalid algo field";
break;
}
/* copy and store the hash algorithm name */
entry->algo = malloc(algo_len);
memcpy(entry->algo, algo_digest, algo_len);
/* read the 32 bit length of the event name in host order */
if (read(fd, &name_len, 4) != 4 ||
eventdata_len != 4 + algo_digest_len + 4 + name_len)
{
error = "invalid filename field length";
break;
}
/* allocate memory for the file name */
entry->name = malloc(name_len);
/* read file name */
if (read(fd, entry->name, name_len) != name_len)
{
error = "invalid filename field";
break;
}
}
else
{
/* skip SHA-1 digest of the file content */
if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1)
{
break;
}
/* read the 32 bit length of the file name in host order */
if (read(fd, &name_len, 4) != 4 || name_len == UINT32_MAX)
{
error = "invalid filename field length";
break;
}
/* allocate memory for the file name */
entry->name = malloc(name_len + 1);
/* read file name */
if (read(fd, entry->name, name_len) != name_len)
{
error = "invalid eventname field";
break;
}
/* terminate the file name with a nul character */
entry->name[name_len] = '\0';
}
this->list->insert_last(this->list, entry);
}
DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error);
free_event_entry(entry);
close(fd);
destroy(this);
return NULL;
}
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2014 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 pts_ima_event_list pts_ima_event_list
* @{ @ingroup pts
*/
#ifndef PTS_IMA_EVENT_LIST_H_
#define PTS_IMA_EVENT_LIST_H_
#include <time.h>
#include <library.h>
typedef struct pts_ima_event_list_t pts_ima_event_list_t;
#define IMA_PCR 10
#define IMA_ALGO_LEN_MIN 5
#define IMA_ALGO_LEN_MAX 8
/**
* Class retrieving Linux IMA file measurements
*
*/
struct pts_ima_event_list_t {
/**
* Get the time the file measurements were taken
*
* @return Measurement time
*/
time_t (*get_time)(pts_ima_event_list_t *this);
/**
* Get the number of non-processed file measurements
*
* @return Number of measurements left
*/
int (*get_count)(pts_ima_event_list_t *this);
/**
* Get the next file measurement and remove it from the list
*
* @param measurement Measurement hash
* @param algo Algorithm used to hash files
" @param name Event name (absolute filename or boot_aggregate)
* @return Return code
*/
status_t (*get_next)(pts_ima_event_list_t *this, chunk_t *measurement,
char **algo, char **name);
/**
* Destroys a pts_ima_event_list_t object.
*/
void (*destroy)(pts_ima_event_list_t *this);
};
/**
* Create a PTS IMA runtime file measurement object
*
* @param file Pathname pointing to the IMA runtme measurements
*/
pts_ima_event_list_t* pts_ima_event_list_create(char *file);
#endif /** PTS_IMA_EVENT_LIST_H_ @}*/
+176
View File
@@ -0,0 +1,176 @@
/*
* Copyright (C) 2011-2014 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 "pts_meas_algo.h"
#include <utils/debug.h>
ENUM_BEGIN(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_NONE,
"None");
ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA384, PTS_MEAS_ALGO_SHA384,
PTS_MEAS_ALGO_NONE,
"SHA384");
ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA256, PTS_MEAS_ALGO_SHA256,
PTS_MEAS_ALGO_SHA384,
"SHA256");
ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1, PTS_MEAS_ALGO_SHA1,
PTS_MEAS_ALGO_SHA256,
"SHA1");
ENUM_END(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1);
/**
* Described in header.
*/
bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms)
{
enumerator_t *enumerator;
hash_algorithm_t hash_alg;
const char *plugin_name;
char format1[] = " %s PTS measurement algorithm %N[%s] available";
char format2[] = " %s PTS measurement algorithm %N not available";
*algorithms = 0;
enumerator = lib->crypto->create_hasher_enumerator(lib->crypto);
while (enumerator->enumerate(enumerator, &hash_alg, &plugin_name))
{
if (hash_alg == HASH_SHA1)
{
*algorithms |= PTS_MEAS_ALGO_SHA1;
DBG2(DBG_PTS, format1, "mandatory", hash_algorithm_names, hash_alg,
plugin_name);
}
else if (hash_alg == HASH_SHA256)
{
*algorithms |= PTS_MEAS_ALGO_SHA256;
DBG2(DBG_PTS, format1, "mandatory", hash_algorithm_names, hash_alg,
plugin_name);
}
else if (hash_alg == HASH_SHA384)
{
*algorithms |= PTS_MEAS_ALGO_SHA384;
DBG2(DBG_PTS, format1, "optional ", hash_algorithm_names, hash_alg,
plugin_name);
}
}
enumerator->destroy(enumerator);
if (!(*algorithms & PTS_MEAS_ALGO_SHA384))
{
DBG1(DBG_PTS, format2, "optional ", hash_algorithm_names, HASH_SHA384);
}
if ((*algorithms & PTS_MEAS_ALGO_SHA1) &&
(*algorithms & PTS_MEAS_ALGO_SHA256))
{
return TRUE;
}
if (!(*algorithms & PTS_MEAS_ALGO_SHA1))
{
DBG1(DBG_PTS, format2, "mandatory", hash_algorithm_names, HASH_SHA1);
}
if (!(*algorithms & PTS_MEAS_ALGO_SHA256))
{
DBG1(DBG_PTS, format2, "mandatory", hash_algorithm_names, HASH_SHA256);
}
return FALSE;
}
/**
* Described in header.
*/
bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms)
{
if (strcaseeq(hash_alg, "sha384") || strcaseeq(hash_alg, "sha2_384"))
{
/* nothing to update, all algorithms are supported */
return TRUE;
}
if (strcaseeq(hash_alg, "sha256") || strcaseeq(hash_alg, "sha2_256"))
{
/* remove SHA384algorithm */
*algorithms &= ~PTS_MEAS_ALGO_SHA384;
return TRUE;
}
if (strcaseeq(hash_alg, "sha1"))
{
/* remove SHA384 and SHA256 algorithms */
*algorithms &= ~(PTS_MEAS_ALGO_SHA384 | PTS_MEAS_ALGO_SHA256);
return TRUE;
}
DBG1(DBG_PTS, "unknown hash algorithm '%s' configured", hash_alg);
return FALSE;
}
/**
* Described in header.
*/
pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos,
pts_meas_algorithms_t offered_algos)
{
if ((supported_algos & PTS_MEAS_ALGO_SHA384) &&
(offered_algos & PTS_MEAS_ALGO_SHA384))
{
return PTS_MEAS_ALGO_SHA384;
}
if ((supported_algos & PTS_MEAS_ALGO_SHA256) &&
(offered_algos & PTS_MEAS_ALGO_SHA256))
{
return PTS_MEAS_ALGO_SHA256;
}
if ((supported_algos & PTS_MEAS_ALGO_SHA1) &&
(offered_algos & PTS_MEAS_ALGO_SHA1))
{
return PTS_MEAS_ALGO_SHA1;
}
return PTS_MEAS_ALGO_NONE;
}
/**
* Described in header.
*/
hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm)
{
switch (algorithm)
{
case PTS_MEAS_ALGO_SHA1:
return HASH_SHA1;
case PTS_MEAS_ALGO_SHA256:
return HASH_SHA256;
case PTS_MEAS_ALGO_SHA384:
return HASH_SHA384;
default:
return HASH_UNKNOWN;
}
}
/**
* Described in header.
*/
size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm)
{
switch (algorithm)
{
case PTS_MEAS_ALGO_SHA1:
return HASH_SIZE_SHA1;
case PTS_MEAS_ALGO_SHA256:
return HASH_SIZE_SHA256;
case PTS_MEAS_ALGO_SHA384:
return HASH_SIZE_SHA384;
case PTS_MEAS_ALGO_NONE:
default:
return 0;
}
}
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* Copyright (C) 2011-2014 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 pts_meas_algo pts_meas_algo
* @{ @ingroup pts
*/
#ifndef PTS_MEAS_ALGO_H_
#define PTS_MEAS_ALGO_H_
#include <library.h>
#include <crypto/hashers/hasher.h>
typedef enum pts_meas_algorithms_t pts_meas_algorithms_t;
/**
* PTS Measurement Algorithms
*/
enum pts_meas_algorithms_t {
PTS_MEAS_ALGO_NONE = 0,
PTS_MEAS_ALGO_SHA384 = (1<<13),
PTS_MEAS_ALGO_SHA256 = (1<<14),
PTS_MEAS_ALGO_SHA1 = (1<<15)
};
/**
* enum name for pts_meas_algorithms_t.
*/
extern enum_name_t *pts_meas_algorithm_names;
/**
* Diffie-Hellman Hash Algorithm Values
* see section 3.8.5 of PTS Protocol: Binding to TNC IF-M Specification
*
* 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |1|2|3|R|R|R|R|R|R|R|R|R|R|R|R|R|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
/**
* Probe available PTS measurement algorithms
*
* @param algorithms set of available algorithms
* @return TRUE if mandatory algorithms are available
*/
bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms);
/**
* Update supported PTS measurement algorithms according to configuration
*
* sha1 : PTS_MEAS_ALGO_SHA1
* sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
* sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
*
* The PTS-IMC is expected to select the strongest supported algorithm
*
* @param hash_alg configured hash algorithm
* @param algorithms returns set of available PTS measurement algorithms
*/
bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms);
/**
* Select the strongest PTS measurement algorithm
* among a set of offered PTS measurement algorithms
*
* @param supported_algos set of supported PTS measurement algorithms
* @param offered_algos set of offered PTS measurements algorithms
* @return selected algorithm
*/
pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos,
pts_meas_algorithms_t offered_algos);
/**
* Convert pts_meas_algorithms_t to hash_algorithm_t
*
* @param algorithm PTS measurement algorithm type
* @return libstrongswan hash algorithm type
*/
hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm);
/**
* Return the hash size of a pts_meas_algorithm
*
* @param algorithm PTS measurement algorithm type
* @return hash size in bytes
*/
size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm);
#endif /** PTS_MEAS_ALGO_H_ @}*/
+289
View File
@@ -0,0 +1,289 @@
/*
* Copyright (C) 2012 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 "pts_pcr.h"
#include <utils/debug.h>
#include <stdarg.h>
typedef struct private_pts_pcr_t private_pts_pcr_t;
/**
* Private data of a pts_pcr_t object.
*
*/
struct private_pts_pcr_t {
/**
* Public pts_pcr_t interface.
*/
pts_pcr_t public;
/**
* Shadow PCR registers
*/
chunk_t pcrs[PTS_PCR_MAX_NUM];
/**
* Number of extended PCR registers
*/
u_int32_t pcr_count;
/**
* Highest extended PCR register
*/
u_int32_t pcr_max;
/**
* Bitmap of extended PCR registers
*/
u_int8_t pcr_select[PTS_PCR_MAX_NUM / 8];
/**
* Hasher used to extend shadow PCRs
*/
hasher_t *hasher;
};
METHOD(pts_pcr_t, get_count, u_int32_t,
private_pts_pcr_t *this)
{
return this->pcr_count;
}
METHOD(pts_pcr_t, select_pcr, bool,
private_pts_pcr_t *this, u_int32_t pcr)
{
u_int32_t i, f;
if (pcr >= PTS_PCR_MAX_NUM)
{
DBG1(DBG_PTS, "PCR %2u: number is larger than maximum of %u",
pcr, PTS_PCR_MAX_NUM-1);
return FALSE;
}
/* Determine PCR selection flag */
i = pcr / 8;
f = 1 << (pcr - 8*i);
/* Has this PCR already been selected? */
if (!(this->pcr_select[i] & f))
{
this->pcr_select[i] |= f;
this->pcr_max = max(this->pcr_max, pcr);
this->pcr_count++;
}
return TRUE;
}
METHOD(pts_pcr_t, get_selection_size, size_t,
private_pts_pcr_t *this)
{
/**
* A TPM v1.2 has 24 PCR Registers so the bitmask field length
* used by TrouSerS is at least 3 bytes
*/
return PTS_PCR_MAX_NUM / 8;
}
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** current PCR */
u_int32_t pcr;
/** back reference to parent */
private_pts_pcr_t *pcrs;
} pcr_enumerator_t;
/**
* Implementation of enumerator.enumerate
*/
static bool pcr_enumerator_enumerate(pcr_enumerator_t *this, ...)
{
u_int32_t *pcr, i, f;
va_list args;
va_start(args, this);
pcr = va_arg(args, u_int32_t*);
va_end(args);
while (this->pcr <= this->pcrs->pcr_max)
{
/* Determine PCR selection flag */
i = this->pcr / 8;
f = 1 << (this->pcr - 8*i);
/* Assign current PCR to output argument and increase */
*pcr = this->pcr++;
/* return if PCR is selected */
if (this->pcrs->pcr_select[i] & f)
{
return TRUE;
}
}
return FALSE;
}
METHOD(pts_pcr_t, create_enumerator, enumerator_t*,
private_pts_pcr_t *this)
{
pcr_enumerator_t *enumerator;
INIT(enumerator,
.public = {
.enumerate = (void*)pcr_enumerator_enumerate,
.destroy = (void*)free,
},
.pcrs = this,
);
return (enumerator_t*)enumerator;
}
METHOD(pts_pcr_t, get, chunk_t,
private_pts_pcr_t *this, u_int32_t pcr)
{
return (pcr < PTS_PCR_MAX_NUM) ? this->pcrs[pcr] : chunk_empty;
}
METHOD(pts_pcr_t, set, bool,
private_pts_pcr_t *this, u_int32_t pcr, chunk_t value)
{
if (value.len != PTS_PCR_LEN)
{
DBG1(DBG_PTS, "PCR %2u: value does not fit", pcr);
return FALSE;
}
if (select_pcr(this, pcr))
{
memcpy(this->pcrs[pcr].ptr, value.ptr, PTS_PCR_LEN);
return TRUE;
}
return FALSE;
}
METHOD(pts_pcr_t, extend, chunk_t,
private_pts_pcr_t *this, u_int32_t pcr, chunk_t measurement)
{
if (measurement.len != PTS_PCR_LEN)
{
DBG1(DBG_PTS, "PCR %2u: measurement does not fit", pcr);
return chunk_empty;
}
if (!select_pcr(this, pcr))
{
return chunk_empty;
}
if (!this->hasher->get_hash(this->hasher, this->pcrs[pcr] , NULL) ||
!this->hasher->get_hash(this->hasher, measurement, this->pcrs[pcr].ptr))
{
DBG1(DBG_PTS, "PCR %2u: not extended due to hasher problem", pcr);
return chunk_empty;
}
return this->pcrs[pcr];
}
METHOD(pts_pcr_t, get_composite, chunk_t,
private_pts_pcr_t *this)
{
chunk_t composite;
enumerator_t *enumerator;
u_int16_t selection_size;
u_int32_t pcr_field_size, pcr;
u_char *pos;
selection_size = get_selection_size(this);
pcr_field_size = this->pcr_count * PTS_PCR_LEN;
composite = chunk_alloc(2 + selection_size + 4 + pcr_field_size);
pos = composite.ptr;
htoun16(pos, selection_size);
pos += 2;
memcpy(pos, this->pcr_select, selection_size);
pos += selection_size;
htoun32(pos, pcr_field_size);
pos += 4;
enumerator = create_enumerator(this);
while (enumerator->enumerate(enumerator, &pcr))
{
memcpy(pos, this->pcrs[pcr].ptr, PTS_PCR_LEN);
pos += PTS_PCR_LEN;
}
enumerator->destroy(enumerator);
DBG3(DBG_PTS, "constructed PCR Composite: %B", &composite);
return composite;
}
METHOD(pts_pcr_t, destroy, void,
private_pts_pcr_t *this)
{
u_int32_t i;
for (i = 0; i < PTS_PCR_MAX_NUM; i++)
{
free(this->pcrs[i].ptr);
}
this->hasher->destroy(this->hasher);
free(this);
}
/**
* See header
*/
pts_pcr_t *pts_pcr_create(void)
{
private_pts_pcr_t *this;
hasher_t *hasher;
u_int32_t i;
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (!hasher)
{
DBG1(DBG_PTS, "%N hasher could not be created",
hash_algorithm_short_names, HASH_SHA1);
return NULL;
}
INIT(this,
.public = {
.get_count = _get_count,
.select_pcr = _select_pcr,
.get_selection_size = _get_selection_size,
.create_enumerator = _create_enumerator,
.get = _get,
.set = _set,
.extend = _extend,
.get_composite = _get_composite,
.destroy = _destroy,
},
.hasher = hasher,
);
for (i = 0; i < PTS_PCR_MAX_NUM; i++)
{
this->pcrs[i] = chunk_alloc(PTS_PCR_LEN);
memset(this->pcrs[i].ptr, 0x00, PTS_PCR_LEN);
}
return &this->public;
}
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2012 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 pts_pcr pts_pcr
* @{ @ingroup pts
*/
#ifndef PTS_PCR_H_
#define PTS_PCR_H_
typedef struct pts_pcr_t pts_pcr_t;
#include <library.h>
/**
* Maximum number of PCR's of TPM, TPM Spec 1.2
*/
#define PTS_PCR_MAX_NUM 24
/**
* Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2
*/
#define PTS_PCR_LEN 20
/**
* Class implementing a shadow PCR register set
*/
struct pts_pcr_t {
/**
* Get the number of selected PCRs
*
* @return number of selected PCRs
*/
u_int32_t (*get_count)(pts_pcr_t *this);
/**
* Mark a PCR as selected
*
* @param pcr index of PCR
* @return TRUE if PCR index exists
*/
bool (*select_pcr)(pts_pcr_t *this, u_int32_t pcr);
/**
* Get the size of the selection field in bytes
*
* @return number of bytes written
*/
size_t (*get_selection_size)(pts_pcr_t *this);
/**
* Create an enumerator over all selected PCR indexes
*
* @return enumerator
*/
enumerator_t* (*create_enumerator)(pts_pcr_t *this);
/**
* Get the current content of a PCR
*
* @param pcr index of PCR
* @return content of PCR
*/
chunk_t (*get)(pts_pcr_t *this, u_int32_t pcr);
/**
* Set the content of a PCR
*
* @param pcr index of PCR
* @param value new value of PCR
* @return TRUE if value could be set
*/
bool (*set)(pts_pcr_t *this, u_int32_t pcr, chunk_t value);
/**
* Extend the content of a PCR
*
* @param pcr index of PCR
* @param measurement measurment value to be extended into PCR
* @return new content of PCR
*/
chunk_t (*extend)(pts_pcr_t *this, u_int32_t pcr, chunk_t measurement);
/**
* Create a PCR Composite object over all selected PCRs
*
* @return PCR Composite object (must be freed)
*/
chunk_t (*get_composite)(pts_pcr_t *this);
/**
* Destroys a pts_pcr_t object.
*/
void (*destroy)(pts_pcr_t *this);
};
/**
* Creates an pts_pcr_t object
*/
pts_pcr_t* pts_pcr_create(void);
#endif /** PTS_PCR_H_ @}*/
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_proto_caps pts_proto_caps
* @{ @ingroup pts
*/
#ifndef PTS_PROTO_CAPS_H_
#define PTS_PROTO_CAPS_H_
typedef enum pts_proto_caps_flag_t pts_proto_caps_flag_t;
#include <library.h>
/**
* PTS Protocol Capabilities Flags
*/
enum pts_proto_caps_flag_t {
/** XML based Evidence Support flag */
PTS_PROTO_CAPS_X = (1<<0),
/** Trusted Platform Evidence flag */
PTS_PROTO_CAPS_T = (1<<1),
/** DH Nonce Negotiation Support flag */
PTS_PROTO_CAPS_D = (1<<2),
/** Verification Support flag */
PTS_PROTO_CAPS_V = (1<<3),
/** Current (In-Memory) Evidence Support flag */
PTS_PROTO_CAPS_C = (1<<4),
};
#endif /** PTS_PROTO_CAPS_H_ @}*/
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_req_func_comp_evid pts_req_func_comp_evid
* @{ @ingroup pts
*/
#ifndef PTS_REQ_FUNC_COMP_EVID_H_
#define PTS_REQ_FUNC_COMP_EVID_H_
typedef enum pts_req_func_comp_evid_t pts_req_func_comp_evid_t;
#include <library.h>
/**
* PTS Request Functional Component Evidence Flags
*/
enum pts_req_func_comp_evid_t {
/** Transitive Trust Chain flag */
PTS_REQ_FUNC_COMP_EVID_TTC = (1<<7),
/** Verify Component flag */
PTS_REQ_FUNC_COMP_EVID_VER = (1<<6),
/** Current Evidence flag */
PTS_REQ_FUNC_COMP_EVID_CURR = (1<<5),
/** PCR Information flag */
PTS_REQ_FUNC_COMP_EVID_PCR = (1<<4),
};
#endif /** PTS_FUNCT_COMP_EVID_REQ_H_ @}*/
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 pts_simple_evid_final pts_rsimple_evid_final
* @{ @ingroup pts
*/
#ifndef PTS_SIMPLE_EVID_FINAL_H_
#define PTS_SIMPLE_EVID_FINAL_H_
typedef enum pts_simple_evid_final_flag_t pts_simple_evid_final_flag_t;
#include <library.h>
/**
* PTS Simple Evidence Final Flags
*/
enum pts_simple_evid_final_flag_t {
/** TPM PCR Composite and TPM Quote Signature not included */
PTS_SIMPLE_EVID_FINAL_NO = 0x00,
/** TPM PCR Composite and TPM Quote Signature included
* using TPM_QUOTE_INFO */
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO = 0x40,
/** TPM PCR Composite and TPM Quote Signature included
* using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO not appended */
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 = 0x80,
/** TPM PCR Composite and TPM Quote Signature included
* using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO appended */
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER = 0xC0,
/** Evidence Signature included */
PTS_SIMPLE_EVID_FINAL_EVID_SIG = 0x20,
};
#endif /** PTS_SIMPLE_EVID_FINAL_H_ @}*/
+1 -2
View File
@@ -15,14 +15,13 @@
#include "seg_contract.h"
#include "seg_env.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include <utils/debug.h>
#include <bio/bio_writer.h>
#include <tncif_pa_subtypes.h>
#include <tcg/seg/tcg_seg_attr_seg_env.h>
typedef struct private_seg_contract_t private_seg_contract_t;
/**
+1 -2
View File
@@ -17,13 +17,12 @@
#include "imcv.h"
#include "pa_tnc/pa_tnc_msg.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include <utils/debug.h>
#include <bio/bio_reader.h>
#include <bio/bio_writer.h>
#include <tcg/seg/tcg_seg_attr_seg_env.h>
#define BASE_ATTR_ID_PREFIX 0xFF
typedef struct private_seg_env_t private_seg_env_t;
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* 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 "swid_error.h"
#include <bio/bio_writer.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
ENUM(swid_error_code_names, TCG_SWID_ERROR, TCG_SWID_RESPONSE_TOO_LARGE,
"SWID Error",
"SWID Subscription Denied",
"SWID Response Too Large"
);
/**
* Described in header.
*/
pa_tnc_attr_t* swid_error_create(swid_error_code_t code, u_int32_t request_id,
u_int32_t max_attr_size, char *description)
{
bio_writer_t *writer;
chunk_t msg_info;
pa_tnc_attr_t *attr;
pen_type_t error_code;
error_code = pen_type_create( PEN_TCG, code);
writer = bio_writer_create(4);
writer->write_uint32(writer, request_id);
if (code == TCG_SWID_RESPONSE_TOO_LARGE)
{
writer->write_uint32(writer, max_attr_size);
}
if (description)
{
writer->write_data(writer, chunk_from_str(description));
}
msg_info = writer->get_buf(writer);
attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
}
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <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 swid_error swid_error
* @{ @ingroup swid
*/
#ifndef SWID_ERROR_H_
#define SWID_ERROR_H_
typedef enum swid_error_code_t swid_error_code_t;
#include "pa_tnc/pa_tnc_attr.h"
#include <library.h>
/**
* SWID Error Codes
* see section 3.14.2 of PTS Protocol: Binding to TNC IF-M Specification
*/
enum swid_error_code_t {
TCG_SWID_ERROR = 0x20,
TCG_SWID_SUBSCRIPTION_DENIED = 0x21,
TCG_SWID_RESPONSE_TOO_LARGE = 0x22
};
/**
* enum name for swid_error_code_t.
*/
extern enum_name_t *swid_error_code_names;
/**
* Creates a SWID Error Attribute
* see section 4.12 of TNC SWID Message and Attributes for IF-M
*
* @param code SWID error code
* @param request SWID request ID
* @param max_attr_size Maximum IF-M attribute size (if applicable)
* @param description Optional description string or NULL
*/
pa_tnc_attr_t* swid_error_create(swid_error_code_t code, u_int32_t request,
u_int32_t max_attr_size, char *description);
#endif /** SWID_ERROR_H_ @}*/
+458
View File
@@ -0,0 +1,458 @@
/*
* Copyright (C) 2013-2014 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 "swid_inventory.h"
#include "swid_tag.h"
#include "swid_tag_id.h"
#include <collections/linked_list.h>
#include <bio/bio_writer.h>
#include <utils/debug.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <libgen.h>
#include <errno.h>
typedef struct private_swid_inventory_t private_swid_inventory_t;
/**
* Private data of a swid_inventory_t object.
*
*/
struct private_swid_inventory_t {
/**
* Public swid_inventory_t interface.
*/
swid_inventory_t public;
/**
* Full SWID tags or just SWID tag IDs
*/
bool full_tags;
/**
* List of SWID tags or tag IDs
*/
linked_list_t *list;
};
/**
* Read SWID tags issued by the swid_generator tool
*/
static status_t read_swid_tags(private_swid_inventory_t *this, FILE *file)
{
swid_tag_t *tag;
bio_writer_t *writer;
chunk_t tag_encoding, tag_file_path = chunk_empty;
bool more_tags = TRUE, last_newline, end_of_tag;
char line[8192];
size_t len;
while (more_tags)
{
last_newline = TRUE;
end_of_tag = FALSE;
writer = bio_writer_create(512);
do
{
if (!fgets(line, sizeof(line), file))
{
more_tags = FALSE;
end_of_tag = TRUE;
break;
}
len = strlen(line);
if (last_newline && line[0] == '\n')
{
end_of_tag = TRUE;
break;
}
else
{
last_newline = (line[len-1] == '\n');
writer->write_data(writer, chunk_create(line, len));
}
}
while (!end_of_tag);
tag_encoding = writer->get_buf(writer);
if (tag_encoding.len > 1)
{
/* remove trailing newline if present */
if (tag_encoding.ptr[tag_encoding.len - 1] == '\n')
{
tag_encoding.len--;
}
DBG3(DBG_IMC, " %.*s", tag_encoding.len, tag_encoding.ptr);
tag = swid_tag_create(tag_encoding, tag_file_path);
this->list->insert_last(this->list, tag);
}
writer->destroy(writer);
}
return SUCCESS;
}
/**
* Read SWID tag or software IDs issued by the swid_generator tool
*/
static status_t read_swid_tag_ids(private_swid_inventory_t *this, FILE *file)
{
swid_tag_id_t *tag_id;
chunk_t tag_creator, unique_sw_id, tag_file_path = chunk_empty;
char line[BUF_LEN];
while (TRUE)
{
char *separator;
size_t len;
if (!fgets(line, sizeof(line), file))
{
return SUCCESS;
}
len = strlen(line);
/* remove trailing newline if present */
if (len > 0 && line[len - 1] == '\n')
{
len--;
}
DBG3(DBG_IMC, " %.*s", len, line);
separator = strchr(line, '_');
if (!separator)
{
DBG1(DBG_IMC, "separation of regid from unique software ID failed");
return FAILED;
}
tag_creator = chunk_create(line, separator - line);
separator++;
unique_sw_id = chunk_create(separator, len - (separator - line));
tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
this->list->insert_last(this->list, tag_id);
}
}
static status_t generate_tags(private_swid_inventory_t *this, char *generator,
swid_inventory_t *targets, bool pretty, bool full)
{
FILE *file;
char command[BUF_LEN];
char doc_separator[] = "'\n\n'";
status_t status = SUCCESS;
if (targets->get_count(targets) == 0)
{
/* Assemble the SWID generator command */
if (this->full_tags)
{
snprintf(command, BUF_LEN, "%s swid --doc-separator %s%s%s",
generator, doc_separator, pretty ? " --pretty" : "",
full ? " --full" : "");
}
else
{
snprintf(command, BUF_LEN, "%s software-id", generator);
}
/* Open a pipe stream for reading the SWID generator output */
file = popen(command, "r");
if (!file)
{
DBG1(DBG_IMC, "failed to run swid_generator command");
return NOT_SUPPORTED;
}
if (this->full_tags)
{
DBG2(DBG_IMC, "SWID tag generation by package manager");
status = read_swid_tags(this, file);
}
else
{
DBG2(DBG_IMC, "SWID tag ID generation by package manager");
status = read_swid_tag_ids(this, file);
}
pclose(file);
}
else if (this->full_tags)
{
swid_tag_id_t *tag_id;
enumerator_t *enumerator;
enumerator = targets->create_enumerator(targets);
while (enumerator->enumerate(enumerator, &tag_id))
{
char software_id[BUF_LEN];
chunk_t tag_creator, unique_sw_id;
tag_creator = tag_id->get_tag_creator(tag_id);
unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
snprintf(software_id, BUF_LEN, "%.*s_%.*s",
tag_creator.len, tag_creator.ptr,
unique_sw_id.len, unique_sw_id.ptr);
/* Assemble the SWID generator command */
snprintf(command, BUF_LEN, "%s swid --software-id %s%s%s",
generator, software_id, pretty ? " --pretty" : "",
full ? " --full" : "");
/* Open a pipe stream for reading the SWID generator output */
file = popen(command, "r");
if (!file)
{
DBG1(DBG_IMC, "failed to run swid_generator command");
return NOT_SUPPORTED;
}
status = read_swid_tags(this, file);
pclose(file);
if (status != SUCCESS)
{
break;
}
}
enumerator->destroy(enumerator);
}
return status;
}
static bool collect_tags(private_swid_inventory_t *this, char *pathname,
swid_inventory_t *targets)
{
char *rel_name, *abs_name;
struct stat st;
bool success = FALSE;
enumerator_t *enumerator;
enumerator = enumerator_create_directory(pathname);
if (!enumerator)
{
DBG1(DBG_IMC, "directory '%s' can not be opened, %s",
pathname, strerror(errno));
return FALSE;
}
DBG2(DBG_IMC, "entering %s", pathname);
while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
{
char * start, *stop;
chunk_t tag_creator;
chunk_t unique_sw_id = chunk_empty, tag_file_path = chunk_empty;
if (!strstr(rel_name, "regid."))
{
continue;
}
if (S_ISDIR(st.st_mode))
{
/* In case of a targeted request */
if (targets->get_count(targets))
{
enumerator_t *target_enumerator;
swid_tag_id_t *tag_id;
bool match = FALSE;
target_enumerator = targets->create_enumerator(targets);
while (target_enumerator->enumerate(target_enumerator, &tag_id))
{
if (chunk_equals(tag_id->get_tag_creator(tag_id),
chunk_from_str(rel_name)))
{
match = TRUE;
break;
}
}
target_enumerator->destroy(target_enumerator);
if (!match)
{
continue;
}
}
if (!collect_tags(this, abs_name, targets))
{
goto end;
}
continue;
}
/* parse the regid filename into its components */
start = rel_name;
stop = strchr(start, '_');
if (!stop)
{
DBG1(DBG_IMC, " %s", rel_name);
DBG1(DBG_IMC, " '_' separator not found");
goto end;
}
tag_creator = chunk_create(start, stop-start);
start = stop + 1;
stop = strstr(start, ".swidtag");
if (!stop)
{
DBG1(DBG_IMC, " %s", rel_name);
DBG1(DBG_IMC, " swidtag postfix not found");
goto end;
}
unique_sw_id = chunk_create(start, stop-start);
tag_file_path = chunk_from_str(abs_name);
/* In case of a targeted request */
if (targets->get_count(targets))
{
chunk_t target_unique_sw_id, target_tag_creator;
enumerator_t *target_enumerator;
swid_tag_id_t *tag_id;
bool match = FALSE;
target_enumerator = targets->create_enumerator(targets);
while (target_enumerator->enumerate(target_enumerator, &tag_id))
{
target_unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
target_tag_creator = tag_id->get_tag_creator(tag_id);
if (chunk_equals(target_unique_sw_id, unique_sw_id) &&
chunk_equals(target_tag_creator, tag_creator))
{
match = TRUE;
break;
}
}
target_enumerator->destroy(target_enumerator);
if (!match)
{
continue;
}
}
DBG2(DBG_IMC, " %s", rel_name);
if (this->full_tags)
{
swid_tag_t *tag;
chunk_t *xml_tag;
xml_tag = chunk_map(abs_name, FALSE);
if (!xml_tag)
{
DBG1(DBG_IMC, " opening '%s' failed: %s", abs_name,
strerror(errno));
goto end;
}
tag = swid_tag_create(*xml_tag, tag_file_path);
this->list->insert_last(this->list, tag);
chunk_unmap(xml_tag);
}
else
{
swid_tag_id_t *tag_id;
tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path);
this->list->insert_last(this->list, tag_id);
}
}
success = TRUE;
end:
enumerator->destroy(enumerator);
DBG2(DBG_IMC, "leaving %s", pathname);
return success;
}
METHOD(swid_inventory_t, collect, bool,
private_swid_inventory_t *this, char *directory, char *generator,
swid_inventory_t *targets, bool pretty, bool full)
{
/**
* Tags are generated by a package manager
*/
generate_tags(this, generator, targets, pretty, full);
/**
* Collect swidtag files by iteratively entering all directories in
* the tree under the "directory" path.
*/
return collect_tags(this, directory, targets);
}
METHOD(swid_inventory_t, add, void,
private_swid_inventory_t *this, void *item)
{
this->list->insert_last(this->list, item);
}
METHOD(swid_inventory_t, get_count, int,
private_swid_inventory_t *this)
{
return this->list->get_count(this->list);
}
METHOD(swid_inventory_t, create_enumerator, enumerator_t*,
private_swid_inventory_t *this)
{
return this->list->create_enumerator(this->list);
}
METHOD(swid_inventory_t, destroy, void,
private_swid_inventory_t *this)
{
if (this->full_tags)
{
this->list->destroy_offset(this->list, offsetof(swid_tag_t, destroy));
}
else
{
this->list->destroy_offset(this->list, offsetof(swid_tag_id_t, destroy));
}
free(this);
}
/**
* See header
*/
swid_inventory_t *swid_inventory_create(bool full_tags)
{
private_swid_inventory_t *this;
INIT(this,
.public = {
.collect = _collect,
.add = _add,
.get_count = _get_count,
.create_enumerator = _create_enumerator,
.destroy = _destroy,
},
.full_tags = full_tags,
.list = linked_list_create(),
);
return &this->public;
}
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2013-2014 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 swid_inventory swid_inventory
* @{ @ingroup pts
*/
#ifndef SWID_INVENTORY_H_
#define SWID_INVENTORY_H_
#include <library.h>
typedef struct swid_inventory_t swid_inventory_t;
/**
* Class managing SWID tag inventory
*/
struct swid_inventory_t {
/**
* Collect the SWID tags stored on the endpoint
*
* @param directory SWID directory path
* @param generator Path to SWID generator
* @param targets List of target tag IDs
* @param pretty Generate indented XML SWID tags
* @param full Include file information in SWID tags
* @return TRUE if successful
*/
bool (*collect)(swid_inventory_t *this, char *directory, char *generator,
swid_inventory_t *targets, bool pretty, bool full);
/**
* Collect the SWID tags stored on the endpoint
*
* @param item SWID tag or tag ID to be added
*/
void (*add)(swid_inventory_t *this, void *item);
/**
* Get the number of collected SWID tags
*
* @return Number of collected SWID tags
*/
int (*get_count)(swid_inventory_t *this);
/**
* Create a SWID tag inventory enumerator
*
* @return Enumerator returning either tag ID or full tag
*/
enumerator_t* (*create_enumerator)(swid_inventory_t *this);
/**
* Destroys a swid_inventory_t object.
*/
void (*destroy)(swid_inventory_t *this);
};
/**
* Creates a swid_inventory_t object
*
* @param full_tags TRUE if full tags, FALSE if tag IDs only
*/
swid_inventory_t* swid_inventory_create(bool full_tags);
#endif /** SWID_INVENTORY_H_ @}*/

Some files were not shown because too many files have changed in this diff Show More