diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
commit | 81c63b0eed39432878f78727f60a1e7499645199 (patch) | |
tree | 82387d8fecd1c20788fd8bd784a9b0bde091fb6b /src/libpts | |
parent | c5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9 (diff) | |
download | vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.tar.gz vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.zip |
Imported Upstream version 5.2.0
Diffstat (limited to 'src/libpts')
57 files changed, 3308 insertions, 1626 deletions
diff --git a/src/libpts/Android.mk b/src/libpts/Android.mk new file mode 100644 index 000000000..ce328c52c --- /dev/null +++ b/src/libpts/Android.mk @@ -0,0 +1,78 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# copy-n-paste from Makefile.am +libpts_la_SOURCES := \ + libpts.h libpts.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 \ + 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,$(libpts_la_SOURCES)) + +# build libpts ----------------------------------------------------------------- + +LOCAL_C_INCLUDES += \ + $(strongswan_PATH)/src/libtncif \ + $(strongswan_PATH)/src/libimcv \ + $(strongswan_PATH)/src/libstrongswan + +LOCAL_CFLAGS := $(strongswan_CFLAGS) + +LOCAL_MODULE := libpts + +LOCAL_MODULE_TAGS := optional + +LOCAL_ARM_MODE := arm + +LOCAL_PRELINK_MODULE := false + +LOCAL_SHARED_LIBRARIES += libstrongswan libimcv + +include $(BUILD_SHARED_LIBRARY) diff --git a/src/libpts/Makefile.am b/src/libpts/Makefile.am index 48bb46c7a..ea685d837 100644 --- a/src/libpts/Makefile.am +++ b/src/libpts/Makefile.am @@ -13,6 +13,10 @@ libpts_la_LIBADD = \ $(top_builddir)/src/libtncif/libtncif.la \ $(top_builddir)/src/libimcv/libimcv.la +if USE_WINDOWS + libpts_la_LIBADD += -lws2_32 +endif + if USE_TROUSERS libpts_la_LIBADD += -ltspi endif @@ -31,6 +35,8 @@ libpts_la_SOURCES = \ 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 \ @@ -67,6 +73,8 @@ libpts_la_SOURCES = \ 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 +EXTRA_DIST = Android.mk + SUBDIRS = . if USE_IMC_ATTESTATION diff --git a/src/libpts/Makefile.in b/src/libpts/Makefile.in index af5eafd7f..405b5f7ce 100644 --- a/src/libpts/Makefile.in +++ b/src/libpts/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -78,11 +78,12 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@USE_TROUSERS_TRUE@am__append_1 = -ltspi -@USE_IMC_ATTESTATION_TRUE@am__append_2 = plugins/imc_attestation -@USE_IMV_ATTESTATION_TRUE@am__append_3 = plugins/imv_attestation -@USE_IMC_SWID_TRUE@am__append_4 = plugins/imc_swid -@USE_IMV_SWID_TRUE@am__append_5 = plugins/imv_swid +@USE_WINDOWS_TRUE@am__append_1 = -lws2_32 +@USE_TROUSERS_TRUE@am__append_2 = -ltspi +@USE_IMC_ATTESTATION_TRUE@am__append_3 = plugins/imc_attestation +@USE_IMV_ATTESTATION_TRUE@am__append_4 = plugins/imv_attestation +@USE_IMC_SWID_TRUE@am__append_5 = plugins/imc_swid +@USE_IMV_SWID_TRUE@am__append_6 = plugins/imv_swid subdir = src/libpts DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp @@ -136,12 +137,14 @@ am__DEPENDENCIES_1 = libpts_la_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(top_builddir)/src/libtncif/libtncif.la \ - $(top_builddir)/src/libimcv/libimcv.la $(am__DEPENDENCIES_1) + $(top_builddir)/src/libimcv/libimcv.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) am__dirstamp = $(am__leading_dot)dirstamp am_libpts_la_OBJECTS = libpts.lo pts/pts.lo pts/pts_error.lo \ pts/pts_pcr.lo pts/pts_creds.lo pts/pts_database.lo \ pts/pts_dh_group.lo pts/pts_file_meas.lo pts/pts_file_meta.lo \ - pts/pts_file_type.lo pts/pts_meas_algo.lo \ + pts/pts_file_type.lo pts/pts_ima_bios_list.lo \ + pts/pts_ima_event_list.lo pts/pts_meas_algo.lo \ pts/components/pts_component_manager.lo \ pts/components/pts_comp_evidence.lo \ pts/components/pts_comp_func_name.lo \ @@ -341,6 +344,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -359,6 +363,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ @@ -386,6 +391,7 @@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +aikgen_plugins = @aikgen_plugins@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -477,6 +483,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -498,7 +505,8 @@ AM_LDFLAGS = \ ipseclib_LTLIBRARIES = libpts.la libpts_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(top_builddir)/src/libtncif/libtncif.la \ - $(top_builddir)/src/libimcv/libimcv.la $(am__append_1) + $(top_builddir)/src/libimcv/libimcv.la $(am__append_1) \ + $(am__append_2) libpts_la_SOURCES = \ libpts.h libpts.c \ pts/pts.h pts/pts.c \ @@ -513,6 +521,8 @@ libpts_la_SOURCES = \ 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 \ @@ -549,8 +559,9 @@ libpts_la_SOURCES = \ 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 -SUBDIRS = . $(am__append_2) $(am__append_3) $(am__append_4) \ - $(am__append_5) +EXTRA_DIST = Android.mk +SUBDIRS = . $(am__append_3) $(am__append_4) $(am__append_5) \ + $(am__append_6) all: all-recursive .SUFFIXES: @@ -638,6 +649,10 @@ pts/pts_file_meta.lo: pts/$(am__dirstamp) \ pts/$(DEPDIR)/$(am__dirstamp) pts/pts_file_type.lo: pts/$(am__dirstamp) \ pts/$(DEPDIR)/$(am__dirstamp) +pts/pts_ima_bios_list.lo: pts/$(am__dirstamp) \ + pts/$(DEPDIR)/$(am__dirstamp) +pts/pts_ima_event_list.lo: pts/$(am__dirstamp) \ + pts/$(DEPDIR)/$(am__dirstamp) pts/pts_meas_algo.lo: pts/$(am__dirstamp) \ pts/$(DEPDIR)/$(am__dirstamp) pts/components/$(am__dirstamp): @@ -787,6 +802,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@pts/$(DEPDIR)/pts_file_meas.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@pts/$(DEPDIR)/pts_file_meta.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@pts/$(DEPDIR)/pts_file_type.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@pts/$(DEPDIR)/pts_ima_bios_list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@pts/$(DEPDIR)/pts_ima_event_list.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@pts/$(DEPDIR)/pts_meas_algo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@pts/$(DEPDIR)/pts_pcr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@pts/components/$(DEPDIR)/pts_comp_evidence.Plo@am__quote@ diff --git a/src/libpts/plugins/imc_attestation/Makefile.am b/src/libpts/plugins/imc_attestation/Makefile.am index 3f1b52a88..88d9ddd8b 100644 --- a/src/libpts/plugins/imc_attestation/Makefile.am +++ b/src/libpts/plugins/imc_attestation/Makefile.am @@ -5,7 +5,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libpts AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imc-attestation.la diff --git a/src/libpts/plugins/imc_attestation/Makefile.in b/src/libpts/plugins/imc_attestation/Makefile.in index dd347d2d8..1f12af63a 100644 --- a/src/libpts/plugins/imc_attestation/Makefile.in +++ b/src/libpts/plugins/imc_attestation/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -265,6 +265,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -283,6 +284,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ @@ -310,6 +312,7 @@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +aikgen_plugins = @aikgen_plugins@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -401,6 +404,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -418,7 +422,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libpts AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imc-attestation.la imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \ diff --git a/src/libpts/plugins/imc_attestation/imc_attestation.c b/src/libpts/plugins/imc_attestation/imc_attestation.c index c71b21666..74bbc468f 100644 --- a/src/libpts/plugins/imc_attestation/imc_attestation.c +++ b/src/libpts/plugins/imc_attestation/imc_attestation.c @@ -61,10 +61,10 @@ 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_Initialize(TNC_IMCID imc_id, - TNC_Version min_version, - TNC_Version max_version, - TNC_Version *actual_version) +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; @@ -103,9 +103,9 @@ TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, /** * 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) +TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) { imc_state_t *state; @@ -142,8 +142,8 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, /** * 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) +TNC_Result TNC_IMC_API TNC_IMC_BeginHandshake(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) { if (!imc_attestation) { @@ -228,11 +228,11 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) /** * 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) +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; @@ -259,15 +259,15 @@ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, /** * 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) +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; @@ -294,8 +294,8 @@ TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id, /** * 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) +TNC_Result TNC_IMC_API TNC_IMC_BatchEnding(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) { if (!imc_attestation) { @@ -308,7 +308,7 @@ TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, /** * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3 */ -TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) +TNC_Result TNC_IMC_API TNC_IMC_Terminate(TNC_IMCID imc_id) { if (!imc_attestation) { @@ -327,7 +327,7 @@ TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) /** * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3 */ -TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, +TNC_Result TNC_IMC_API TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, TNC_TNCC_BindFunctionPointer bind_function) { if (!imc_attestation) diff --git a/src/libpts/plugins/imc_swid/Makefile.am b/src/libpts/plugins/imc_swid/Makefile.am index d73c6d168..ddf596465 100644 --- a/src/libpts/plugins/imc_swid/Makefile.am +++ b/src/libpts/plugins/imc_swid/Makefile.am @@ -25,7 +25,7 @@ AM_CPPFLAGS = \ -DSWID_DIRECTORY=\"${prefix}/share\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imc-swid.la diff --git a/src/libpts/plugins/imc_swid/Makefile.in b/src/libpts/plugins/imc_swid/Makefile.in index 58402636f..6c3923ae2 100644 --- a/src/libpts/plugins/imc_swid/Makefile.in +++ b/src/libpts/plugins/imc_swid/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -265,6 +265,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -283,6 +284,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ @@ -310,6 +312,7 @@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +aikgen_plugins = @aikgen_plugins@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -401,6 +404,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -427,7 +431,7 @@ AM_CPPFLAGS = \ -DSWID_DIRECTORY=\"${prefix}/share\" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imc-swid.la imc_swid_la_LIBADD = \ diff --git a/src/libpts/plugins/imc_swid/imc_swid.c b/src/libpts/plugins/imc_swid/imc_swid.c index d4aaeff4d..ef3a6a3e3 100644 --- a/src/libpts/plugins/imc_swid/imc_swid.c +++ b/src/libpts/plugins/imc_swid/imc_swid.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -24,12 +24,15 @@ #include <imc/imc_agent.h> #include <imc/imc_msg.h> +#include <ita/ita_attr.h> +#include <ita/ita_attr_angel.h> #include <tncif_pa_subtypes.h> #include <pen/pen.h> #include <utils/debug.h> +#define SWID_GENERATOR "/usr/local/bin/swid_generator" /* IMC definitions */ @@ -128,12 +131,177 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, return TNC_RESULT_SUCCESS; } -static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) +/** + * 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) { - imc_msg_t *out_msg; + 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, tag_file_path; + + /* 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)) + { + tag_file_path = tag->get_tag_file_path(tag); + encoding = tag->get_encoding(tag); + entry_size = 2 + tag_file_path.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; + chunk_t tag_creator, unique_sw_id, tag_file_path; + + /* At least one TCG Tag ID Inventory attribute is sent */ + attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_ID_INV_MIN_SIZE; + 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)) + { + tag_creator = tag_id->get_tag_creator(tag_id); + unique_sw_id = tag_id->get_unique_sw_id(tag_id, &tag_file_path); + entry_size = 2 + tag_creator.len + 2 + unique_sw_id.len + + 2 + tag_file_path.len; + + 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 ID 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 ID Inventory attribute */ + attr_size = PA_TNC_ATTR_HEADER_SIZE + + TCG_SWID_TAG_ID_INV_MIN_SIZE; + attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1); + } + swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr; + swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id)); + attr_size += entry_size; + } + 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; @@ -145,18 +313,16 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) return result; } out_msg = imc_msg_create_as_reply(in_msg); - swid_state = (imc_swid_state_t*)state; /* analyze PA-TNC attributes */ enumerator = in_msg->create_attribute_enumerator(in_msg); while (enumerator->enumerate(enumerator, &attr)) { tcg_swid_attr_req_t *attr_req; - u_int8_t flags; - u_int32_t request_id, eid_epoch; - swid_inventory_t *swid_inventory, *targets; - char *swid_directory; + uint8_t flags; + uint32_t request_id; bool full_tags; + swid_inventory_t *targets; type = attr->get_type(attr); @@ -169,7 +335,6 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) flags = attr_req->get_flags(attr_req); request_id = attr_req->get_request_id(attr_req); targets = attr_req->get_targets(attr_req); - eid_epoch = swid_state->get_eid_epoch(swid_state); if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C)) { @@ -180,33 +345,10 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) } full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0; - swid_directory = lib->settings->get_str(lib->settings, - "%s.plugins.imc-swid.swid_directory", - SWID_DIRECTORY, lib->ns); - swid_inventory = swid_inventory_create(full_tags); - if (!swid_inventory->collect(swid_inventory, swid_directory, targets)) + if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets)) { - swid_inventory->destroy(swid_inventory); - attr = swid_error_create(TCG_SWID_ERROR, request_id, - 0, "error in SWID tag collection"); - out_msg->add_attribute(out_msg, attr); break; } - 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"); - - if (full_tags) - { - attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1, - swid_inventory); - } - else - { - attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1, - swid_inventory); - } - out_msg->add_attribute(out_msg, attr); } enumerator->destroy(enumerator); diff --git a/src/libpts/plugins/imc_swid/regid.2004-03.org.strongswan_strongSwan.swidtag.in b/src/libpts/plugins/imc_swid/regid.2004-03.org.strongswan_strongSwan.swidtag.in index 6945d8769..8b7b50fdf 100644 --- a/src/libpts/plugins/imc_swid/regid.2004-03.org.strongswan_strongSwan.swidtag.in +++ b/src/libpts/plugins/imc_swid/regid.2004-03.org.strongswan_strongSwan.swidtag.in @@ -1,30 +1,12 @@ <?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>strongSwan</product_title> - <product_version> - <name>@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_BUILD@@VERSION_REVIEW@</name> - <numeric> - <major>@VERSION_MAJOR@</major> - <minor>@VERSION_MINOR@</minor> - <build>@VERSION_BUILD@</build> - <review>@VERSION_REVIEW@</review> - </numeric> - </product_version> - <software_creator> - <name>strongSwan Project</name> - <regid>regid.2004-03.org.strongswan</regid> - </software_creator> - <software_licensor> - <name>strongSwan Project</name> - <regid>regid.2004-03.org.strongswan</regid> - </software_licensor> - <software_id> - <unique_id>strongSwan-@VERSION_MAJOR@-@VERSION_MINOR@-@VERSION_BUILD@@VERSION_REVIEW@</unique_id> - <tag_creator_regid>regid.2004-03.org.strongswan</tag_creator_regid> - </software_id> - <tag_creator> - <name>strongSwan Project</name> - <regid>regid.2004-03.org.strongswan</regid> - </tag_creator> -</software_identification_tag> + +<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> diff --git a/src/libpts/plugins/imv_attestation/Makefile.am b/src/libpts/plugins/imv_attestation/Makefile.am index 8d18f1404..8dc74fd54 100644 --- a/src/libpts/plugins/imv_attestation/Makefile.am +++ b/src/libpts/plugins/imv_attestation/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS = \ -DPLUGINS=\""${attest_plugins}\"" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imv-attestation.la diff --git a/src/libpts/plugins/imv_attestation/Makefile.in b/src/libpts/plugins/imv_attestation/Makefile.in index ff94363bf..b0e3787ae 100644 --- a/src/libpts/plugins/imv_attestation/Makefile.in +++ b/src/libpts/plugins/imv_attestation/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -275,6 +275,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -293,6 +294,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ @@ -320,6 +322,7 @@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +aikgen_plugins = @aikgen_plugins@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -411,6 +414,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -429,7 +433,7 @@ AM_CPPFLAGS = \ -DPLUGINS=\""${attest_plugins}\"" AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imv-attestation.la imv_attestation_la_LIBADD = \ diff --git a/src/libpts/plugins/imv_attestation/attest.c b/src/libpts/plugins/imv_attestation/attest.c index 8f4df39e7..63c0023a7 100644 --- a/src/libpts/plugins/imv_attestation/attest.c +++ b/src/libpts/plugins/imv_attestation/attest.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -19,8 +19,10 @@ #include <stdio.h> #include <string.h> #include <errno.h> -#include <syslog.h> #include <libgen.h> +#ifdef HAVE_SYSLOG +# include <syslog.h> +#endif #include <library.h> #include <utils/debug.h> @@ -43,9 +45,6 @@ static bool stderr_quiet = TRUE; */ static void attest_dbg(debug_t group, level_t level, char *fmt, ...) { - int priority = LOG_INFO; - char buffer[8192]; - char *current = buffer, *next; va_list args; if (level <= debug_level) @@ -58,22 +57,30 @@ static void attest_dbg(debug_t group, level_t level, char *fmt, ...) va_end(args); } - /* 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) +#ifdef HAVE_SYSLOG { - next = strchr(current, '\n'); - if (next) + 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++) = '\0'; + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + syslog(priority, "%s\n", current); + current = next; } - syslog(priority, "%s\n", current); - current = next; } +#endif /* HAVE_SYSLOG */ } } @@ -91,7 +98,9 @@ static void cleanup(void) attest->destroy(attest); libpts_deinit(); libimcv_deinit(); +#ifdef HAVE_SYSLOG closelog(); +#endif } static void do_args(int argc, char *argv[]) @@ -144,9 +153,9 @@ static void do_args(int argc, char *argv[]) { "directory", required_argument, NULL, 'D' }, { "dir", required_argument, NULL, 'D' }, { "file", required_argument, NULL, 'F' }, - { "sha1-ima", no_argument, NULL, 'I' }, { "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' }, @@ -294,9 +303,6 @@ static void do_args(int argc, char *argv[]) exit(EXIT_FAILURE); } continue; - case 'I': - attest->set_algo(attest, PTS_MEAS_ALGO_SHA1_IMA); - continue; case 'K': { chunk_t aik; @@ -308,6 +314,12 @@ static void do_args(int argc, char *argv[]) } continue; } + case 'M': + if (!attest->set_meas_directory(attest, optarg)) + { + exit(EXIT_FAILURE); + } + continue; case 'O': attest->set_owner(attest, optarg); continue; @@ -437,7 +449,9 @@ int main(int argc, char *argv[]) /* enable attest debugging hook */ dbg = attest_dbg; +#ifdef HAVE_SYSLOG openlog("attest", 0, LOG_DEBUG); +#endif atexit(library_deinit); @@ -471,4 +485,3 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); } - diff --git a/src/libpts/plugins/imv_attestation/attest_db.c b/src/libpts/plugins/imv_attestation/attest_db.c index 7a8a1135a..d7f45ad29 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.c +++ b/src/libpts/plugins/imv_attestation/attest_db.c @@ -79,6 +79,11 @@ struct private_attest_db_t { int fid; /** + * Directory where file measurement are to be taken + */ + char *meas_dir; + + /** * AIK to be queried */ chunk_t key; @@ -193,6 +198,21 @@ char* print_cfn(pts_comp_func_name_t *cfn) return buf; } +/** + * Get the directory separator to append to a path + */ +static const char* get_separator(const char *path) +{ + if (streq(path, DIRECTORY_SEPARATOR)) + { /* root directory on Unix file system, no separator */ + return ""; + } + else + { /* non-root or Windows path, use system specific separator */ + return DIRECTORY_SEPARATOR; + } +} + METHOD(attest_db_t, set_component, bool, private_attest_db_t *this, char *comp, bool create) { @@ -309,9 +329,9 @@ METHOD(attest_db_t, set_directory, bool, return FALSE; } - /* remove trailing '/' character if not root directory */ + /* remove trailing '/' or '\' character if not root directory */ len = strlen(dir); - if (len > 1 && dir[len-1] == '/') + if (len > 1 && dir[len-1] == DIRECTORY_SEPARATOR[0]) { dir[len-1] = '\0'; } @@ -385,7 +405,6 @@ METHOD(attest_db_t, set_file, bool, private_attest_db_t *this, char *file, bool create) { int fid; - char *sep; enumerator_t *e; if (this->file) @@ -399,7 +418,6 @@ METHOD(attest_db_t, set_file, bool, { return TRUE; } - sep = streq(this->dir, "/") ? "" : "/"; e = this->db->query(this->db, "SELECT id FROM files " "WHERE dir = ? AND name = ?", DB_INT, this->did, DB_TEXT, file, DB_INT); @@ -418,7 +436,8 @@ METHOD(attest_db_t, set_file, bool, if (!create) { - printf("file '%s%s%s' not found in database\n", this->dir, sep, file); + printf("file '%s%s%s' not found in database\n", + this->dir, get_separator(this->dir), file); return FALSE; } @@ -429,8 +448,8 @@ METHOD(attest_db_t, set_file, bool, { this->fid = fid; } - printf("file '%s%s%s' %sinserted into database\n", this->dir, sep, file, - this->fid ? "" : "could not be "); + printf("file '%s%s%s' %sinserted into database\n", this->dir, + get_separator(this->dir), file, this->fid ? "" : "could not be "); return this->fid > 0; } @@ -470,6 +489,22 @@ METHOD(attest_db_t, set_fid, bool, return this->fid > 0; } +METHOD(attest_db_t, set_meas_directory, bool, + private_attest_db_t *this, char *dir) +{ + size_t len; + + /* remove trailing '/' character if not root directory */ + len = strlen(dir); + if (len > 1 && dir[len-1] == '/') + { + dir[len-1] = '\0'; + } + this->meas_dir = strdup(dir); + + return TRUE; +} + METHOD(attest_db_t, set_key, bool, private_attest_db_t *this, chunk_t key, bool create) { @@ -1297,7 +1332,7 @@ METHOD(attest_db_t, list_hashes, void, printf("%d %N value%s found for file '%s%s%s'\n", count, pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", this->dir, - streq(this->dir, "/") ? "" : "/", this->file); + get_separator(this->dir), this->file); } } else if (this->file) @@ -1568,12 +1603,13 @@ METHOD(attest_db_t, list_sessions, void, */ static bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo, - chunk_t measurement, int fid, bool ima, + chunk_t measurement, int fid, int *hashes_added, int *hashes_updated) { enumerator_t *e; chunk_t hash; char *label; + bool insert = TRUE, update = FALSE; label = "could not be created"; @@ -1581,46 +1617,50 @@ static bool insert_file_hash(private_attest_db_t *this, "SELECT hash FROM file_hashes WHERE algo = ? " "AND file = ? AND product = ? AND device = 0", DB_INT, algo, DB_UINT, fid, DB_UINT, this->pid, DB_BLOB); + if (!e) { printf("file_hashes query failed\n"); return FALSE; } - if (e->enumerate(e, &hash)) + + while (e->enumerate(e, &hash)) { + update = TRUE; + if (chunk_equals(measurement, hash)) { label = "exists and equals"; - } - else - { - if (this->db->execute(this->db, NULL, - "UPDATE file_hashes SET hash = ? WHERE algo = ? " - "AND file = ? AND product = ? and device = 0", - DB_BLOB, measurement, DB_INT, algo, DB_UINT, fid, - DB_UINT, this->pid) == 1) - { - label = "updated"; - (*hashes_updated)++; - } + insert = FALSE; + break; } } - else + e->destroy(e); + + if (insert) { if (this->db->execute(this->db, NULL, "INSERT INTO file_hashes " "(file, product, device, algo, hash) " "VALUES (?, ?, 0, ?, ?)", DB_UINT, fid, DB_UINT, this->pid, - DB_INT, algo, DB_BLOB, measurement) == 1) + DB_INT, algo, DB_BLOB, measurement) != 1) + { + printf("file_hash insertion failed\n"); + return FALSE; + } + if (update) + { + label = "updated"; + (*hashes_updated)++; + } + else { label = "created"; (*hashes_added)++; } } - e->destroy(e); - - printf(" %#B - %s%s\n", &measurement, ima ? "ima - " : "", label); + printf(" %#B - %s\n", &measurement, label); return TRUE; } @@ -1629,33 +1669,24 @@ static bool insert_file_hash(private_attest_db_t *this, */ static bool add_hash(private_attest_db_t *this) { - char *pathname, *filename, *sep, *label, *pos; - char ima_buffer[IMA_MAX_NAME_LEN + 1]; - chunk_t measurement, ima_template; + char *pathname, *filename, *label; + const char *sep; pts_file_meas_t *measurements; + chunk_t measurement; hasher_t *hasher = NULL; - bool ima = FALSE; int fid, files_added = 0, hashes_added = 0, hashes_updated = 0; - int len, ima_hashes_added = 0, ima_hashes_updated = 0; enumerator_t *enumerator, *e; - if (this->algo == PTS_MEAS_ALGO_SHA1_IMA) + if (!this->meas_dir) { - ima = TRUE; - this->algo = PTS_MEAS_ALGO_SHA1; - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) - { - printf("could not create hasher\n"); - return FALSE; - } + this->meas_dir = strdup(this->dir); } - sep = streq(this->dir, "/") ? "" : "/"; + sep = get_separator(this->meas_dir); if (this->fid) { /* build pathname from directory path and relative filename */ - if (asprintf(&pathname, "%s%s%s", this->dir, sep, this->file) == -1) + if (asprintf(&pathname, "%s%s%s", this->meas_dir, sep, this->file) == -1) { return FALSE; } @@ -1665,7 +1696,7 @@ static bool add_hash(private_attest_db_t *this) } else { - measurements = pts_file_meas_create_from_path(0, this->dir, TRUE, + measurements = pts_file_meas_create_from_path(0, this->meas_dir, TRUE, TRUE, this->algo); } if (!measurements) @@ -1717,59 +1748,18 @@ static bool add_hash(private_attest_db_t *this) printf("%4d: %s - %s\n", fid, filename, label); /* compute file measurement hash */ - if (!insert_file_hash(this, this->algo, measurement, fid, FALSE, + if (!insert_file_hash(this, this->algo, measurement, fid, &hashes_added, &hashes_updated)) { break; } - if (!ima) - { - continue; - } - - /* compute IMA template hash */ - pos = ima_buffer; - len = IMA_MAX_NAME_LEN; - if (!this->relative) - { - strncpy(pos, this->dir, len); - len = max(0, len - strlen(this->dir)); - pos = ima_buffer + IMA_MAX_NAME_LEN - len; - strncpy(pos, sep, len); - len = max(0, len - strlen(sep)); - pos = ima_buffer + IMA_MAX_NAME_LEN - len; - } - strncpy(pos, filename, len); - ima_buffer[IMA_MAX_NAME_LEN] = '\0'; - ima_template = chunk_create(ima_buffer, sizeof(ima_buffer)); - if (!hasher->get_hash(hasher, measurement, NULL) || - !hasher->get_hash(hasher, ima_template, measurement.ptr)) - { - printf("could not compute IMA template hash\n"); - break; - } - if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA, measurement, fid, - TRUE, &ima_hashes_added, &ima_hashes_updated)) - { - break; - } } enumerator->destroy(enumerator); - printf("%d measurements, added %d new files, %d file hashes", - measurements->get_file_count(measurements), files_added, - hashes_added); - if (ima) - { - printf(", %d ima hashes", ima_hashes_added); - hasher->destroy(hasher); - } - printf(", updated %d file hashes", hashes_updated); - if (ima) - { - printf(", %d ima hashes", ima_hashes_updated); - } - printf("\n"); + printf("%d measurements, added %d new files, %d file hashes, " + "updated %d file hashes\n", + measurements->get_file_count(measurements), + files_added, hashes_added, hashes_updated); measurements->destroy(measurements); return TRUE; @@ -1780,22 +1770,6 @@ METHOD(attest_db_t, add, bool, { bool success = FALSE; - /* add key/component pair */ - if (this->kid && this->cid) - { - success = this->db->execute(this->db, NULL, - "INSERT INTO key_component (key, component, seq_no) " - "VALUES (?, ?, ?)", - DB_UINT, this->kid, DB_UINT, this->cid, - DB_UINT, this->seq_no) == 1; - - printf("key/component pair (%d/%d) %sinserted into database at " - "position %d\n", this->kid, this->cid, - success ? "" : "could not be ", this->seq_no); - - return success; - } - /* add directory or file hash measurement for a given product */ if (this->did && this->pid) { @@ -1844,8 +1818,8 @@ METHOD(attest_db_t, delete, bool, DB_UINT, this->algo, DB_UINT, this->pid, DB_UINT, this->fid) > 0; - printf("%4d: %s%s%s\n", this->fid, this->dir, - streq(this->dir, "/") ? "" : "/", this->file); + printf("%4d: %s%s%s\n", this->fid, this->dir, get_separator(this->dir), + this->file); printf("%N value for product '%s' %sdeleted from database\n", pts_meas_algorithm_names, this->algo, this->product, success ? "" : "could not be "); @@ -1869,19 +1843,6 @@ METHOD(attest_db_t, delete, bool, return success; } - /* delete key/component pair */ - if (this->kid && this->cid) - { - success = this->db->execute(this->db, NULL, - "DELETE FROM key_component " - "WHERE key = ? AND component = ?", - DB_UINT, this->kid, DB_UINT, this->cid) > 0; - - printf("key/component pair (%d/%d) %sdeleted from database\n", - this->kid, this->cid, success ? "" : "could not be "); - return success; - } - if (this->cid) { success = this->db->execute(this->db, NULL, @@ -1900,7 +1861,7 @@ METHOD(attest_db_t, delete, bool, DB_UINT, this->fid) > 0; printf("file '%s%s%s' %sdeleted from database\n", this->dir, - streq(this->dir, "/") ? "" : "/", this->file, + get_separator(this->dir), this->file, success ? "" : "could not be "); return success; } @@ -1970,6 +1931,7 @@ METHOD(attest_db_t, destroy, void, free(this->version); free(this->file); free(this->dir); + free(this->meas_dir); free(this->owner); free(this->key.ptr); free(this); @@ -1990,6 +1952,7 @@ attest_db_t *attest_db_create(char *uri) .set_did = _set_did, .set_file = _set_file, .set_fid = _set_fid, + .set_meas_directory = _set_meas_directory, .set_key = _set_key, .set_kid = _set_kid, .set_package = _set_package, diff --git a/src/libpts/plugins/imv_attestation/attest_db.h b/src/libpts/plugins/imv_attestation/attest_db.h index d0a48d844..07e55cce7 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.h +++ b/src/libpts/plugins/imv_attestation/attest_db.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -84,6 +84,14 @@ struct attest_db_t { 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 diff --git a/src/libpts/plugins/imv_attestation/build-database.sh b/src/libpts/plugins/imv_attestation/build-database.sh index be1024de0..f16b5d152 100755 --- a/src/libpts/plugins/imv_attestation/build-database.sh +++ b/src/libpts/plugins/imv_attestation/build-database.sh @@ -1,221 +1,84 @@ #!/bin/sh -p="Ubuntu 12.04 i686" +p="Ubuntu 14.04 x86_64" +a="x86_64-linux-gnu" +k="3.13.0-30-generic" -ipsec attest --add --product "$p" --sha1-ima --dir /sbin -ipsec attest --add --product "$p" --sha1-ima --dir /usr/sbin -ipsec attest --add --product "$p" --sha1-ima --dir /bin -ipsec attest --add --product "$p" --sha1-ima --dir /usr/bin -ipsec attest --add --product "$p" --sha1-ima --dir /etc/acpi -ipsec attest --add --product "$p" --sha1-ima --file /etc/init.d/rc -ipsec attest --add --product "$p" --sha1-ima --file /etc/init.d/rcS -ipsec attest --add --product "$p" --sha1-ima --dir /etc/network/if-post-down.d -ipsec attest --add --product "$p" --sha1-ima --dir /etc/network/if-pre-up.d -ipsec attest --add --product "$p" --sha1-ima --dir /etc/network/if-up.d -ipsec attest --add --product "$p" --sha1-ima --file /etc/NetworkManager/dispatcher.d/01ifupdown -ipsec attest --add --product "$p" --sha1-ima --dir /etc/ppp/ip-down.d -ipsec attest --add --product "$p" --sha1-ima --dir /etc/rc2.d -ipsec attest --add --product "$p" --sha1-ima --dir /etc/rcS.d -ipsec attest --add --product "$p" --sha1-ima --file /etc/rc.local -ipsec attest --add --product "$p" --sha1-ima --dir /etc/resolvconf/update.d -ipsec attest --add --product "$p" --sha1-ima --file /etc/resolvconf/update-libc.d/avahi-daemon -ipsec attest --add --product "$p" --sha1-ima --dir /etc/update-motd.d -ipsec attest --add --product "$p" --sha1-ima --file /lib/crda/setregdomain -ipsec attest --add --product "$p" --sha1-ima --file /lib/init/apparmor-profile-load -ipsec attest --add --product "$p" --sha1-ima --file /lib/resolvconf/list-records -ipsec attest --add --product "$p" --sha1-ima --dir /lib/udev -ipsec attest --add --product "$p" --sha1-ima --file /lib/ufw/ufw-init -ipsec attest --add --product "$p" --sha1-ima --file /opt/Adobe/Reader9/Reader/intellinux/bin/acroread -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/accountsservice/accounts-daemon -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/apt/methods -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/at-spi2-core -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/avahi/avahi-daemon-check-dns.sh -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/bamf/bamfdaemon -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ConsoleKit -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ConsoleKit/run-seat.d -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ConsoleKit/run-session.d -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/cups/notifier -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/dconf/dconf-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/dbus-1.0/dbus-daemon-launch-helper -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/deja-dup/deja-dup/deja-dup-monitor -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/evolution/3.2/evolution-alarm-notify -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/firefox/firefox -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/firefox/plugin-container -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gcc/i686-linux-gnu/4.6/cc1 -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gcc/i686-linux-gnu/4.6/collect2 -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/geoclue/geoclue-master -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/git-core -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-desktop3/check_gl_texture_size -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-disk-utility/gdu-notification-daemon -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-online-accounts/goa-daemon -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/gnome-settings-daemon -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-user-share/gnome-user-share -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-screensaver/gnome-screensaver-dialog -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/gvfs -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gvfs//gvfs-fuse-daemon -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/i386-linux-gnu/colord/colord -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/i386-linux-gnu/gconf -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-application/indicator-application-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-appmenu/hud-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-datetime/indicator-datetime-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-messages/indicator-messages-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-printers/indicator-printers-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-session/indicator-session-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-sound/indicator-sound-service -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/lightdm -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/NetworkManager/nm-dhcp-client.action -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/NetworkManager/nm-dispatcher.action -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/notify-osd/notify-osd -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/nux/unity_support_test -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/pm-utils/power.d -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/pm-utils/sleep.d -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/policykit-1/polkitd -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/pulseaudio/pulse/gconf-helper -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/rtkit/rtkit-daemon -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/system-service/system-service-d -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/telepathy/mission-control-5 -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/thunderbird/thunderbird -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ubuntuone-client -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/ubuntu-geoip/ubuntu-geoip-provider -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ubuntu-sso-client -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/udisks -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity/unity-panel-service -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-lens-applications/unity-applications-daemon -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-lens-files/unity-files-daemon -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/unity-lens-music -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-lens-video/unity-lens-video -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-scope-video-remote/unity-scope-video-remote -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/update-manager/release-upgrade-motd -ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/update-notifier -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/upower/upowerd -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/libvte-2.90-9/gnome-pty-helper -ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/zeitgeist/zeitgeist-fts -ipsec attest --add --product "$p" --sha1-ima --file /usr/share/apport/apport -ipsec attest --add --product "$p" --sha1-ima --file /usr/share/apport/apport-checkreports -ipsec attest --add --product "$p" --sha1-ima --file /usr/share/apport/apport-gtk -ipsec attest --add --product "$p" --sha1-ima --dir /usr/share/language-tools -ipsec attest --add --product "$p" --sha1-ima --file /usr/share/virtualbox/VBoxCreateUSBNode.sh -ipsec attest --add --product "$p" --sha1-ima --relative --file /etc/ld.so.cache -ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib -ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/i386-linux-gnu -ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/i386-linux-gnu/security -for file in `find /lib/modules/3.2.21ima/kernel -name *.ko` +for hash in sha1 sha256 do -ipsec attest --add --product "$p" --sha1-ima --relative --file $file -done -ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/plymouth -ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/plymouth/renderers -ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/security -ipsec attest --add --product "$p" --sha1-ima --relative --dir /opt/Adobe/Reader9/Reader/intellinux/lib -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/apache2/modules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/compiz -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/compizconfig/backends/ -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/enchant -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/evolution/3.2/libemiscwidgets.so.0.0.0 -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/evolution/3.2/libeutil.so.0.0.0 -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/evolution/3.2/libgnomecanvas.so.0.0.0 -for file in /usr/lib/firefox/*.so -do -ipsec attest --add --product "$p" --sha1-ima --relative --file $file -done -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox/components/libbrowsercomps.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox/components/libdbusservice.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox/components/libmozgnome.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox-addons/extensions/globalmenu@ubuntu.com/components/libglobalmenu.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox-addons/plugins/nppdf.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/flashplugin-installer/libflashplayer.so -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gedit/plugins -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gnome-bluetooth -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gnome-settings-daemon-3.0 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gtk-2.0/2.10.0/menuproxies -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gtk-3.0/3.0.0/menuproxies -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gtk-3.0/3.0.0/theming-engines -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/alsa-lib -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/dri -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gconf/2 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gconv -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gio/modules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-2.0/modules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-2.0/2.10.0/engines -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-2.0/2.10.0/immodules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-3.0/modules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-3.0/3.0.0/immodules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gvfs -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/libcanberra-0.28 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/mesa -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/mit-krb5 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/openssl-1.0.0/engines -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/pango/1.6.0/modules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/pkcs11 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/polkit-1/extensions -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/nss -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/sane -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/sse2 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/indicators3/7 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/indicator-messages/status-providers/1 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/libpeas-1.0/loaders -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/man-db/libman-2.6.1.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/man-db/libmandb-2.6.1.so -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/mission-control-plugins.0 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/ModemManager -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/nautilus/extensions-3.0 -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/NetworkManager/libnm-settings-plugin-ifupdown.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/perl/5.14.2/auto/File/Glob/Glob.so -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/pulse-1.1/modules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/python2.7/lib-dynload -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/apt_inst.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/apt_pkg.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/cairo/_cairo.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/dbus/mainloop/qt.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/_dbus_bindings.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/_dbus_glib_bindings.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/duplicity/_librsync.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gi/_gi.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gi/_gobject/_gobject.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gi/_glib/_glib.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/glib/_glib.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gobject/_gobject.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/atk.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/gtk/_gtk.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/gio/_gio.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/gio/unix.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/pango.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/pangocairo.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/pynotify/_pynotify.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/OpenSSL/crypto.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/OpenSSL/rand.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/OpenSSL/SSL.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/PyQt4/QtCore.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/simplejson/_speedups.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/sip.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/twisted/internet/_sigchld.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/twisted/python/_initgroups.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/xapian/_xapian.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/zope/interface/_zope_interface_coptimizations.so -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/rsyslog -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/sane -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/sse2 -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/sudo -for file in /usr/lib/thunderbird/*.so -do -ipsec attest --add --product "$p" --sha1-ima --relative --file $file + 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 -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/thunderbird/components/libdbusservice.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/thunderbird/components/libmozgnome.so -ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/thunderbird-addons/extensions/globalmenu@ubuntu.com/components/libglobalmenu.so -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules/drivers -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules/extensions -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules/input -ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/share/fonts/truetype/ubuntu-font-family -ipsec attest --del --product "$p" --sha1 --file /lib/resolvconf/list-records -ipsec attest --del --product "$p" --sha1-ima --file /lib/resolvconf/list-records -ipsec attest --del --product "$p" --sha1 --file /usr/bin/lsb_release -ipsec attest --del --product "$p" --sha1-ima --file /usr/bin/lsb_release -ipsec attest --del --product "$p" --sha1 --file /usr/share/language-tools/language-options -ipsec attest --del --product "$p" --sha1-ima --file /usr/share/language-tools/language-options diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_agent.c b/src/libpts/plugins/imv_attestation/imv_attestation_agent.c index ae2660bae..fcfee31c1 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_agent.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_agent.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011-2012 Sansar Choinyambuu - * Copyright (C) 2011-2013 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -25,11 +25,15 @@ #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 <libpts.h> @@ -111,7 +115,9 @@ 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) { @@ -120,6 +126,35 @@ METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, 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); } @@ -131,15 +166,14 @@ METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, static TNC_Result receive_msg(private_imv_attestation_agent_t *this, imv_state_t *state, imv_msg_t *in_msg) { - imv_attestation_state_t *attestation_state; imv_msg_t *out_msg; + 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; - pts_t *pts; - chunk_t os_name = chunk_empty; - chunk_t os_version = chunk_empty; + chunk_t os_name, os_version; bool fatal_error = FALSE; /* parse received PA-TNC message and handle local and remote errors */ @@ -149,8 +183,8 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this, return result; } - attestation_state = (imv_attestation_state_t*)state; - pts = attestation_state->get_pts(attestation_state); + session = state->get_session(state); + os_info = session->get_os_info(session); out_msg = imv_msg_create_as_reply(in_msg); out_msg->set_msg_type(out_msg, msg_types[0]); @@ -188,17 +222,64 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this, 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, NULL, NULL); + 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: @@ -218,15 +299,6 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this, } enumerator->destroy(enumerator); - /** - * The IETF Product Information and String Version attributes - * are supposed to arrive in the same PA-TNC message - */ - if (os_name.len && os_version.len) - { - pts->set_platform_info(pts, os_name, os_version); - } - if (fatal_error || result != TNC_RESULT_SUCCESS) { state->set_recommendation(state, @@ -288,6 +360,31 @@ METHOD(imv_agent_if_t, receive_message_long, TNC_Result, 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) { @@ -302,7 +399,8 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, TNC_IMVID imv_id; TNC_Result result = TNC_RESULT_SUCCESS; pts_t *pts; - char *platform_info; + int pid; + uint32_t actions; enumerator_t *enumerator; if (!this->agent->get_state(this->agent, id, &state)) @@ -312,40 +410,59 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, attestation_state = (imv_attestation_state_t*)state; pts = attestation_state->get_pts(attestation_state); handshake_state = attestation_state->get_handshake_state(attestation_state); - platform_info = pts->get_platform_info(pts); + 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 (state->get_action_flags(state) & IMV_ATTESTATION_FLAG_REC) + if (actions & IMV_ATTESTATION_REC) { return TNC_RESULT_SUCCESS; } /* send an IETF attribute request if no platform info was received */ - if (!platform_info && - !(state->get_action_flags(state) & IMV_ATTESTATION_FLAG_ATTR_REQ)) + if (!(actions & IMV_ATTESTATION_ATTR_REQ)) { - pa_tnc_attr_t *attr; - ietf_attr_attr_request_t *attr_cast; - imv_msg_t *os_msg; + if ((actions & IMV_ATTESTATION_ATTR_MUST) != IMV_ATTESTATION_ATTR_MUST) + { + imv_msg_t *os_msg; - attr = ietf_attr_attr_request_create(PEN_IETF, - IETF_ATTR_PRODUCT_INFORMATION); - attr_cast = (ietf_attr_attr_request_t*)attr; - attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION); + /* 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); - os_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY, - msg_types[1]); - os_msg->add_attribute(os_msg, attr); - 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 (result != TNC_RESULT_SUCCESS) + 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) { - return result; + /* 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); } - state->set_action_flags(state, IMV_ATTESTATION_FLAG_ATTR_REQ); } if (handshake_state == IMV_ATTESTATION_STATE_INIT) @@ -378,22 +495,24 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, } /* exit if we are not ready yet for PTS measurements */ - if (!platform_info || !session || - !(state->get_action_flags(state) & IMV_ATTESTATION_FLAG_ALGO)) + 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 (!(state->get_action_flags(state) & IMV_ATTESTATION_FLAG_FILE_MEAS)) + if (!(actions & IMV_ATTESTATION_FILE_MEAS)) { bool is_dir, no_workitems = TRUE; - u_int32_t delimiter = SOLIDUS_UTF; - u_int16_t request_id; + uint32_t delimiter = SOLIDUS_UTF; + uint16_t request_id; pa_tnc_attr_t *attr; char *pathname; @@ -555,7 +674,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, enumerator->destroy(enumerator); /* sent all file and directory measurement and metadata requests */ - state->set_action_flags(state, IMV_ATTESTATION_FLAG_FILE_MEAS); + state->set_action_flags(state, IMV_ATTESTATION_FILE_MEAS); if (no_workitems) { @@ -600,14 +719,14 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, enumerator->destroy(enumerator); /* finalized all workitems? */ - if (session && session->get_policy_started(session) && + 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_FLAG_REC); + state->set_action_flags(state, IMV_ATTESTATION_REC); if (result != TNC_RESULT_SUCCESS) { @@ -642,14 +761,16 @@ METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, session = state->get_session(state); imv_id = this->agent->get_id(this->agent); - if (session) + if (imcv_db) { TNC_IMV_Evaluation_Result eval; TNC_IMV_Action_Recommendation rec; imv_workitem_t *workitem; enumerator_t *enumerator; - char *result_str; int pending_file_meas = 0; + char *result_str; + chunk_t result_buf; + bio_writer_t *result; enumerator = session->create_workitem_enumerator(session); if (enumerator) @@ -660,20 +781,28 @@ METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, { 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"; + result_str = "pending file measurements"; pending_file_meas++; break; case IMV_WORKITEM_TPM_ATTEST: - attestation_state->finalize_components(attestation_state); - result_str = "Pending component evidence"; + 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); @@ -682,6 +811,7 @@ METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, state->update_recommendation(state, rec, eval); imcv_db->finalize_workitem(imcv_db, workitem); workitem->destroy(workitem); + result->destroy(result); } enumerator->destroy(enumerator); diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_build.c b/src/libpts/plugins/imv_attestation/imv_attestation_build.c index 84023c6c6..120fe3eaa 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_build.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_build.c @@ -62,6 +62,11 @@ bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state, 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); @@ -89,17 +94,14 @@ bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state, tcg_pts_attr_req_func_comp_evid_t *attr_cast; enumerator_t *enumerator; pts_comp_func_name_t *name; - chunk_t keyid; - int kid; - u_int8_t flags; - u_int32_t depth; + 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_keyid(pts, &keyid) || - pts_db->check_aik_keyid(pts_db, keyid, &kid) != SUCCESS) + if (!pts->get_aik_id(pts)) { attestation_state->set_measurement_error(attestation_state, IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK); diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.c b/src/libpts/plugins/imv_attestation/imv_attestation_process.c index e40c92a24..26a57d15c 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_process.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.c @@ -46,10 +46,12 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, 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); @@ -80,7 +82,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, return FALSE; } pts->set_meas_algorithm(pts, selected_algorithm); - state->set_action_flags(state, IMV_ATTESTATION_FLAG_ALGO); + state->set_action_flags(state, IMV_ATTESTATION_ALGO); break; } case TCG_PTS_DH_NONCE_PARAMS_RESP: @@ -140,6 +142,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, { return FALSE; } + state->set_action_flags(state, IMV_ATTESTATION_DH_NONCE); break; } case TCG_PTS_TPM_VERSION_INFO: @@ -157,9 +160,10 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, tcg_pts_attr_aik_t *attr_cast; certificate_t *aik, *issuer; public_key_t *public; - chunk_t keyid; + chunk_t keyid, keyid_hex, device_id; + int aik_id; enumerator_t *e; - bool trusted = FALSE; + bool trusted = FALSE, trusted_chain = FALSE; attr_cast = (tcg_pts_attr_aik_t*)attr; aik = attr_cast->get_aik(attr_cast); @@ -170,12 +174,27 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, 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) { - public = aik->get_public_key(aik); - public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid); - DBG1(DBG_IMV, "verifying AIK certificate with keyid %#B", &keyid); - public->destroy(public); e = pts_credmgr->create_trusted_enumerator(pts_credmgr, KEY_ANY, aik->get_issuer(aik), FALSE); @@ -183,21 +202,22 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, { if (aik->issued_by(aik, issuer, NULL)) { - trusted = TRUE; + trusted_chain = TRUE; break; } } e->destroy(e); DBG1(DBG_IMV, "AIK certificate is %strusted", - trusted ? "" : "not "); - if (!trusted) + trusted_chain ? "" : "not "); + if (!trusted || !trusted_chain) { attestation_state->set_measurement_error(attestation_state, IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK); break; } } - pts->set_aik(pts, aik); + session->get_session_id(session, NULL, &aik_id); + pts->set_aik(pts, aik, aik_id); break; } case TCG_PTS_FILE_MEAS: @@ -205,21 +225,18 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, TNC_IMV_Evaluation_Result eval; TNC_IMV_Action_Recommendation rec; tcg_pts_attr_file_meas_t *attr_cast; - u_int16_t request_id; + uint16_t request_id; int arg_int, file_count; pts_meas_algorithms_t algo; pts_file_meas_t *measurements; - imv_session_t *session; imv_workitem_t *workitem, *found = NULL; imv_workitem_type_t type; - char result_str[BUF_LEN], *platform_info; + char result_str[BUF_LEN]; bool is_dir, correct; enumerator_t *enumerator; eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; - session = state->get_session(state); algo = pts->get_meas_algorithm(pts); - platform_info = pts->get_platform_info(pts); attr_cast = (tcg_pts_attr_file_meas_t*)attr; measurements = attr_cast->get_measurements(attr_cast); request_id = measurements->get_request_id(measurements); @@ -272,7 +289,8 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, /* check hashes from database against measurements */ e = pts_db->create_file_hash_enumerator(pts_db, - platform_info, algo, is_dir, arg_int); + pts->get_platform_id(pts), + algo, is_dir, arg_int); if (!e) { eval = TNC_IMV_EVALUATION_RESULT_ERROR; @@ -304,8 +322,8 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, while (e->enumerate(e, &filename, &measurement)) { if (pts_db->add_file_measurement(pts_db, - platform_info, algo, measurement, filename, - is_dir, arg_int) != SUCCESS) + pts->get_platform_id(pts), algo, measurement, + filename, is_dir, arg_int) != SUCCESS) { eval = TNC_IMV_EVALUATION_RESULT_ERROR; } @@ -328,7 +346,8 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, } else { - measurements->check(measurements, pts_db, platform_info, algo); + measurements->check(measurements, pts_db, + pts->get_platform_id(pts), algo); } break; } @@ -373,7 +392,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, pts_comp_func_name_t *name; pts_comp_evidence_t *evidence; pts_component_t *comp; - u_int32_t depth; + uint32_t depth; status_t status; attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr; @@ -398,14 +417,15 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, case TCG_PTS_SIMPLE_EVID_FINAL: { tcg_pts_attr_simple_evid_final_t *attr_cast; - u_int8_t flags; + 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; - imv_session_t *session; + 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, @@ -451,9 +471,10 @@ quote_error: * Finalize any pending measurement registrations and check * if all expected component measurements were received */ - attestation_state->finalize_components(attestation_state); + result = bio_writer_create(128); + attestation_state->finalize_components(attestation_state, + result); - session = state->get_session(state); enumerator = session->create_workitem_enumerator(session); while (enumerator->enumerate(enumerator, &workitem)) { @@ -461,8 +482,7 @@ quote_error: { TNC_IMV_Action_Recommendation rec; TNC_IMV_Evaluation_Result eval; - char *result_str; - u_int32_t error; + uint32_t error; error = attestation_state->get_measurement_error( attestation_state); @@ -470,34 +490,35 @@ quote_error: IMV_ATTESTATION_ERROR_COMP_EVID_PEND | IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL)) { - imv_reason_string_t *reason_string; - chunk_t result; - 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); + 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 { - result_str = strdup("attestation successful"); eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; } session->remove_workitem(session, enumerator); - rec = workitem->set_result(workitem, result_str, eval); + + 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); - free(result_str); 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)) diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_state.c b/src/libpts/plugins/imv_attestation/imv_attestation_state.c index 9304b9a13..11afbc29d 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_state.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.c @@ -63,22 +63,12 @@ struct private_imv_attestation_state_t { /** * Maximum PA-TNC message size for this TNCCS connection */ - u_int32_t max_msg_len; + uint32_t max_msg_len; /** * Flags set for completed actions */ - u_int32_t action_flags; - - /** - * Access Requestor ID Type - */ - u_int32_t ar_id_type; - - /** - * Access Requestor ID Value - */ - chunk_t ar_id_value; + uint32_t action_flags; /** * IMV database session associated with TNCCS connection @@ -113,7 +103,7 @@ struct private_imv_attestation_state_t { /** * Measurement error flags */ - u_int32_t measurement_error; + uint32_t measurement_error; /** * TNC Reason String @@ -215,46 +205,29 @@ METHOD(imv_state_t, set_flags, void, } METHOD(imv_state_t, set_max_msg_len, void, - private_imv_attestation_state_t *this, u_int32_t max_msg_len) + 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, u_int32_t, +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, u_int32_t flags) + private_imv_attestation_state_t *this, uint32_t flags) { this->action_flags |= flags; } -METHOD(imv_state_t, get_action_flags, u_int32_t, +METHOD(imv_state_t, get_action_flags, uint32_t, private_imv_attestation_state_t *this) { return this->action_flags; } -METHOD(imv_state_t, set_ar_id, void, - private_imv_attestation_state_t *this, u_int32_t id_type, chunk_t id_value) -{ - this->ar_id_type = id_type; - this->ar_id_value = chunk_clone(id_value); -} - -METHOD(imv_state_t, get_ar_id, chunk_t, - private_imv_attestation_state_t *this, u_int32_t *id_type) -{ - if (id_type) - { - *id_type = this->ar_id_type; - } - return this->ar_id_value; -} - METHOD(imv_state_t, set_session, void, private_imv_attestation_state_t *this, imv_session_t *session) { @@ -362,7 +335,6 @@ METHOD(imv_state_t, destroy, void, DESTROY_IF(this->reason_string); this->components->destroy_function(this->components, (void *)free_func_comp); this->pts->destroy(this->pts); - free(this->ar_id_value.ptr); free(this); } @@ -387,7 +359,7 @@ METHOD(imv_attestation_state_t, get_pts, pts_t*, METHOD(imv_attestation_state_t, create_component, pts_component_t*, private_imv_attestation_state_t *this, pts_comp_func_name_t *name, - u_int32_t depth, pts_database_t *pts_db) + uint32_t depth, pts_database_t *pts_db) { enumerator_t *enumerator; func_comp_t *entry, *new_entry; @@ -437,8 +409,8 @@ METHOD(imv_attestation_state_t, create_component, pts_component_t*, /** * Enumerate file measurement entries */ -static bool entry_filter(void *null, func_comp_t **entry, u_int8_t *flags, - void *i2, u_int32_t *depth, +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; @@ -482,28 +454,38 @@ METHOD(imv_attestation_state_t, get_component, pts_component_t*, return found; } -METHOD(imv_attestation_state_t, get_measurement_error, u_int32_t, +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, u_int32_t error) + 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) + 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))) + entry->name->get_qualifier(entry->name), + result)) { set_measurement_error(this, IMV_ATTESTATION_ERROR_COMP_EVID_PEND); } @@ -529,8 +511,6 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .get_max_msg_len = _get_max_msg_len, .set_action_flags = _set_action_flags, .get_action_flags = _get_action_flags, - .set_ar_id = _set_ar_id, - .get_ar_id = _get_ar_id, .set_session = _set_session, .get_session = _get_session, .change_state = _change_state, diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_state.h b/src/libpts/plugins/imv_attestation/imv_attestation_state.h index 9369d30a2..b72857552 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_state.h +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.h @@ -29,7 +29,9 @@ #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; @@ -40,10 +42,15 @@ typedef enum imv_meas_error_t imv_meas_error_t; * IMV Attestation Flags set for completed actions */ enum imv_attestation_flag_t { - IMV_ATTESTATION_FLAG_ATTR_REQ = (1<<0), - IMV_ATTESTATION_FLAG_ALGO = (1<<1), - IMV_ATTESTATION_FLAG_FILE_MEAS = (1<<2), - IMV_ATTESTATION_FLAG_REC = (1<<3) + 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) }; /** @@ -114,7 +121,7 @@ struct imv_attestation_state_t { */ pts_component_t* (*create_component)(imv_attestation_state_t *this, pts_comp_func_name_t *name, - u_int32_t depth, + uint32_t depth, pts_database_t *pts_db); /** @@ -136,15 +143,18 @@ struct imv_attestation_state_t { /** * 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); + void (*finalize_components)(imv_attestation_state_t *this, + bio_writer_t *result); /** * Indicates the types of measurement errors that occurred * * @return Measurement error flags */ - u_int32_t (*get_measurement_error)(imv_attestation_state_t *this); + uint32_t (*get_measurement_error)(imv_attestation_state_t *this); /** * Call if a measurement error is encountered @@ -152,7 +162,7 @@ struct imv_attestation_state_t { * @param error Measurement error type */ void (*set_measurement_error)(imv_attestation_state_t *this, - u_int32_t error); + uint32_t error); /** * Returns a concatenation of File Measurement reason strings diff --git a/src/libpts/plugins/imv_swid/Makefile.am b/src/libpts/plugins/imv_swid/Makefile.am index 29c05e0ab..77f33e6c6 100644 --- a/src/libpts/plugins/imv_swid/Makefile.am +++ b/src/libpts/plugins/imv_swid/Makefile.am @@ -5,17 +5,19 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libpts AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imv-swid.la imv_swid_la_LIBADD = \ $(top_builddir)/src/libimcv/libimcv.la \ $(top_builddir)/src/libpts/libpts.la \ - $(top_builddir)/src/libstrongswan/libstrongswan.la + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + -ljson 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_agent.h imv_swid_agent.c \ + imv_swid_rest.h imv_swid_rest.c imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined diff --git a/src/libpts/plugins/imv_swid/Makefile.in b/src/libpts/plugins/imv_swid/Makefile.in index f9bd93ce0..bd89a6f90 100644 --- a/src/libpts/plugins/imv_swid/Makefile.in +++ b/src/libpts/plugins/imv_swid/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. +# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -131,7 +131,7 @@ imv_swid_la_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la \ $(top_builddir)/src/libpts/libpts.la \ $(top_builddir)/src/libstrongswan/libstrongswan.la am_imv_swid_la_OBJECTS = imv_swid.lo imv_swid_state.lo \ - imv_swid_agent.lo + imv_swid_agent.lo imv_swid_rest.lo imv_swid_la_OBJECTS = $(am_imv_swid_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -263,6 +263,7 @@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ @@ -281,6 +282,7 @@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ @@ -308,6 +310,7 @@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +aikgen_plugins = @aikgen_plugins@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ @@ -399,6 +402,7 @@ srcdir = @srcdir@ starter_plugins = @starter_plugins@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ @@ -416,17 +420,19 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/libpts AM_CFLAGS = \ - -rdynamic + $(PLUGIN_CFLAGS) imcv_LTLIBRARIES = imv-swid.la imv_swid_la_LIBADD = \ $(top_builddir)/src/libimcv/libimcv.la \ $(top_builddir)/src/libpts/libpts.la \ - $(top_builddir)/src/libstrongswan/libstrongswan.la + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + -ljson 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_agent.h imv_swid_agent.c \ + imv_swid_rest.h imv_swid_rest.c imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined all: all-am @@ -510,6 +516,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_swid.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_swid_agent.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_swid_rest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_swid_state.Plo@am__quote@ .c.o: diff --git a/src/libpts/plugins/imv_swid/imv_swid_agent.c b/src/libpts/plugins/imv_swid/imv_swid_agent.c index a0326f88d..3053b2643 100644 --- a/src/libpts/plugins/imv_swid/imv_swid_agent.c +++ b/src/libpts/plugins/imv_swid/imv_swid_agent.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -13,8 +13,12 @@ * 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 "libpts.h" #include "swid/swid_error.h" @@ -27,6 +31,8 @@ #include <ietf/ietf_attr_pa_tnc_error.h> #include <imv/imv_agent.h> #include <imv/imv_msg.h> +#include <ita/ita_attr.h> +#include <ita/ita_attr_angel.h> #include <tncif_names.h> #include <tncif_pa_subtypes.h> @@ -43,6 +49,14 @@ static pen_type_t msg_types[] = { }; /** + * 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 { @@ -57,6 +71,11 @@ struct private_imv_swid_agent_t { */ imv_agent_t *agent; + /** + * REST API to strongTNC manager + */ + imv_swid_rest_t *rest_api; + }; METHOD(imv_agent_if_t, bind_functions, TNC_Result, @@ -89,8 +108,8 @@ METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, 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; - imv_session_t *session; enumerator_t *enumerator; pa_tnc_attr_t *attr; TNC_Result result; @@ -103,22 +122,16 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this, return result; } - session = state->get_session(state); + swid_state = (imv_swid_state_t*)state; /* analyze PA-TNC attributes */ enumerator = in_msg->create_attribute_enumerator(in_msg); while (enumerator->enumerate(enumerator, &attr)) { - TNC_IMV_Evaluation_Result eval; - TNC_IMV_Action_Recommendation rec; - pen_type_t type; - u_int32_t request_id, last_eid, eid_epoch; + uint32_t request_id = 0, last_eid, eid_epoch; swid_inventory_t *inventory; - int tag_count; - char result_str[BUF_LEN], *tag_item; - imv_workitem_t *workitem, *found = NULL; - enumerator_t *et, *ew; - + pen_type_t type; + type = attr->get_type(attr); if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR) @@ -127,7 +140,7 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this, pen_type_t error_code; chunk_t msg_info, description; bio_reader_t *reader; - u_int32_t request_id = 0, max_attr_size; + uint32_t max_attr_size; bool success; error_attr = (ietf_attr_pa_tnc_error_t*)attr; @@ -166,6 +179,20 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this, 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; @@ -176,33 +203,30 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this, case TCG_SWID_TAG_ID_INVENTORY: { tcg_swid_attr_tag_id_inv_t *attr_cast; - swid_tag_id_t *tag_id; - chunk_t tag_creator, unique_sw_id; + 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_item = "tag ID"; - DBG2(DBG_IMV, "received SWID %s inventory for request %d " - "at eid %d of epoch 0x%08x", tag_item, + 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); - et = inventory->create_enumerator(inventory); - while (et->enumerate(et, &tag_id)) + if (request_id == swid_state->get_request_id(swid_state)) { - tag_creator = tag_id->get_tag_creator(tag_id); - unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL); - DBG3(DBG_IMV, " %.*s_%.*s.swidtag", - tag_creator.len, tag_creator.ptr, - unique_sw_id.len, unique_sw_id.ptr); + swid_state->set_swid_inventory(swid_state, inventory); + swid_state->set_count(swid_state, tag_id_count, 0); } - et->destroy(et); - - if (request_id == 0) + else { - /* TODO handle subscribed messages */ - break; + DBG1(DBG_IMV, "no workitem found for SWID tag ID inventory " + "with request ID %d", request_id); } break; } @@ -211,62 +235,64 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this, 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_item = "tag"; - DBG2(DBG_IMV, "received SWID %s inventory for request %d " - "at eid %d of epoch 0x%08x", tag_item, + 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); - et = inventory->create_enumerator(inventory); - while (et->enumerate(et, &tag)) + + if (request_id == swid_state->get_request_id(swid_state)) { - tag_encoding = tag->get_encoding(tag); - DBG3(DBG_IMV, "%.*s", tag_encoding.len, tag_encoding.ptr); - } - et->destroy(et); + swid_state->set_count(swid_state, 0, tag_count); - if (request_id == 0) + 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 { - /* TODO handle subscribed messages */ - break; + DBG1(DBG_IMV, "no workitem found for SWID tag inventory " + "with request ID %d", request_id); } - break; } default: continue; } - - ew = session->create_workitem_enumerator(session); - while (ew->enumerate(ew, &workitem)) - { - if (workitem->get_id(workitem) == request_id) - { - found = workitem; - break; - } - } - if (!found) - { - DBG1(DBG_IMV, "no workitem found for SWID %s inventory " - "with request ID %d", tag_item, request_id); - ew->destroy(ew); - continue; - } - - eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; - tag_count = inventory->get_count(inventory); - snprintf(result_str, BUF_LEN, "received inventory of %d SWID %s%s", - tag_count, tag_item, (tag_count == 1) ? "" : "s"); - session->remove_workitem(session, ew); - ew->destroy(ew); - rec = found->set_result(found, result_str, eval); - state->update_recommendation(state, rec, eval); - imcv_db->finalize_workitem(imcv_db, found); - found->destroy(found); } enumerator->destroy(enumerator); @@ -342,8 +368,8 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, TNC_IMVID imv_id; TNC_Result result = TNC_RESULT_SUCCESS; bool no_workitems = TRUE; - u_int32_t request_id; - u_int8_t flags; + uint32_t request_id, received; + uint8_t flags; enumerator_t *enumerator; if (!this->agent->get_state(this->agent, id, &state)) @@ -360,11 +386,11 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, return TNC_RESULT_SUCCESS; } - /* create an empty out message - we might need it */ + /* 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 (!session) + if (!imcv_db) { DBG2(DBG_IMV, "no workitems available - no evaluation possible"); state->set_recommendation(state, @@ -381,7 +407,9 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, return this->agent->provide_recommendation(this->agent, state); } - if (handshake_state == IMV_SWID_STATE_INIT) + /* Look for SWID tag workitem and create SWID tag request */ + if (handshake_state == IMV_SWID_STATE_INIT && + session->get_policy_started(session)) { enumerator = session->create_workitem_enumerator(session); if (enumerator) @@ -408,13 +436,14 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, flags |= TCG_SWID_ATTR_REQ_FLAG_C; } 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); @@ -431,6 +460,171 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, } } + 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) @@ -471,6 +665,7 @@ METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, 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); libpts_deinit(); @@ -484,6 +679,8 @@ imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id, { 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); @@ -505,6 +702,14 @@ imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id, .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); + } libpts_init(); return &this->public; diff --git a/src/libpts/plugins/imv_swid/imv_swid_rest.c b/src/libpts/plugins/imv_swid/imv_swid_rest.c new file mode 100644 index 000000000..143b0b239 --- /dev/null +++ b/src/libpts/plugins/imv_swid/imv_swid_rest.c @@ -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; +} + + diff --git a/src/libpts/plugins/imv_swid/imv_swid_rest.h b/src/libpts/plugins/imv_swid/imv_swid_rest.h new file mode 100644 index 000000000..93e3d6ab9 --- /dev/null +++ b/src/libpts/plugins/imv_swid/imv_swid_rest.h @@ -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/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_ @}*/ diff --git a/src/libpts/plugins/imv_swid/imv_swid_state.c b/src/libpts/plugins/imv_swid/imv_swid_state.c index 5be8c0254..c68b57e4d 100644 --- a/src/libpts/plugins/imv_swid/imv_swid_state.c +++ b/src/libpts/plugins/imv_swid/imv_swid_state.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -14,9 +14,11 @@ */ #include "imv_swid_state.h" -#include "imv/imv_lang_string.h" -#include "imv/imv_reason_string.h" -#include "imv/imv_remediation_string.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> @@ -58,22 +60,12 @@ struct private_imv_swid_state_t { /** * Maximum PA-TNC message size for this TNCCS connection */ - u_int32_t max_msg_len; + uint32_t max_msg_len; /** * Flags set for completed actions */ - u_int32_t action_flags; - - /** - * Access Requestor ID Type - */ - u_int32_t ar_id_type; - - /** - * Access Requestor ID Value - */ - chunk_t ar_id_value; + uint32_t action_flags; /** * IMV database session associatied with TNCCS connection @@ -105,6 +97,36 @@ struct private_imv_swid_state_t { */ 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, @@ -133,46 +155,29 @@ METHOD(imv_state_t, set_flags, void, } METHOD(imv_state_t, set_max_msg_len, void, - private_imv_swid_state_t *this, u_int32_t max_msg_len) + 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, u_int32_t, +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, u_int32_t flags) + private_imv_swid_state_t *this, uint32_t flags) { this->action_flags |= flags; } -METHOD(imv_state_t, get_action_flags, u_int32_t, +METHOD(imv_state_t, get_action_flags, uint32_t, private_imv_swid_state_t *this) { return this->action_flags; } -METHOD(imv_state_t, set_ar_id, void, - private_imv_swid_state_t *this, u_int32_t id_type, chunk_t id_value) -{ - this->ar_id_type = id_type; - this->ar_id_value = chunk_clone(id_value); -} - -METHOD(imv_state_t, get_ar_id, chunk_t, - private_imv_swid_state_t *this, u_int32_t *id_type) -{ - if (id_type) - { - *id_type = this->ar_id_type; - } - return this->ar_id_value; -} - METHOD(imv_state_t, set_session, void, private_imv_swid_state_t *this, imv_session_t *session) { @@ -232,10 +237,10 @@ METHOD(imv_state_t, get_remediation_instructions, bool, 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); - free(this->ar_id_value.ptr); free(this); } @@ -251,6 +256,83 @@ METHOD(imv_swid_state_t, get_handshake_state, imv_swid_handshake_state_t, 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. */ @@ -269,8 +351,6 @@ imv_state_t *imv_swid_state_create(TNC_ConnectionID connection_id) .get_max_msg_len = _get_max_msg_len, .set_action_flags = _set_action_flags, .get_action_flags = _get_action_flags, - .set_ar_id = _set_ar_id, - .get_ar_id = _get_ar_id, .set_session = _set_session, .get_session= _get_session, .change_state = _change_state, @@ -283,13 +363,25 @@ imv_state_t *imv_swid_state_create(TNC_ConnectionID connection_id) }, .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, + .jobj = json_object_new_object(), + .jarray = json_object_new_array(), ); + json_object_object_add(this->jobj, "data", this->jarray); + return &this->public.interface; } diff --git a/src/libpts/plugins/imv_swid/imv_swid_state.h b/src/libpts/plugins/imv_swid/imv_swid_state.h index d6e5840df..7ffabfd26 100644 --- a/src/libpts/plugins/imv_swid/imv_swid_state.h +++ b/src/libpts/plugins/imv_swid/imv_swid_state.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -25,8 +25,11 @@ #define IMV_SWID_STATE_H_ #include <imv/imv_state.h> +#include <swid/swid_inventory.h> #include <library.h> +#include <json/json.h> + typedef struct imv_swid_state_t imv_swid_state_t; typedef enum imv_swid_handshake_state_t imv_swid_handshake_state_t; @@ -64,6 +67,64 @@ struct imv_swid_state_t { */ 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); + }; /** diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c index c6b4131bf..be8aa40ad 100644 --- a/src/libpts/pts/components/ita/ita_comp_ima.c +++ b/src/libpts/pts/components/ita/ita_comp_ima.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,27 +18,20 @@ #include "libpts.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> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.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_PCR 10 -#define IMA_TYPE_LEN 3 -#define IMA_FILENAME_LEN_MAX 255 +#define IMA_FILENAME_LEN_MAX 255 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t; -typedef struct bios_entry_t bios_entry_t; -typedef struct ima_entry_t ima_entry_t; typedef enum ima_state_t ima_state_t; enum ima_state_t { @@ -66,14 +59,9 @@ struct pts_ita_comp_ima_t { pts_comp_func_name_t *name; /** - * AIK keyid - */ - chunk_t keyid; - - /** * Sub-component depth */ - u_int32_t depth; + uint32_t depth; /** * PTS measurement database @@ -83,7 +71,7 @@ struct pts_ita_comp_ima_t { /** * Primary key for AIK database entry */ - int kid; + int aik_id; /** * Primary key for IMA BIOS Component Functional Name database entry @@ -118,12 +106,12 @@ struct pts_ita_comp_ima_t { /** * IMA BIOS measurements */ - linked_list_t *bios_list; + pts_ima_bios_list_t *bios_list; /** * IMA runtime file measurements */ - linked_list_t *ima_list; + pts_ima_event_list_t *ima_list; /** * Whether to send pcr_before and pcr_after info @@ -131,9 +119,9 @@ struct pts_ita_comp_ima_t { bool pcr_info; /** - * IMA measurement time + * Creation time of measurement */ - time_t measurement_time; + time_t creation_time; /** * IMA state machine @@ -173,222 +161,11 @@ struct pts_ita_comp_ima_t { }; /** - * Linux IMA BIOS measurement entry - */ -struct bios_entry_t { - - /** - * PCR register - */ - u_int32_t pcr; - - /** - * SHA1 measurement hash - */ - chunk_t measurement; -}; - -/** - * Linux IMA runtime file measurement entry - */ -struct ima_entry_t { - - /** - * SHA1 measurement hash - */ - chunk_t measurement; - - /** - * absolute path of executable files or basename of dynamic libraries - */ - char *filename; -}; - -/** - * Free a bios_entry_t object - */ -static void free_bios_entry(bios_entry_t *this) -{ - free(this->measurement.ptr); - free(this); -} - -/** - * Free an ima_entry_t object - */ -static void free_ima_entry(ima_entry_t *this) -{ - free(this->measurement.ptr); - free(this->filename); - free(this); -} - -/** - * Load a PCR measurement file and determine the creation date - */ -static bool load_bios_measurements(char *file, linked_list_t *list, - time_t *created) -{ - u_int32_t pcr, num, len; - 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 FALSE; - } - - if (fstat(fd, &st) == -1) - { - DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file, - strerror(errno)); - close(fd); - return FALSE; - } - *created = st.st_ctime; - - while (TRUE) - { - res = read(fd, &pcr, 4); - if (res == 0) - { - DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)", - file, list->get_count(list)); - close(fd); - return TRUE; - } - - entry = malloc_thing(bios_entry_t); - entry->pcr = pcr; - entry->measurement = chunk_alloc(HASH_SIZE_SHA1); - - if (res != 4) - { - break; - } - if (read(fd, &num, 4) != 4) - { - break; - } - if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1) - { - break; - } - if (read(fd, &len, 4) != 4) - { - break; - } - if (lseek(fd, len, SEEK_CUR) == -1) - { - break; - } - list->insert_last(list, entry); - } - - DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file, - strerror(errno)); - free_bios_entry(entry); - close(fd); - return FALSE; -} - -/** - * Load an IMA runtime measurement file and determine the creation and - * update dates - */ -static bool load_runtime_measurements(char *file, linked_list_t *list, - time_t *created) -{ - u_int32_t pcr, len; - ima_entry_t *entry; - char type[IMA_TYPE_LEN]; - 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 TRUE; - } - - if (fstat(fd, &st) == -1) - { - DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file, - strerror(errno)); - close(fd); - return FALSE; - } - *created = st.st_ctime; - - while (TRUE) - { - res = read(fd, &pcr, 4); - if (res == 0) - { - DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)", - file, list->get_count(list)); - close(fd); - return TRUE; - } - - entry = malloc_thing(ima_entry_t); - entry->measurement = chunk_alloc(HASH_SIZE_SHA1); - entry->filename = NULL; - - if (res != 4 || pcr != IMA_PCR) - { - break; - } - if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1) - { - break; - } - if (read(fd, &len, 4) != 4 || len != IMA_TYPE_LEN) - { - break; - } - if (read(fd, type, IMA_TYPE_LEN) != IMA_TYPE_LEN || - memcmp(type, "ima", IMA_TYPE_LEN)) - { - break; - } - if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1) - { - break; - } - if (read(fd, &len, 4) != 4) - { - break; - } - entry->filename = malloc(len + 1); - if (read(fd, entry->filename, len) != len) - { - break; - } - entry->filename[len] = '\0'; - - list->insert_last(list, entry); - } - - DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", - file, strerror(errno)); - free_ima_entry(entry); - close(fd); - return FALSE; -} - -/** - * Extend measurement into PCR an create evidence + * Extend measurement into PCR and create evidence */ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, - u_int8_t qualifier, pts_pcr_t *pcrs, - u_int32_t pcr, chunk_t measurement) + uint8_t qualifier, pts_pcr_t *pcrs, + uint32_t pcr, chunk_t measurement) { size_t pcr_len; pts_pcr_transform_t pcr_transform; @@ -414,7 +191,7 @@ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, 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->measurement_time, measurement); + pcr_transform, this->creation_time, measurement); if (this->pcr_info) { pcr_after =chunk_clone(pcrs->get(pcrs, pcr)); @@ -424,15 +201,83 @@ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, } /** + * 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) +static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement, + char *algo) { - u_int32_t i; - u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1]; u_char pcr_buffer[HASH_SIZE_SHA1]; - chunk_t file_name, boot_aggregate; + chunk_t boot_aggregate; hasher_t *hasher; + uint32_t i; bool success, pcr_ok = TRUE; hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); @@ -448,19 +293,20 @@ static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement) } if (pcr_ok) { - boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer)); - memset(filename_buffer, 0, sizeof(filename_buffer)); - strcpy(filename_buffer, "boot_aggregate"); - file_name = chunk_create (filename_buffer, sizeof(filename_buffer)); - - pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer) && - hasher->get_hash(hasher, boot_aggregate, NULL) && - hasher->get_hash(hasher, file_name, boot_aggregate.ptr); + 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"); @@ -479,26 +325,28 @@ METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, return this->name; } -METHOD(pts_component_t, get_evidence_flags, u_int8_t, +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, u_int32_t, +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, u_int8_t qualifier, pts_t *pts, + pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts, pts_comp_evidence_t **evidence) { - bios_entry_t *bios_entry; - ima_entry_t *ima_entry; 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); @@ -509,25 +357,25 @@ METHOD(pts_component_t, measure, status_t, switch (this->state) { case IMA_STATE_INIT: - if (!load_bios_measurements(IMA_BIOS_MEASUREMENTS, - this->bios_list, &this->measurement_time)) + 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->remove_first(this->bios_list, - (void**)&bios_entry); + 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, bios_entry->pcr, - bios_entry->measurement); - free(bios_entry); + evid = extend_pcr(this, qualifier, pcrs, pcr, measurement); this->state = this->bios_list->get_count(this->bios_list) ? IMA_STATE_BIOS : IMA_STATE_INIT; @@ -542,17 +390,20 @@ METHOD(pts_component_t, measure, status_t, switch (this->state) { case IMA_STATE_INIT: - if (!load_runtime_measurements(IMA_RUNTIME_MEASUREMENTS, - this->ima_list, &this->measurement_time)) + 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->remove_first(this->ima_list, - (void**)&ima_entry); + status = this->ima_list->get_next(this->ima_list, &measurement, + &algo, &name); if (status != SUCCESS) { DBG1(DBG_PTS, "could not retrieve ima measurement entry"); @@ -560,20 +411,33 @@ METHOD(pts_component_t, measure, status_t, } if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count) { - if (!check_boot_aggregate(pcrs, ima_entry->measurement)) + if (!check_boot_aggregate(pcrs, measurement, algo)) { return FAILED; } } evid = extend_pcr(this, qualifier, pcrs, IMA_PCR, - ima_entry->measurement); + 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, - ima_entry->filename); + uri); + free(uri); } - free(ima_entry->filename); - free(ima_entry); + free(name); + free(algo); this->state = this->ima_list->get_count(this->ima_list) ? IMA_STATE_RUNTIME : IMA_STATE_END; @@ -598,40 +462,80 @@ METHOD(pts_component_t, measure, status_t, SUCCESS : NEED_MORE; } -METHOD(pts_component_t, verify, status_t, - pts_ita_comp_ima_t *this, u_int8_t qualifier, pts_t *pts, - pts_comp_evidence_t *evidence) +/** + * 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) { - bool has_pcr_info; - u_int32_t 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; - char *uri; + pts_meas_algorithms_t hash_algo; + char *uri, *pos, *algo, *name; - /* some first time initializations */ - if (!this->keyid.ptr) + evidence->get_validation(evidence, &uri); + + /* IMA-NG format? */ + pos = strchr(uri, ':'); + if (pos && (pos - uri + 1) < IMA_ALGO_LEN_MAX) { - if (!pts->get_aik_keyid(pts, &this->keyid)) + 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:")) { - DBG1(DBG_PTS, "AIK keyid not available"); - return FAILED; + hash_algo = PTS_MEAS_ALGO_SHA256; } - this->keyid = chunk_clone(this->keyid); - if (!this->pts_db) + else if (streq(algo, "sha384:")) { - DBG1(DBG_PTS, "pts database not available"); - return FAILED; + 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, - &measurement_time); + &creation_time); if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | PTS_ITA_QUALIFIER_TYPE_TRUSTED)) @@ -641,26 +545,22 @@ METHOD(pts_component_t, verify, status_t, 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->keyid, algo, &this->bios_cid, - &this->kid, &this->bios_count); + 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; } - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); if (this->bios_count) { - DBG1(DBG_PTS, "checking %d %N '%N' BIOS evidence measurements", - this->bios_count, pen_names, vid, names, name); + DBG1(DBG_PTS, "checking %d BIOS evidence measurements", + this->bios_count); } else { - DBG1(DBG_PTS, "registering %N '%N' BIOS evidence measurements", - pen_names, vid, names, name); + DBG1(DBG_PTS, "registering BIOS evidence measurements"); this->is_bios_registering = TRUE; } @@ -670,8 +570,8 @@ METHOD(pts_component_t, verify, status_t, if (this->is_bios_registering) { status = this->pts_db->insert_comp_measurement(this->pts_db, - measurement, this->bios_cid, this->kid, - ++this->seq_no, pcr, algo); + measurement, this->bios_cid, this->aik_id, + ++this->seq_no, pcr, algo); if (status != SUCCESS) { return status; @@ -681,8 +581,8 @@ METHOD(pts_component_t, verify, status_t, else { status = this->pts_db->check_comp_measurement(this->pts_db, - measurement, this->bios_cid, this->kid, - ++this->seq_no, pcr, algo); + measurement, this->bios_cid, this->aik_id, + ++this->seq_no, pcr, algo); if (status == FAILED) { return status; @@ -697,13 +597,34 @@ METHOD(pts_component_t, verify, status_t, 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: - if (!check_boot_aggregate(pcrs, measurement)) + 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)) { - this->state = IMA_STATE_RUNTIME; return FAILED; } this->state = IMA_STATE_INIT; @@ -711,33 +632,30 @@ METHOD(pts_component_t, verify, status_t, 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->keyid, algo, - &this->ima_cid, &this->kid, &ima_count); + 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; } - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); if (ima_count) { - DBG1(DBG_PTS, "checking %N '%N' boot aggregate evidence " - "measurement", pen_names, vid, names, name); + DBG1(DBG_PTS, "checking boot aggregate evidence " + "measurement"); status = this->pts_db->check_comp_measurement(this->pts_db, measurement, this->ima_cid, - this->kid, 1, pcr, algo); + this->aik_id, 1, pcr, algo); } else { - DBG1(DBG_PTS, "registering %N '%N' boot aggregate evidence " - "measurement", pen_names, vid, names, name); + 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->kid, 1, pcr, algo); + this->aik_id, 1, pcr, algo); } this->state = IMA_STATE_RUNTIME; @@ -747,42 +665,76 @@ METHOD(pts_component_t, verify, status_t, } 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, &uri) != + if (evidence->get_validation(evidence, NULL) != PTS_COMP_EVID_VALIDATION_PASSED) { - DBG1(DBG_PTS, "policy URI could no be retrieved"); + DBG1(DBG_PTS, "evidence validation failed"); this->count_failed++; return FAILED; } - status = this->pts_db->check_file_measurement(this->pts_db, - pts->get_platform_info(pts), - PTS_MEAS_ALGO_SHA1_IMA, - measurement, uri); + 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, uri); + &measurement, ima_name); this->count_ok++; break; case NOT_FOUND: DBG2(DBG_PTS, "%#B for '%s' not found", - &measurement, uri); + &measurement, ima_name); this->count_unknown++; break; case VERIFY_ERROR: DBG1(DBG_PTS, "%#B for '%s' differs", - &measurement, uri); + &measurement, ima_name); this->count_differ++; break; case FAILED: default: DBG1(DBG_PTS, "%#B for '%s' failed", - &measurement, uri); + &measurement, ima_name); this->count_failed++; } break; + } default: return FAILED; } @@ -818,16 +770,15 @@ METHOD(pts_component_t, verify, status_t, } METHOD(pts_component_t, finalize, bool, - pts_ita_comp_ima_t *this, u_int8_t qualifier) + pts_ita_comp_ima_t *this, uint8_t qualifier, bio_writer_t *result) { - u_int32_t vid, name; - enum_name_t *names; + 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); - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | PTS_ITA_QUALIFIER_TYPE_TRUSTED)) @@ -838,16 +789,20 @@ METHOD(pts_component_t, finalize, bool, /* close registration */ this->is_bios_registering = FALSE; - DBG1(DBG_PTS, "registered %d %N '%N' BIOS evidence measurements", - this->seq_no, pen_names, vid, names, name); + snprintf(pos, len, "registered %d BIOS evidence measurements", + this->seq_no); } else if (this->seq_no < this->bios_count) { - DBG1(DBG_PTS, "%d of %d %N '%N' BIOS evidence measurements missing", - this->bios_count - this->seq_no, this->bios_count, - pen_names, vid, names, name); + 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)) @@ -858,26 +813,34 @@ METHOD(pts_component_t, finalize, bool, /* close registration */ this->is_ima_registering = FALSE; - DBG1(DBG_PTS, "registered %N '%N' boot aggregate evidence " - "measurement", pen_names, vid, names, name); + written = snprintf(pos, len, "registered IMA boot aggregate " + "evidence measurement; "); + pos += written; + len -= written; } if (this->count) { - DBG1(DBG_PTS, "processed %d %N '%N' file evidence measurements: " - "%d ok, %d unknown, %d differ, %d failed", - this->count, pen_names, vid, names, name, - this->count_ok, this->count_unknown, - this->count_differ, this->count_failed); - success = !this->count_differ && !this->count_failed; + 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 { - DBG1(DBG_PTS, "unsupported functional component name qualifier"); + 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; } @@ -892,35 +855,28 @@ METHOD(pts_component_t, destroy, void, pts_ita_comp_ima_t *this) { int count; - u_int32_t vid, name; - enum_name_t *names; if (ref_put(&this->ref)) { - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); if (this->is_bios_registering) { count = this->pts_db->delete_comp_measurements(this->pts_db, - this->bios_cid, this->kid); - DBG1(DBG_PTS, "deleted %d registered %N '%N' BIOS evidence " - "measurements", count, pen_names, vid, names, name); + 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->kid); - DBG1(DBG_PTS, "deleted registered %N '%N' boot aggregate evidence " - "measurement", pen_names, vid, names, name); + this->ima_cid, this->aik_id); + DBG1(DBG_PTS, "deleted registered boot aggregate evidence " + "measurement"); } - this->bios_list->destroy_function(this->bios_list, - (void *)free_bios_entry); - this->ima_list->destroy_function(this->ima_list, - (void *)free_ima_entry); + DESTROY_IF(this->bios_list); + DESTROY_IF(this->ima_list); this->name->destroy(this->name); - free(this->keyid.ptr); + free(this); } } @@ -928,7 +884,7 @@ METHOD(pts_component_t, destroy, void, /** * See header */ -pts_component_t *pts_ita_comp_ima_create(u_int32_t depth, +pts_component_t *pts_ita_comp_ima_create(uint32_t depth, pts_database_t *pts_db) { pts_ita_comp_ima_t *this; @@ -948,10 +904,8 @@ pts_component_t *pts_ita_comp_ima_create(u_int32_t depth, PTS_QUALIFIER_UNKNOWN), .depth = depth, .pts_db = pts_db, - .bios_list = linked_list_create(), - .ima_list = linked_list_create(), .pcr_info = lib->settings->get_bool(lib->settings, - "%s.plugins.imc-attestation.pcr_info", TRUE, lib->ns), + "%s.plugins.imc-attestation.pcr_info", FALSE, lib->ns), .ref = 1, ); diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.c b/src/libpts/pts/components/ita/ita_comp_tboot.c index f4859f801..67be1ca3a 100644 --- a/src/libpts/pts/components/ita/ita_comp_tboot.c +++ b/src/libpts/pts/components/ita/ita_comp_tboot.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -41,11 +41,6 @@ struct pts_ita_comp_tboot_t { pts_comp_func_name_t *name; /** - * AIK keyid - */ - chunk_t keyid; - - /** * Sub-component depth */ u_int32_t depth; @@ -56,6 +51,11 @@ struct pts_ita_comp_tboot_t { pts_database_t *pts_db; /** + * Primary key for AIK database entry + */ + int aik_id; + + /** * Primary key for Component Functional Name database entry */ int cid; @@ -201,51 +201,38 @@ METHOD(pts_component_t, verify, status_t, 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); - if (!this->keyid.ptr) + status = this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->aik_id, algo, + &this->cid, &this->count); + if (status != SUCCESS) { - if (!pts->get_aik_keyid(pts, &this->keyid)) - { - return FAILED; - } - this->keyid = chunk_clone(this->keyid); - - if (!this->pts_db) - { - DBG1(DBG_PTS, "pts database not available"); - return FAILED; - } - status = this->pts_db->get_comp_measurement_count(this->pts_db, - this->name, this->keyid, algo, &this->cid, - &this->kid, &this->count); - if (status != SUCCESS) - { - return status; - } - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); + return status; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(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->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->kid, + measurement, this->cid, this->aik_id, ++this->seq_no, extended_pcr, algo); if (status != SUCCESS) { @@ -282,30 +269,31 @@ METHOD(pts_component_t, verify, status_t, } METHOD(pts_component_t, finalize, bool, - pts_ita_comp_tboot_t *this, u_int8_t qualifier) + pts_ita_comp_tboot_t *this, u_int8_t qualifier, bio_writer_t *result) { - u_int32_t vid, name; - enum_name_t *names; - - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); + char result_buf[BUF_LEN]; if (this->is_registering) { /* close registration */ this->is_registering = FALSE; - DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence " - "measurements", this->seq_no, pen_names, vid, names, name); + snprintf(result_buf, BUF_LEN, "registered %d evidence measurements", + this->seq_no); } else if (this->seq_no < this->count) { - DBG1(DBG_PTS, "%d of %d %N '%N' functional component evidence " - "measurements missing", this->count - this->seq_no, - this->count, pen_names, vid, names, name); + 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; } @@ -329,7 +317,7 @@ METHOD(pts_component_t, destroy, void, if (this->is_registering) { count = this->pts_db->delete_comp_measurements(this->pts_db, - this->cid, this->kid); + this->cid, this->aik_id); vid = this->name->get_vendor_id(this->name); name = this->name->get_name(this->name); names = pts_components->get_comp_func_names(pts_components, vid); @@ -337,7 +325,6 @@ METHOD(pts_component_t, destroy, void, "evidence measurements", count, pen_names, vid, names, name); } this->name->destroy(this->name); - free(this->keyid.ptr); free(this); } } diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.c b/src/libpts/pts/components/ita/ita_comp_tgrub.c index e3acd8774..097e4c89c 100644 --- a/src/libpts/pts/components/ita/ita_comp_tgrub.c +++ b/src/libpts/pts/components/ita/ita_comp_tgrub.c @@ -49,7 +49,6 @@ struct pts_ita_comp_tgrub_t { */ pts_database_t *pts_db; - /** * Reference count */ @@ -126,7 +125,8 @@ METHOD(pts_component_t, verify, status_t, pts_pcr_transform_t transform; pts_pcr_t *pcrs; time_t measurement_time; - chunk_t measurement, pcr_before, pcr_after; + chunk_t pcr_before, pcr_after; + chunk_t measurement __attribute__((unused)); pcrs = pts->get_pcrs(pts); measurement = evidence->get_measurement(evidence, &extended_pcr, @@ -155,7 +155,7 @@ METHOD(pts_component_t, verify, status_t, } METHOD(pts_component_t, finalize, bool, - pts_ita_comp_tgrub_t *this, u_int8_t qualifier) + pts_ita_comp_tgrub_t *this, u_int8_t qualifier, bio_writer_t *result) { return FALSE; } @@ -206,4 +206,3 @@ pts_component_t *pts_ita_comp_tgrub_create(u_int32_t depth, return &this->public; } - diff --git a/src/libpts/pts/components/pts_component.h b/src/libpts/pts/components/pts_component.h index da339a55f..71b1ad59c 100644 --- a/src/libpts/pts/components/pts_component.h +++ b/src/libpts/pts/components/pts_component.h @@ -30,6 +30,7 @@ typedef struct pts_component_t pts_component_t; #include "pts/components/pts_comp_evidence.h" #include <library.h> +#include <bio/bio_writer.h> /** * PTS Functional Component Interface @@ -85,9 +86,11 @@ struct pts_component_t { * 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); + bool (*finalize)(pts_component_t *this, u_int8_t qualifier, + bio_writer_t *result); /** * Get a new reference to the PTS Functional Component diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c index 3ab9b92e6..2fff4c901 100644 --- a/src/libpts/pts/pts.c +++ b/src/libpts/pts/pts.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * 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 @@ -21,6 +22,10 @@ #include <bio/bio_reader.h> #ifdef TSS_TROUSERS +#ifdef _BASETSD_H_ +/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */ +# define _BASETSD_H +#endif #include <trousers/tss.h> #include <trousers/trousers.h> #else @@ -34,7 +39,6 @@ #include <sys/types.h> #include <sys/stat.h> -#include <sys/utsname.h> #include <libgen.h> #include <unistd.h> #include <errno.h> @@ -88,9 +92,9 @@ struct private_pts_t { chunk_t secret; /** - * Platform and OS Info + * Primary key of platform entry in database */ - char *platform_info; + int platform_id; /** * TRUE if IMC-PTS, FALSE if IMV-PTS @@ -118,6 +122,11 @@ struct private_pts_t { certificate_t *aik; /** + * Primary key referening AIK in database + */ + int aik_id; + + /** * Shadow PCR set */ pts_pcr_t *pcrs; @@ -296,29 +305,23 @@ METHOD(pts_t, calculate_secret, bool, */ static void print_tpm_version_info(private_pts_t *this) { - TPM_CAP_VERSION_INFO versionInfo; - UINT64 offset = 0; - TSS_RESULT result; + TPM_CAP_VERSION_INFO *info; - result = Trspi_UnloadBlob_CAP_VERSION_INFO(&offset, - this->tpm_version_info.ptr, &versionInfo); - if (result != TSS_SUCCESS) + info = (TPM_CAP_VERSION_INFO*)this->tpm_version_info.ptr; + + if (this->tpm_version_info.len >= + sizeof(*info) - sizeof(info->vendorSpecific)) { - DBG1(DBG_PTS, "could not parse tpm version info: tss error 0x%x", - result); + DBG2(DBG_PTS, "TPM Version Info: Chip Version: %u.%u.%u.%u, " + "Spec Level: %u, Errata Rev: %u, Vendor ID: %.4s", + info->version.major, info->version.minor, + info->version.revMajor, info->version.revMinor, + untoh16(&info->specLevel), info->errataRev, info->tpmVendorID); } else { - DBG2(DBG_PTS, "TPM 1.2 Version Info: Chip Version: %hhu.%hhu.%hhu.%hhu," - " Spec Level: %hu, Errata Rev: %hhu, Vendor ID: %.4s [%.*s]", - versionInfo.version.major, versionInfo.version.minor, - versionInfo.version.revMajor, versionInfo.version.revMinor, - versionInfo.specLevel, versionInfo.errataRev, - versionInfo.tpmVendorID, versionInfo.vendorSpecificSize, - versionInfo.vendorSpecificSize ? - (char*)versionInfo.vendorSpecific : ""); + DBG1(DBG_PTS, "could not parse tpm version info"); } - free(versionInfo.vendorSpecific); } #else @@ -330,22 +333,16 @@ static void print_tpm_version_info(private_pts_t *this) #endif /* TSS_TROUSERS */ -METHOD(pts_t, get_platform_info, char*, +METHOD(pts_t, get_platform_id, int, private_pts_t *this) { - return this->platform_info; + return this->platform_id; } -METHOD(pts_t, set_platform_info, void, - private_pts_t *this, chunk_t name, chunk_t version) +METHOD(pts_t, set_platform_id, void, + private_pts_t *this, int pid) { - int len = name.len + 1 + version.len + 1; - - /* platform info is a concatenation of OS name and OS version */ - free(this->platform_info); - this->platform_info = malloc(len); - snprintf(this->platform_info, len, "%.*s %.*s", (int)name.len, name.ptr, - (int)version.len, version.ptr); + this->platform_id = pid; } METHOD(pts_t, get_tpm_version_info, bool, @@ -372,42 +369,31 @@ METHOD(pts_t, set_tpm_version_info, void, */ static void load_aik_blob(private_pts_t *this) { - char *blob_path; - FILE *fp; - u_int32_t aikBlobLen; + char *path; + chunk_t *map; - blob_path = lib->settings->get_str(lib->settings, + path = lib->settings->get_str(lib->settings, "%s.plugins.imc-attestation.aik_blob", NULL, lib->ns); - - if (blob_path) + if (path) { - /* Read aik key blob from a file */ - if ((fp = fopen(blob_path, "r")) == NULL) - { - DBG1(DBG_PTS, "unable to open AIK Blob file: %s", blob_path); - return; - } - - fseek(fp, 0, SEEK_END); - aikBlobLen = ftell(fp); - fseek(fp, 0L, SEEK_SET); - - this->aik_blob = chunk_alloc(aikBlobLen); - if (fread(this->aik_blob.ptr, 1, aikBlobLen, fp) == aikBlobLen) + map = chunk_map(path, FALSE); + if (map) { - DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path); - DBG3(DBG_PTS, "AIK Blob: %B", &this->aik_blob); + DBG2(DBG_PTS, "loaded AIK Blob from '%s'", path); + DBG3(DBG_PTS, "AIK Blob: %B", map); + this->aik_blob = chunk_clone(*map); + chunk_unmap(map); } else { - DBG1(DBG_PTS, "unable to read AIK Blob file '%s'", blob_path); - chunk_free(&this->aik_blob); + DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s", + path, strerror(errno)); } - fclose(fp); - return; } - - DBG1(DBG_PTS, "AIK Blob is not available"); + else + { + DBG1(DBG_PTS, "AIK Blob is not available"); + } } /** @@ -421,7 +407,7 @@ static void load_aik(private_pts_t *this) cert_path = lib->settings->get_str(lib->settings, "%s.plugins.imc-attestation.aik_cert", NULL, lib->ns); key_path = lib->settings->get_str(lib->settings, - "%s.plugins.imc-attestation.aik_key", NULL, lib->ns); + "%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns); if (cert_path) { @@ -456,37 +442,17 @@ METHOD(pts_t, get_aik, certificate_t*, } METHOD(pts_t, set_aik, void, - private_pts_t *this, certificate_t *aik) + private_pts_t *this, certificate_t *aik, int aik_id) { DESTROY_IF(this->aik); this->aik = aik->get_ref(aik); + this->aik_id = aik_id; } -METHOD(pts_t, get_aik_keyid, bool, - private_pts_t *this, chunk_t *keyid) +METHOD(pts_t, get_aik_id, int, + private_pts_t *this) { - public_key_t *public; - bool success; - - if (!this->aik) - { - DBG1(DBG_PTS, "no AIK certificate available"); - return FALSE; - } - public = this->aik->get_public_key(this->aik); - if (!public) - { - DBG1(DBG_PTS, "no AIK public key available"); - return FALSE; - } - success = public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, keyid); - if (!success) - { - DBG1(DBG_PTS, "no SHA-1 AIK public key info ID available"); - } - public->destroy(public); - - return success; + return this->aik_id; } METHOD(pts_t, is_path_valid, bool, @@ -557,6 +523,7 @@ static bool file_metadata(char *pathname, pts_file_metadata_t **entry) { this->type = PTS_FILE_FIFO; } +#ifndef WIN32 else if (S_ISLNK(st.st_mode)) { this->type = PTS_FILE_SYM_LINK; @@ -565,6 +532,7 @@ static bool file_metadata(char *pathname, pts_file_metadata_t **entry) { this->type = PTS_FILE_SOCKET; } +#endif /* WIN32 */ else { this->type = PTS_FILE_OTHER; @@ -644,7 +612,8 @@ METHOD(pts_t, read_pcr, bool, TSS_HCONTEXT hContext; TSS_HTPM hTPM; TSS_RESULT result; - chunk_t rgbPcrValue; + BYTE *buf; + UINT32 len; bool success = FALSE; @@ -665,12 +634,12 @@ METHOD(pts_t, read_pcr, bool, { goto err; } - result = Tspi_TPM_PcrRead(hTPM, pcr_num, (UINT32*)&rgbPcrValue.len, &rgbPcrValue.ptr); + result = Tspi_TPM_PcrRead(hTPM, pcr_num, &len, &buf); if (result != TSS_SUCCESS) { goto err; } - *pcr_value = chunk_clone(rgbPcrValue); + *pcr_value = chunk_clone(chunk_create(buf, len)); DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, pcr_value); success = TRUE; @@ -1093,7 +1062,6 @@ METHOD(pts_t, destroy, void, free(this->initiator_nonce.ptr); free(this->responder_nonce.ptr); free(this->secret.ptr); - free(this->platform_info); free(this->aik_blob.ptr); free(this->tpm_version_info.ptr); free(this); @@ -1187,13 +1155,13 @@ pts_t *pts_create(bool is_imc) .get_my_public_value = _get_my_public_value, .set_peer_public_value = _set_peer_public_value, .calculate_secret = _calculate_secret, - .get_platform_info = _get_platform_info, - .set_platform_info = _set_platform_info, + .get_platform_id = _get_platform_id, + .set_platform_id = _set_platform_id, .get_tpm_version_info = _get_tpm_version_info, .set_tpm_version_info = _set_tpm_version_info, .get_aik = _get_aik, .set_aik = _set_aik, - .get_aik_keyid = _get_aik_keyid, + .get_aik_id = _get_aik_id, .is_path_valid = _is_path_valid, .get_metadata = _get_metadata, .read_pcr = _read_pcr, diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h index 11154aa38..fead588ae 100644 --- a/src/libpts/pts/pts.h +++ b/src/libpts/pts/pts.h @@ -1,5 +1,6 @@ /* * 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 @@ -162,19 +163,18 @@ struct pts_t { bool (*calculate_secret) (pts_t *this); /** - * Get Platform and OS Info + * Get primary key of platform entry in database * * @return Platform and OS info */ - char* (*get_platform_info)(pts_t *this); + int (*get_platform_id)(pts_t *this); /** - * Set Platform and OS Info + * Set primary key of platform entry in database * - * @param name OS name - * @param version OS version + * @param pid Primary key of platform entry in database */ - void (*set_platform_info)(pts_t *this, chunk_t name, chunk_t version); + void (*set_platform_id)(pts_t *this, int pid); /** * Get TPM 1.2 Version Info @@ -202,16 +202,16 @@ struct pts_t { * 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); + void (*set_aik)(pts_t *this, certificate_t *aik, int aik_id); /** - * Get SHA-1 Attestation Identity Public Key Info ID + * Get primary key referencing AIK in database * - * @param keyid AIK ID - * @return TRUE if AIK ID exists + * @return Primary key referencing AIK in database */ - bool (*get_aik_keyid)(pts_t *this, chunk_t *keyid); + int (*get_aik_id)(pts_t *this); /** * Check whether path is valid file/directory on filesystem diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c index fda644a6a..d7b85c138 100644 --- a/src/libpts/pts/pts_database.c +++ b/src/libpts/pts/pts_database.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * 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 @@ -47,7 +48,7 @@ METHOD(pts_database_t, get_pathname, char*, private_pts_database_t *this, bool is_dir, int id) { enumerator_t *e; - char *path, *name, *pathname; + char *path, *name, *sep, *pathname = NULL; if (is_dir) { @@ -69,11 +70,21 @@ METHOD(pts_database_t, get_pathname, char*, "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) || - asprintf(&pathname, "%s%s%s", - path, streq(path, "/") ? "" : "/", name) == -1) + if (e && e->enumerate(e, &path, &name)) { - pathname = NULL; + 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); @@ -82,7 +93,7 @@ METHOD(pts_database_t, get_pathname, char*, } METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, - private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, + private_pts_database_t *this, int pid, pts_meas_algorithms_t algo, bool is_dir, int id) { enumerator_t *e; @@ -90,73 +101,34 @@ METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, if (is_dir) { e = this->db->query(this->db, - "SELECT f.name, fh.hash FROM file_hashes AS fh " + "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh " "JOIN files AS f ON f.id = fh.file " - "JOIN products AS p ON p.id = fh.product " "JOIN directories as d ON d.id = f.dir " - "WHERE p.name = ? AND fh.algo = ? AND d.id = ? " + "WHERE fh.product = ? AND fh.algo = ? AND d.id = ? " "ORDER BY f.name", - DB_TEXT, product, DB_INT, algo, DB_INT, id, DB_TEXT, DB_BLOB); + DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB); } else { e = this->db->query(this->db, - "SELECT f.name, fh.hash FROM file_hashes AS fh " + "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh " "JOIN files AS f ON f.id = fh.file " - "JOIN products AS p ON p.id = fh.product " - "WHERE p.name = ? AND fh.algo = ? AND fh.file = ?", - DB_TEXT, product, DB_INT, algo, DB_INT, id, DB_TEXT, DB_BLOB); + "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, check_aik_keyid, status_t, - private_pts_database_t *this, chunk_t keyid, int *kid) -{ - enumerator_t *e; - - /* If the AIK is registered get the primary key */ - e = this->db->query(this->db, - "SELECT id FROM keys WHERE keyid = ?", DB_BLOB, keyid, DB_INT); - if (!e) - { - DBG1(DBG_PTS, "no database query enumerator returned"); - return FAILED; - } - if (!e->enumerate(e, kid)) - { - DBG1(DBG_PTS, "AIK %#B is not registered in database", &keyid); - e->destroy(e); - return FAILED; - } - e->destroy(e); - - return SUCCESS; -} - METHOD(pts_database_t, add_file_measurement, status_t, - private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, + 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, pid = 0; + int hash_id, fid; status_t status = SUCCESS; - /* get primary key of product string */ - e = this->db->query(this->db, - "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT); - if (e) - { - e->enumerate(e, &pid); - e->destroy(e); - } - if (pid == 0) - { - return FAILED; - } - if (is_dir) { /* does filename entry already exist? */ @@ -242,18 +214,16 @@ METHOD(pts_database_t, add_file_measurement, status_t, return status; } -METHOD(pts_database_t, check_file_measurement, status_t, - private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, - chunk_t measurement, char *filename) +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; - chunk_t hash; - status_t status = NOT_FOUND; char *dir, *file; if (strlen(filename) < 1) { - return INVALID_ARG; + return NULL; } /* separate filename into directory and basename components */ @@ -265,84 +235,40 @@ METHOD(pts_database_t, check_file_measurement, status_t, e = this->db->query(this->db, "SELECT fh.hash FROM file_hashes AS fh " "JOIN files AS f ON f.id = fh.file " - "JOIN products AS p ON p.id = fh.product " - "WHERE p.name = ? AND f.name = ? AND fh.algo = ?", - DB_TEXT, product, DB_TEXT, file, DB_INT, algo, DB_BLOB); + "WHERE fh.product = ? AND f.name = ? AND fh.algo = ?", + DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_BLOB); } else { /* absolute pathname */ - bool dir_found; 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) + + if (!e || !e->enumerate(e, &did)) { - status = FAILED; goto err; } - dir_found = e->enumerate(e, &did); e->destroy(e); - if (!dir_found) - { - status = NOT_FOUND; - goto err; - } e = this->db->query(this->db, "SELECT fh.hash FROM file_hashes AS fh " "JOIN files AS f ON f.id = fh.file " - "JOIN products AS p ON p.id = fh.product " - "WHERE p.name = ? AND f.dir = ? AND f.name = ? AND fh.algo = ?", - DB_TEXT, product, DB_INT, did, DB_TEXT, file, DB_INT, algo, - DB_BLOB); - } - if (!e) - { - status = FAILED; - goto err; + "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); } - while (e->enumerate(e, &hash)) - { - /* with relative filenames there might be multiple entries */ - if (chunk_equals(measurement, hash)) - { - status = SUCCESS; - break; - } - else - { - status = VERIFY_ERROR; - } - } - e->destroy(e); err: free(file); free(dir); - return status; -} - -METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*, - private_pts_database_t *this, int kid) -{ - enumerator_t *e; - - /* look for all entries belonging to an AIK in the components table */ - e = this->db->query(this->db, - "SELECT c.vendor_id, c.name, c.qualifier, kc.depth " - "FROM components AS c " - "JOIN key_component AS kc ON c.id = kc.component " - "WHERE kc.key = ? ORDER BY kc.seq_no", - DB_INT, kid, DB_INT, DB_INT, DB_INT, DB_INT); return e; } METHOD(pts_database_t, check_comp_measurement, status_t, - private_pts_database_t *this, chunk_t measurement, int cid, int kid, + 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; @@ -353,7 +279,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t, "SELECT hash FROM component_hashes " "WHERE component = ? AND key = ? " "AND seq_no = ? AND pcr = ? AND algo = ? ", - DB_INT, cid, DB_INT, kid, DB_INT, seq_no, + DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, DB_INT, pcr, DB_INT, algo, DB_BLOB); if (!e) { @@ -390,7 +316,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t, } METHOD(pts_database_t, insert_comp_measurement, status_t, - private_pts_database_t *this, chunk_t measurement, int cid, int kid, + 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; @@ -399,7 +325,7 @@ METHOD(pts_database_t, insert_comp_measurement, status_t, "INSERT INTO component_hashes " "(component, key, seq_no, pcr, algo, hash) " "VALUES (?, ?, ?, ?, ?, ?)", - DB_INT, cid, DB_INT, kid, DB_INT, seq_no, DB_INT, pcr, + DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, DB_INT, pcr, DB_INT, algo, DB_BLOB, measurement) == 1) { return SUCCESS; @@ -410,17 +336,17 @@ METHOD(pts_database_t, insert_comp_measurement, status_t, } METHOD(pts_database_t, delete_comp_measurements, int, - private_pts_database_t *this, int cid, int kid) + 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, kid); + 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, - chunk_t keyid, pts_meas_algorithms_t algo, int *cid, int *kid, int *count) + int aik_id, pts_meas_algorithms_t algo, int *cid, int *count) { enumerator_t *e; status_t status = SUCCESS; @@ -428,11 +354,6 @@ METHOD(pts_database_t, get_comp_measurement_count, status_t, /* Initialize count */ *count = 0; - if (_check_aik_keyid(this, keyid, kid) != SUCCESS) - { - return FAILED; - } - /* Get the primary key of the Component Functional Name */ e = this->db->query(this->db, "SELECT id FROM components " @@ -458,7 +379,7 @@ METHOD(pts_database_t, get_comp_measurement_count, status_t, e = this->db->query(this->db, "SELECT COUNT(*) FROM component_hashes AS ch " "WHERE component = ? AND key = ? AND algo = ?", - DB_INT, *cid, DB_INT, *kid, DB_INT, algo, DB_INT); + DB_INT, *cid, DB_INT, aik_id, DB_INT, algo, DB_INT); if (!e) { DBG1(DBG_PTS, "no database query enumerator returned"); @@ -495,11 +416,9 @@ pts_database_t *pts_database_create(imv_database_t *imv_db) INIT(this, .public = { .get_pathname = _get_pathname, - .create_comp_evid_enumerator = _create_comp_evid_enumerator, .create_file_hash_enumerator = _create_file_hash_enumerator, - .check_aik_keyid = _check_aik_keyid, .add_file_measurement = _add_file_measurement, - .check_file_measurement = _check_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, @@ -511,4 +430,3 @@ pts_database_t *pts_database_create(imv_database_t *imv_db) return &this->public; } - diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h index eb8aca346..a6c9fb3b6 100644 --- a/src/libpts/pts/pts_database.h +++ b/src/libpts/pts/pts_database.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -47,37 +47,20 @@ struct pts_database_t { /** * Get stored measurement hash for single file or directory entries * - * @param product Software product (os, vpn client, etc.) + * @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, - char *product, pts_meas_algorithms_t algo, + int pid, pts_meas_algorithms_t algo, bool is_dir, int id); /** - * Check if an AIK given by its keyid is registered in the database - * - * @param keyid AIK keyid (SHA-1 hash of the AIK public key info) - * @param kid Primary key of AIK entry in keys table - * @return SUCCESS if AIK is present, FAILED otherwise - */ - status_t (*check_aik_keyid)(pts_database_t *this, chunk_t keyid, int *kid); - - /** - * Get functional components to request evidence of - * - * @param kid Primary key of AIK entry in keys table - * @return Enumerator over all matching components - */ - enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, int kid); - - /** * Add PTS file measurement reference value * - * @param product Software product (os, vpn client, etc.) + * @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 @@ -85,37 +68,36 @@ struct pts_database_t { * @param id Primary key into direcories/files table * @return Status */ - status_t (*add_file_measurement)(pts_database_t *this, char *product, + 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); /** - * Check PTS file measurement against reference stored in database + * Get PTS measurement[s] for a given filename stored in database * - * @param product Software product (os, vpn client, etc.) + * @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 - * @return Status + * @param filename Name of the file to be checked + * @return Enumerator over all matching measurement hashes */ - status_t (*check_file_measurement)(pts_database_t *this, char *product, - pts_meas_algorithms_t algo, - chunk_t measurement, char *filename); + 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 kid Primary key of AIK entry in keys table + * @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 kid, int seq_no, int pcr, + int cid, int aik_id, int seq_no, int pcr, pts_meas_algorithms_t algo); /** @@ -123,40 +105,38 @@ struct pts_database_t { * * @param measurement Measurement hash * @param cid Primary key of Component Functional Name entry - * @param kid Primary key of AIK entry in keys table + * @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 kid, int seq_no, int pcr, + 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 kid Primary key of AIK entry in keys table + * @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 kid); + 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 keyid SHA-1 hash of AIK public key info + * @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 kid Primary key of AIK entry in keys table * @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, chunk_t keyid, - pts_meas_algorithms_t algo, int *cid, int *kid, - int *count); + 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. diff --git a/src/libpts/pts/pts_file_meas.c b/src/libpts/pts/pts_file_meas.c index 77a0957bb..478892aea 100644 --- a/src/libpts/pts/pts_file_meas.c +++ b/src/libpts/pts/pts_file_meas.c @@ -1,5 +1,6 @@ /* * 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 @@ -112,19 +113,43 @@ METHOD(pts_file_meas_t, create_enumerator, enumerator_t*, } METHOD(pts_file_meas_t, check, bool, - private_pts_file_meas_t *this, pts_database_t *pts_db, char *product, + private_pts_file_meas_t *this, pts_database_t *pts_db, int pid, pts_meas_algorithms_t algo) { - enumerator_t *enumerator; + 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 = pts_db->check_file_measurement(pts_db, product, algo, - entry->measurement, entry->filename); + 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: @@ -159,47 +184,75 @@ METHOD(pts_file_meas_t, check, bool, 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; - bool found, success = TRUE; + enumerator_t *enumerator = NULL; + bool found = FALSE, match = FALSE, success = TRUE; - while (e_hash->enumerate(e_hash, &filename, &measurement)) + while (e_hash->enumerate(e_hash, &fid, &filename, &measurement)) { - found = FALSE; - - enumerator = this->list->create_enumerator(this->list); - while (enumerator->enumerate(enumerator, &entry)) + if (fid != fid_last) { - if (!is_dir || streq(filename, entry->filename)) + if (found && !match) { - found = TRUE; - break; + /* 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); } - } - enumerator->destroy(enumerator); - if (!found) - { - DBG1(DBG_PTS, " no measurement found for '%s'", filename); - success = FALSE; - continue; - } - if (chunk_equals(measurement, entry->measurement)) - { - DBG2(DBG_PTS, " %#B for '%s' is ok", &measurement, filename); - } - else - { - DBG1(DBG_PTS, " %#B for '%s' is incorrect", &measurement, filename); - success = FALSE; + /* 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 (!is_dir) + + if (found && !match) { - break; + 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; } diff --git a/src/libpts/pts/pts_file_meas.h b/src/libpts/pts/pts_file_meas.h index a13bb29ba..4bf28e280 100644 --- a/src/libpts/pts/pts_file_meas.h +++ b/src/libpts/pts/pts_file_meas.h @@ -1,5 +1,6 @@ /* * 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 @@ -65,11 +66,11 @@ struct pts_file_meas_t { * Check PTS File Measurements against reference value in the database * * @param db PTS Measurement database - * @param product Software product (os, vpn client, etc.) + * @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, char* product, + bool (*check)(pts_file_meas_t *this, pts_database_t *db, int pid, pts_meas_algorithms_t algo); /** diff --git a/src/libpts/pts/pts_ima_bios_list.c b/src/libpts/pts/pts_ima_bios_list.c new file mode 100644 index 000000000..5051b6c2d --- /dev/null +++ b/src/libpts/pts/pts_ima_bios_list.c @@ -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; +} diff --git a/src/libpts/pts/pts_ima_bios_list.h b/src/libpts/pts/pts_ima_bios_list.h new file mode 100644 index 000000000..ad162e15a --- /dev/null +++ b/src/libpts/pts/pts_ima_bios_list.h @@ -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_ @}*/ diff --git a/src/libpts/pts/pts_ima_event_list.c b/src/libpts/pts/pts_ima_event_list.c new file mode 100644 index 000000000..9bff4654b --- /dev/null +++ b/src/libpts/pts/pts_ima_event_list.c @@ -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; +} diff --git a/src/libpts/pts/pts_ima_event_list.h b/src/libpts/pts/pts_ima_event_list.h new file mode 100644 index 000000000..bf5478a51 --- /dev/null +++ b/src/libpts/pts/pts_ima_event_list.h @@ -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_ @}*/ diff --git a/src/libpts/pts/pts_meas_algo.c b/src/libpts/pts/pts_meas_algo.c index 16a66e7b3..c06371123 100644 --- a/src/libpts/pts/pts_meas_algo.c +++ b/src/libpts/pts/pts_meas_algo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -28,10 +28,7 @@ ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA256, PTS_MEAS_ALGO_SHA256, ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1, PTS_MEAS_ALGO_SHA1, PTS_MEAS_ALGO_SHA256, "SHA1"); -ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1_IMA, PTS_MEAS_ALGO_SHA1_IMA, - PTS_MEAS_ALGO_SHA1, - "SHA1-IMA"); -ENUM_END(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1_IMA); +ENUM_END(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1); /** * Described in header. diff --git a/src/libpts/pts/pts_meas_algo.h b/src/libpts/pts/pts_meas_algo.h index 27cdaea7e..eec7e7981 100644 --- a/src/libpts/pts/pts_meas_algo.h +++ b/src/libpts/pts/pts_meas_algo.h @@ -1,5 +1,6 @@ /* * 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 @@ -33,8 +34,7 @@ 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), - PTS_MEAS_ALGO_SHA1_IMA = (1<<16), /* internal use only */ + PTS_MEAS_ALGO_SHA1 = (1<<15) }; /** diff --git a/src/libpts/swid/swid_error.c b/src/libpts/swid/swid_error.c index 7f7da7688..7f3c34476 100644 --- a/src/libpts/swid/swid_error.c +++ b/src/libpts/swid/swid_error.c @@ -40,7 +40,7 @@ pa_tnc_attr_t* swid_error_create(swid_error_code_t code, u_int32_t request_id, writer->write_uint32(writer, request_id); if (code == TCG_SWID_RESPONSE_TOO_LARGE) { - writer->write_uint16(writer, max_attr_size); + writer->write_uint32(writer, max_attr_size); } if (description) { diff --git a/src/libpts/swid/swid_inventory.c b/src/libpts/swid/swid_inventory.c index a71682f43..a9f081efa 100644 --- a/src/libpts/swid/swid_inventory.c +++ b/src/libpts/swid/swid_inventory.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,6 +18,7 @@ #include "swid_tag_id.h" #include <collections/linked_list.h> +#include <bio/bio_writer.h> #include <utils/debug.h> #include <stdio.h> @@ -51,6 +52,194 @@ struct private_swid_inventory_t { 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) { @@ -72,7 +261,8 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname, { char * start, *stop; chunk_t tag_creator; - chunk_t unique_sw_id = chunk_empty, unique_seq_id = chunk_empty; + chunk_t unique_sw_id = chunk_empty, tag_file_path = chunk_empty; + if (!strstr(rel_name, "regid.")) { continue; @@ -121,14 +311,7 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname, goto end; } tag_creator = chunk_create(start, stop-start); - start = stop + 1; - stop = strchr(start, '_'); - if (stop) - { - unique_sw_id = chunk_create(start, stop-start); - start = stop + 1; - } stop = strstr(start, ".swidtag"); if (!stop) @@ -137,18 +320,13 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname, DBG1(DBG_IMC, " swidtag postfix not found"); goto end; } - if (unique_sw_id.ptr) - { - unique_seq_id = chunk_create(start, stop-start); - } - else - { - unique_sw_id = chunk_create(start, stop-start); - } + 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; @@ -156,10 +334,11 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname, target_enumerator = targets->create_enumerator(targets); while (target_enumerator->enumerate(target_enumerator, &tag_id)) { - if (chunk_equals(tag_id->get_unique_sw_id(tag_id, NULL), - unique_sw_id) && - chunk_equals(tag_id->get_tag_creator(tag_id), - tag_creator)) + 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; @@ -187,7 +366,7 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname, goto end; } - tag = swid_tag_create(*xml_tag, unique_seq_id); + tag = swid_tag_create(*xml_tag, tag_file_path); this->list->insert_last(this->list, tag); chunk_unmap(xml_tag); } @@ -195,10 +374,9 @@ static bool collect_tags(private_swid_inventory_t *this, char *pathname, { swid_tag_id_t *tag_id; - tag_id = swid_tag_id_create(tag_creator, unique_sw_id, unique_seq_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; @@ -210,8 +388,18 @@ end: } METHOD(swid_inventory_t, collect, bool, - private_swid_inventory_t *this, char *directory, swid_inventory_t *targets) + 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); } diff --git a/src/libpts/swid/swid_inventory.h b/src/libpts/swid/swid_inventory.h index 68d3047aa..7de8bb221 100644 --- a/src/libpts/swid/swid_inventory.h +++ b/src/libpts/swid/swid_inventory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -34,11 +34,14 @@ 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, - swid_inventory_t *targets); + 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 diff --git a/src/libpts/swid/swid_tag.c b/src/libpts/swid/swid_tag.c index 0b6519693..c71d5d2bd 100644 --- a/src/libpts/swid/swid_tag.c +++ b/src/libpts/swid/swid_tag.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -34,10 +34,14 @@ struct private_swid_tag_t { chunk_t encoding; /** - * Optional Unique Sequence ID + * Optional Tag File Path */ - chunk_t unique_seq_id; + chunk_t tag_file_path; + /** + * Reference count + */ + refcount_t ref; }; METHOD(swid_tag_t, get_encoding, chunk_t, @@ -46,39 +50,51 @@ METHOD(swid_tag_t, get_encoding, chunk_t, return this->encoding; } -METHOD(swid_tag_t, get_unique_seq_id, chunk_t, +METHOD(swid_tag_t, get_tag_file_path, chunk_t, private_swid_tag_t *this) { - return this->unique_seq_id; + return this->tag_file_path; +} + +METHOD(swid_tag_t, get_ref, swid_tag_t*, + private_swid_tag_t *this) +{ + ref_get(&this->ref); + return &this->public; } METHOD(swid_tag_t, destroy, void, private_swid_tag_t *this) { - free(this->encoding.ptr); - free(this->unique_seq_id.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->encoding.ptr); + free(this->tag_file_path.ptr); + free(this); + } } /** * See header */ -swid_tag_t *swid_tag_create(chunk_t encoding, chunk_t unique_seq_id) +swid_tag_t *swid_tag_create(chunk_t encoding, chunk_t tag_file_path) { private_swid_tag_t *this; INIT(this, .public = { .get_encoding = _get_encoding, - .get_unique_seq_id = _get_unique_seq_id, + .get_tag_file_path = _get_tag_file_path, + .get_ref = _get_ref, .destroy = _destroy, }, .encoding = chunk_clone(encoding), + .ref = 1, ); - if (unique_seq_id.len > 0) + if (tag_file_path.len > 0) { - this->unique_seq_id = chunk_clone(unique_seq_id); + this->tag_file_path = chunk_clone(tag_file_path); } return &this->public; diff --git a/src/libpts/swid/swid_tag.h b/src/libpts/swid/swid_tag.h index 9d3f86333..e20c538ea 100644 --- a/src/libpts/swid/swid_tag.h +++ b/src/libpts/swid/swid_tag.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -39,11 +39,18 @@ struct swid_tag_t { chunk_t (*get_encoding)(swid_tag_t *this); /** - * Get th Optional Unique Sequence ID + * Get th Optional Tag File Path * - * @return Optional Unique Sequence ID + * @return Optional Tag File Path */ - chunk_t (*get_unique_seq_id)(swid_tag_t *this); + chunk_t (*get_tag_file_path)(swid_tag_t *this); + + /** + * Get a new reference to the swid_tag object + * + * @return this, with an increased refcount + */ + swid_tag_t* (*get_ref)(swid_tag_t *this); /** * Destroys a swid_tag_t object. @@ -56,8 +63,8 @@ struct swid_tag_t { * Creates a swid_tag_t object * * @param encoding XML encoding of SWID tag - * @param unique_seq_id Unique Sequence ID or empty chunk + * @param tag_file_path Tag File Path or empty chunk */ -swid_tag_t* swid_tag_create(chunk_t encoding, chunk_t unique_seq_id); +swid_tag_t* swid_tag_create(chunk_t encoding, chunk_t tag_file_path); #endif /** SWID_TAG_H_ @}*/ diff --git a/src/libpts/swid/swid_tag_id.c b/src/libpts/swid/swid_tag_id.c index 7ad486d4b..8bede28a0 100644 --- a/src/libpts/swid/swid_tag_id.c +++ b/src/libpts/swid/swid_tag_id.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -39,10 +39,14 @@ struct private_swid_tag_id_t { chunk_t unique_sw_id; /** - * Optional Unique Sequence ID + * Tag File Path */ - chunk_t unique_seq_id; + chunk_t tag_file_path; + /** + * Reference count + */ + refcount_t ref; }; METHOD(swid_tag_id_t, get_tag_creator, chunk_t, @@ -52,29 +56,39 @@ METHOD(swid_tag_id_t, get_tag_creator, chunk_t, } METHOD(swid_tag_id_t, get_unique_sw_id, chunk_t, - private_swid_tag_id_t *this, chunk_t *unique_seq_id) + private_swid_tag_id_t *this, chunk_t *tag_file_path) { - if (unique_seq_id) + if (tag_file_path) { - *unique_seq_id = this->unique_seq_id; + *tag_file_path = this->tag_file_path; } return this->unique_sw_id; } +METHOD(swid_tag_id_t, get_ref, swid_tag_id_t*, + private_swid_tag_id_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + METHOD(swid_tag_id_t, destroy, void, private_swid_tag_id_t *this) { - free(this->tag_creator.ptr); - free(this->unique_sw_id.ptr); - free(this->unique_seq_id.ptr); - free(this); + if (ref_put(&this->ref)) + { + free(this->tag_creator.ptr); + free(this->unique_sw_id.ptr); + free(this->tag_file_path.ptr); + free(this); + } } /** * See header */ swid_tag_id_t *swid_tag_id_create(chunk_t tag_creator, chunk_t unique_sw_id, - chunk_t unique_seq_id) + chunk_t tag_file_path) { private_swid_tag_id_t *this; @@ -82,15 +96,17 @@ swid_tag_id_t *swid_tag_id_create(chunk_t tag_creator, chunk_t unique_sw_id, .public = { .get_tag_creator = _get_tag_creator, .get_unique_sw_id = _get_unique_sw_id, + .get_ref = _get_ref, .destroy = _destroy, }, .tag_creator = chunk_clone(tag_creator), .unique_sw_id = chunk_clone(unique_sw_id), + .ref = 1, ); - if (unique_seq_id.len > 0) + if (tag_file_path.len > 0) { - this->unique_seq_id = chunk_clone(unique_seq_id); + this->tag_file_path = chunk_clone(tag_file_path); } return &this->public; diff --git a/src/libpts/swid/swid_tag_id.h b/src/libpts/swid/swid_tag_id.h index d4715967d..d2a783b35 100644 --- a/src/libpts/swid/swid_tag_id.h +++ b/src/libpts/swid/swid_tag_id.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -39,12 +39,19 @@ struct swid_tag_id_t { chunk_t (*get_tag_creator)(swid_tag_id_t *this); /** - * Get the Unique Software ID and optional Unique Sequence ID + * Get the Unique Software ID and optional Tag File Path * - * @param Optional Unique Sequence ID + * @param Optional Tag File Path * @return Unique Software ID */ - chunk_t (*get_unique_sw_id)(swid_tag_id_t *this, chunk_t *unique_seq_id); + chunk_t (*get_unique_sw_id)(swid_tag_id_t *this, chunk_t *tag_file_path); + + /** + * Get a new reference to the swid_tag_id object + * + * @return this, with an increased refcount + */ + swid_tag_id_t* (*get_ref)(swid_tag_id_t *this); /** * Destroys a swid_tag_id_t object. @@ -58,9 +65,9 @@ struct swid_tag_id_t { * * @param tag_creator Tag Creator * @param unique_sw_id Unique Software ID - * @param unique_seq_id Unique Sequence ID or empty chunk + * @param tag_file_path Tag File Path or empty chunk */ swid_tag_id_t* swid_tag_id_create(chunk_t tag_creator, chunk_t unique_sw_id, - chunk_t unique_seq_id); + chunk_t tag_file_path); #endif /** SWID_TAG_ID_H_ @}*/ diff --git a/src/libpts/tcg/swid/tcg_swid_attr_req.c b/src/libpts/tcg/swid/tcg_swid_attr_req.c index b8e7962c1..c403d06f9 100644 --- a/src/libpts/tcg/swid/tcg_swid_attr_req.c +++ b/src/libpts/tcg/swid/tcg_swid_attr_req.c @@ -44,7 +44,6 @@ typedef struct private_tcg_swid_attr_req_t private_tcg_swid_attr_req_t; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#define SWID_REQ_SIZE 12 #define SWID_REQ_RESERVED_MASK 0x03 /** @@ -135,7 +134,7 @@ METHOD(pa_tnc_attr_t, build, void, return; } - writer = bio_writer_create(SWID_REQ_SIZE); + writer = bio_writer_create(TCG_SWID_REQ_MIN_SIZE); writer->write_uint8 (writer, this->flags); writer->write_uint24(writer, this->targets->get_count(this->targets)); writer->write_uint32(writer, this->request_id); @@ -163,7 +162,7 @@ METHOD(pa_tnc_attr_t, process, status_t, chunk_t tag_creator, unique_sw_id; swid_tag_id_t *tag_id; - if (this->value.len < SWID_REQ_SIZE) + if (this->value.len < TCG_SWID_REQ_MIN_SIZE) { DBG1(DBG_TNC, "insufficient data for SWID Request"); *offset = 0; @@ -181,7 +180,7 @@ METHOD(pa_tnc_attr_t, process, status_t, *offset = 4; return FAILED; } - *offset = SWID_REQ_SIZE; + *offset = TCG_SWID_REQ_MIN_SIZE; this->flags &= SWID_REQ_RESERVED_MASK; diff --git a/src/libpts/tcg/swid/tcg_swid_attr_req.h b/src/libpts/tcg/swid/tcg_swid_attr_req.h index 851b68d3b..59b597d84 100644 --- a/src/libpts/tcg/swid/tcg_swid_attr_req.h +++ b/src/libpts/tcg/swid/tcg_swid_attr_req.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -21,6 +21,8 @@ #ifndef TCG_SWID_ATTR_REQ_H_ #define TCG_SWID_ATTR_REQ_H_ +#define TCG_SWID_REQ_MIN_SIZE 12 + typedef struct tcg_swid_attr_req_t tcg_swid_attr_req_t; typedef enum tcg_swid_attr_req_flag_t tcg_swid_attr_req_flag_t; diff --git a/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.c b/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.c index 429919edd..33aa16d53 100644 --- a/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.c +++ b/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -42,12 +42,11 @@ typedef struct private_tcg_swid_attr_tag_id_inv_t private_tcg_swid_attr_tag_id_i * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Unique Software ID Length |Unique Software ID (var length)| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Unique Sequence ID Length |Unique Sequence ID (var length)| + * | Tag File Path Length | Tag File Path (var. length) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#define SWID_TAG_ID_INV_SIZE 16 -#define SWID_TAG_ID_INV_RESERVED 0x00 +#define TCG_SWID_TAG_ID_INV_RESERVED 0x00 /** * Private data of an tcg_swid_attr_tag_id_inv_t object. @@ -77,17 +76,17 @@ struct private_tcg_swid_attr_tag_id_inv_t { /** * Request ID */ - u_int32_t request_id; + uint32_t request_id; /** * Event ID Epoch */ - u_int32_t eid_epoch; + uint32_t eid_epoch; /** * Last Event ID */ - u_int32_t last_eid; + uint32_t last_eid; /** * SWID Tag ID Inventory @@ -129,7 +128,7 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; swid_tag_id_t *tag_id; - chunk_t tag_creator, unique_sw_id, unique_seq_id; + chunk_t tag_creator, unique_sw_id, tag_file_path; enumerator_t *enumerator; if (this->value.ptr) @@ -137,8 +136,8 @@ METHOD(pa_tnc_attr_t, build, void, return; } - writer = bio_writer_create(SWID_TAG_ID_INV_SIZE); - writer->write_uint8 (writer, SWID_TAG_ID_INV_RESERVED); + writer = bio_writer_create(TCG_SWID_TAG_ID_INV_MIN_SIZE); + writer->write_uint8 (writer, TCG_SWID_TAG_ID_INV_RESERVED); writer->write_uint24(writer, this->inventory->get_count(this->inventory)); writer->write_uint32(writer, this->request_id); writer->write_uint32(writer, this->eid_epoch); @@ -148,10 +147,10 @@ METHOD(pa_tnc_attr_t, build, void, while (enumerator->enumerate(enumerator, &tag_id)) { tag_creator = tag_id->get_tag_creator(tag_id); - unique_sw_id = tag_id->get_unique_sw_id(tag_id, &unique_seq_id); + unique_sw_id = tag_id->get_unique_sw_id(tag_id, &tag_file_path); writer->write_data16(writer, tag_creator); writer->write_data16(writer, unique_sw_id); - writer->write_data16(writer, unique_seq_id); + writer->write_data16(writer, tag_file_path); } enumerator->destroy(enumerator); @@ -160,15 +159,15 @@ METHOD(pa_tnc_attr_t, build, void, } METHOD(pa_tnc_attr_t, process, status_t, - private_tcg_swid_attr_tag_id_inv_t *this, u_int32_t *offset) + private_tcg_swid_attr_tag_id_inv_t *this, uint32_t *offset) { bio_reader_t *reader; - u_int32_t tag_id_count; - u_int8_t reserved; - chunk_t tag_creator, unique_sw_id, unique_seq_id; + uint32_t tag_id_count; + uint8_t reserved; + chunk_t tag_creator, unique_sw_id, tag_file_path; swid_tag_id_t *tag_id; - if (this->value.len < SWID_TAG_ID_INV_SIZE) + if (this->value.len < TCG_SWID_TAG_ID_INV_MIN_SIZE) { DBG1(DBG_TNC, "insufficient data for SWID Tag Identifier Inventory"); *offset = 0; @@ -181,7 +180,7 @@ METHOD(pa_tnc_attr_t, process, status_t, reader->read_uint32(reader, &this->request_id); reader->read_uint32(reader, &this->eid_epoch); reader->read_uint32(reader, &this->last_eid); - *offset = SWID_TAG_ID_INV_SIZE; + *offset = TCG_SWID_TAG_ID_INV_MIN_SIZE; while (tag_id_count--) { @@ -199,14 +198,14 @@ METHOD(pa_tnc_attr_t, process, status_t, } *offset += 2 + unique_sw_id.len; - if (!reader->read_data16(reader, &unique_seq_id)) + if (!reader->read_data16(reader, &tag_file_path)) { - DBG1(DBG_TNC, "insufficient data for Unique Sequence ID"); + DBG1(DBG_TNC, "insufficient data for Tag File Path"); return FAILED; } - *offset += 2 + unique_seq_id.len; + *offset += 2 + tag_file_path.len; - tag_id = swid_tag_id_create(tag_creator, unique_sw_id, unique_seq_id); + tag_id = swid_tag_id_create(tag_creator, unique_sw_id, tag_file_path); this->inventory->add(this->inventory, tag_id); } reader->destroy(reader); @@ -232,14 +231,20 @@ METHOD(pa_tnc_attr_t, destroy, void, } } -METHOD(tcg_swid_attr_tag_id_inv_t, get_request_id, u_int32_t, +METHOD(tcg_swid_attr_tag_id_inv_t, add, void, + private_tcg_swid_attr_tag_id_inv_t *this, swid_tag_id_t *tag_id) +{ + this->inventory->add(this->inventory, tag_id); +} + +METHOD(tcg_swid_attr_tag_id_inv_t, get_request_id, uint32_t, private_tcg_swid_attr_tag_id_inv_t *this) { return this->request_id; } -METHOD(tcg_swid_attr_tag_id_inv_t, get_last_eid, u_int32_t, - private_tcg_swid_attr_tag_id_inv_t *this, u_int32_t *eid_epoch) +METHOD(tcg_swid_attr_tag_id_inv_t, get_last_eid, uint32_t, + private_tcg_swid_attr_tag_id_inv_t *this, uint32_t *eid_epoch) { if (eid_epoch) { @@ -257,10 +262,9 @@ METHOD(tcg_swid_attr_tag_id_inv_t, get_inventory, swid_inventory_t*, /** * Described in header. */ -pa_tnc_attr_t *tcg_swid_attr_tag_id_inv_create(u_int32_t request_id, - u_int32_t eid_epoch, - u_int32_t eid, - swid_inventory_t *inventory) +pa_tnc_attr_t *tcg_swid_attr_tag_id_inv_create(uint32_t request_id, + uint32_t eid_epoch, + uint32_t eid) { private_tcg_swid_attr_tag_id_inv_t *this; @@ -276,6 +280,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_id_inv_create(u_int32_t request_id, .get_ref = _get_ref, .destroy = _destroy, }, + .add = _add, .get_request_id = _get_request_id, .get_last_eid = _get_last_eid, .get_inventory = _get_inventory, @@ -284,7 +289,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_id_inv_create(u_int32_t request_id, .request_id = request_id, .eid_epoch = eid_epoch, .last_eid = eid, - .inventory = inventory, + .inventory = swid_inventory_create(FALSE), .ref = 1, ); @@ -311,6 +316,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_id_inv_create_from_data(chunk_t data) .get_ref = _get_ref, .destroy = _destroy, }, + .add = _add, .get_request_id = _get_request_id, .get_last_eid = _get_last_eid, .get_inventory = _get_inventory, diff --git a/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.h b/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.h index 1a0cbe7d2..c4ade904e 100644 --- a/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.h +++ b/src/libpts/tcg/swid/tcg_swid_attr_tag_id_inv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ typedef struct tcg_swid_attr_tag_id_inv_t tcg_swid_attr_tag_id_inv_t; #include <pa_tnc/pa_tnc_attr.h> +#define TCG_SWID_TAG_ID_INV_MIN_SIZE 16 + /** * Class implementing the TCG SWID Tag Identifier Inventory attribute * @@ -41,11 +43,18 @@ struct tcg_swid_attr_tag_id_inv_t { pa_tnc_attr_t pa_tnc_attribute; /** + * Add a Tag ID to the attribute + * + * @param tag_id SWID Tag ID to be added + */ + void (*add)(tcg_swid_attr_tag_id_inv_t *this, swid_tag_id_t *tag_id); + + /** * Get Request ID * * @return Request ID */ - u_int32_t (*get_request_id)(tcg_swid_attr_tag_id_inv_t *this); + uint32_t (*get_request_id)(tcg_swid_attr_tag_id_inv_t *this); /** * Get Last Event ID @@ -53,8 +62,8 @@ struct tcg_swid_attr_tag_id_inv_t { * @param eid_epoch Event ID Epoch * @return Last Event ID */ - u_int32_t (*get_last_eid)(tcg_swid_attr_tag_id_inv_t *this, - u_int32_t *eid_epoch); + uint32_t (*get_last_eid)(tcg_swid_attr_tag_id_inv_t *this, + uint32_t *eid_epoch); /** * Get Inventory of SWID tag IDs @@ -71,12 +80,10 @@ struct tcg_swid_attr_tag_id_inv_t { * @param request_id Copy of the Request ID * @param eid_epoch Event ID Epoch * @param eid Last Event ID - * @param inventory SWID Tag Inventory */ -pa_tnc_attr_t* tcg_swid_attr_tag_id_inv_create(u_int32_t request_id, - u_int32_t eid_epoch, - u_int32_t eid, - swid_inventory_t *inventory); +pa_tnc_attr_t* tcg_swid_attr_tag_id_inv_create(uint32_t request_id, + uint32_t eid_epoch, + uint32_t eid); /** * Creates an tcg_swid_attr_tag_id_inv_t object from received data diff --git a/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.c b/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.c index 82b9ef958..fbb94c6c2 100644 --- a/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.c +++ b/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ typedef struct private_tcg_swid_attr_tag_inv_t private_tcg_swid_attr_tag_inv_t; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Last EID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Unique Sequence ID Length |Unique Sequence ID (var length)| + * | Tag File Path Length | Tag File Path (var length) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Tag Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -46,8 +46,7 @@ typedef struct private_tcg_swid_attr_tag_inv_t private_tcg_swid_attr_tag_inv_t; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#define SWID_TAG_INV_SIZE 16 -#define SWID_TAG_INV_RESERVED 0x00 +#define TCG_SWID_TAG_INV_RESERVED 0x00 /** * Private data of an tcg_swid_attr_tag_inv_t object. @@ -77,17 +76,17 @@ struct private_tcg_swid_attr_tag_inv_t { /** * Request ID */ - u_int32_t request_id; + uint32_t request_id; /** * Event ID Epoch */ - u_int32_t eid_epoch; + uint32_t eid_epoch; /** * Last Event ID */ - u_int32_t last_eid; + uint32_t last_eid; /** * SWID Tag Inventory @@ -136,8 +135,8 @@ METHOD(pa_tnc_attr_t, build, void, return; } - writer = bio_writer_create(SWID_TAG_INV_SIZE); - writer->write_uint8 (writer, SWID_TAG_INV_RESERVED); + writer = bio_writer_create(TCG_SWID_TAG_INV_MIN_SIZE); + writer->write_uint8 (writer, TCG_SWID_TAG_INV_RESERVED); writer->write_uint24(writer, this->inventory->get_count(this->inventory)); writer->write_uint32(writer, this->request_id); writer->write_uint32(writer, this->eid_epoch); @@ -146,7 +145,7 @@ METHOD(pa_tnc_attr_t, build, void, enumerator = this->inventory->create_enumerator(this->inventory); while (enumerator->enumerate(enumerator, &tag)) { - writer->write_data16(writer, tag->get_unique_seq_id(tag)); + writer->write_data16(writer, tag->get_tag_file_path(tag)); writer->write_data32(writer, tag->get_encoding(tag)); } enumerator->destroy(enumerator); @@ -156,15 +155,15 @@ METHOD(pa_tnc_attr_t, build, void, } METHOD(pa_tnc_attr_t, process, status_t, - private_tcg_swid_attr_tag_inv_t *this, u_int32_t *offset) + private_tcg_swid_attr_tag_inv_t *this, uint32_t *offset) { bio_reader_t *reader; - u_int32_t tag_count; - u_int8_t reserved; - chunk_t tag_encoding, unique_seq_id; + uint32_t tag_count; + uint8_t reserved; + chunk_t tag_encoding, tag_file_path; swid_tag_t *tag; - if (this->value.len < SWID_TAG_INV_SIZE) + if (this->value.len < TCG_SWID_TAG_INV_MIN_SIZE) { DBG1(DBG_TNC, "insufficient data for SWID Tag Inventory"); *offset = 0; @@ -177,16 +176,16 @@ METHOD(pa_tnc_attr_t, process, status_t, reader->read_uint32(reader, &this->request_id); reader->read_uint32(reader, &this->eid_epoch); reader->read_uint32(reader, &this->last_eid); - *offset = SWID_TAG_INV_SIZE; + *offset = TCG_SWID_TAG_INV_MIN_SIZE; while (tag_count--) { - if (!reader->read_data16(reader, &unique_seq_id)) + if (!reader->read_data16(reader, &tag_file_path)) { - DBG1(DBG_TNC, "insufficient data for Unique Sequence ID"); + DBG1(DBG_TNC, "insufficient data for Tag File Path"); return FAILED; } - *offset += 2 + unique_seq_id.len; + *offset += 2 + tag_file_path.len; if (!reader->read_data32(reader, &tag_encoding)) { @@ -195,7 +194,7 @@ METHOD(pa_tnc_attr_t, process, status_t, } *offset += 4 + tag_encoding.len; - tag = swid_tag_create(tag_encoding, unique_seq_id); + tag = swid_tag_create(tag_encoding, tag_file_path); this->inventory->add(this->inventory, tag); } reader->destroy(reader); @@ -221,14 +220,20 @@ METHOD(pa_tnc_attr_t, destroy, void, } } -METHOD(tcg_swid_attr_tag_inv_t, get_request_id, u_int32_t, +METHOD(tcg_swid_attr_tag_inv_t, add, void, + private_tcg_swid_attr_tag_inv_t *this, swid_tag_t *tag) +{ + this->inventory->add(this->inventory, tag); +} + +METHOD(tcg_swid_attr_tag_inv_t, get_request_id, uint32_t, private_tcg_swid_attr_tag_inv_t *this) { return this->request_id; } -METHOD(tcg_swid_attr_tag_inv_t, get_last_eid, u_int32_t, - private_tcg_swid_attr_tag_inv_t *this, u_int32_t *eid_epoch) +METHOD(tcg_swid_attr_tag_inv_t, get_last_eid, uint32_t, + private_tcg_swid_attr_tag_inv_t *this, uint32_t *eid_epoch) { if (eid_epoch) { @@ -246,9 +251,8 @@ METHOD(tcg_swid_attr_tag_inv_t, get_inventory, swid_inventory_t*, /** * Described in header. */ -pa_tnc_attr_t *tcg_swid_attr_tag_inv_create(u_int32_t request_id, - u_int32_t eid_epoch, u_int32_t eid, - swid_inventory_t *inventory) +pa_tnc_attr_t *tcg_swid_attr_tag_inv_create(uint32_t request_id, + uint32_t eid_epoch, uint32_t eid) { private_tcg_swid_attr_tag_inv_t *this; @@ -264,6 +268,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_inv_create(u_int32_t request_id, .get_ref = _get_ref, .destroy = _destroy, }, + .add = _add, .get_request_id = _get_request_id, .get_last_eid = _get_last_eid, .get_inventory = _get_inventory, @@ -272,7 +277,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_inv_create(u_int32_t request_id, .request_id = request_id, .eid_epoch = eid_epoch, .last_eid = eid, - .inventory = inventory, + .inventory = swid_inventory_create(TRUE), .ref = 1, ); @@ -299,6 +304,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_inv_create_from_data(chunk_t data) .get_ref = _get_ref, .destroy = _destroy, }, + .add = _add, .get_request_id = _get_request_id, .get_last_eid = _get_last_eid, .get_inventory = _get_inventory, diff --git a/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.h b/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.h index 433f55ee0..69966c7d6 100644 --- a/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.h +++ b/src/libpts/tcg/swid/tcg_swid_attr_tag_inv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Andreas Steffen + * Copyright (C) 2013-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ typedef struct tcg_swid_attr_tag_inv_t tcg_swid_attr_tag_inv_t; #include <pa_tnc/pa_tnc_attr.h> +#define TCG_SWID_TAG_INV_MIN_SIZE 16 + /** * Class implementing the TCG SWID Tag Inventory attribute * @@ -41,11 +43,17 @@ struct tcg_swid_attr_tag_inv_t { pa_tnc_attr_t pa_tnc_attribute; /** + * Add a Tag ID to the attribute + * + * @param tag SWID Tag to be added + */ + void (*add)(tcg_swid_attr_tag_inv_t *this, swid_tag_t *tag); + /** * Get Request ID * * @return Request ID */ - u_int32_t (*get_request_id)(tcg_swid_attr_tag_inv_t *this); + uint32_t (*get_request_id)(tcg_swid_attr_tag_inv_t *this); /** * Get Last Event ID @@ -53,8 +61,8 @@ struct tcg_swid_attr_tag_inv_t { * @param eid_epoch Event ID Epoch * @return Last Event ID */ - u_int32_t (*get_last_eid)(tcg_swid_attr_tag_inv_t *this, - u_int32_t *eid_epoch); + uint32_t (*get_last_eid)(tcg_swid_attr_tag_inv_t *this, + uint32_t *eid_epoch); /** * Get Inventory of SWID tags @@ -71,12 +79,10 @@ struct tcg_swid_attr_tag_inv_t { * @param request_id Copy of the Request ID * @param eid_epoch Event ID Epoch * @param eid Last Event ID - * @param inventory SWID Tag Inventory */ -pa_tnc_attr_t* tcg_swid_attr_tag_inv_create(u_int32_t request_id, - u_int32_t eid_epoch, - u_int32_t eid, - swid_inventory_t *inventory); +pa_tnc_attr_t* tcg_swid_attr_tag_inv_create(uint32_t request_id, + uint32_t eid_epoch, + uint32_t eid); /** * Creates an tcg_swid_attr_tag_inv_t object from received data |