diff options
author | Romain Francoise <rfrancoise@debian.org> | 2014-10-21 19:28:38 +0200 |
---|---|---|
committer | Romain Francoise <rfrancoise@debian.org> | 2014-10-21 19:41:50 +0200 |
commit | b23b0e5609ed4b3d29396a1727aab035fa4a395f (patch) | |
tree | 091d0b144dd92a0c124b7fbe9eae68f79cb975dc /src/libimcv/plugins | |
parent | 4a01a7e2574040cf246fd00ebff173b873c17349 (diff) | |
download | vyos-strongswan-b23b0e5609ed4b3d29396a1727aab035fa4a395f.tar.gz vyos-strongswan-b23b0e5609ed4b3d29396a1727aab035fa4a395f.zip |
Import upstream release 5.2.1
Diffstat (limited to 'src/libimcv/plugins')
58 files changed, 12534 insertions, 135 deletions
diff --git a/src/libimcv/plugins/imc_attestation/Makefile.am b/src/libimcv/plugins/imc_attestation/Makefile.am new file mode 100644 index 000000000..e7b1f1ce1 --- /dev/null +++ b/src/libimcv/plugins/imc_attestation/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +imcv_LTLIBRARIES = imc-attestation.la + +imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +imc_attestation_la_SOURCES = imc_attestation.c \ + imc_attestation_state.h imc_attestation_state.c \ + imc_attestation_process.h imc_attestation_process.c + +imc_attestation_la_LDFLAGS = -module -avoid-version -no-undefined diff --git a/src/libimcv/plugins/imc_attestation/Makefile.in b/src/libimcv/plugins/imc_attestation/Makefile.in new file mode 100644 index 000000000..3c5017f32 --- /dev/null +++ b/src/libimcv/plugins/imc_attestation/Makefile.in @@ -0,0 +1,765 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libimcv/plugins/imc_attestation +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/split-package-version.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(imcvdir)" +LTLIBRARIES = $(imcv_LTLIBRARIES) +imc_attestation_la_DEPENDENCIES = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +am_imc_attestation_la_OBJECTS = imc_attestation.lo \ + imc_attestation_state.lo imc_attestation_process.lo +imc_attestation_la_OBJECTS = $(am_imc_attestation_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +imc_attestation_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(imc_attestation_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(imc_attestation_la_SOURCES) +DIST_SOURCES = $(imc_attestation_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COVERAGE_CFLAGS = @COVERAGE_CFLAGS@ +COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GEM = @GEM@ +GENHTML = @GENHTML@ +GPERF = @GPERF@ +GPRBUILD = @GPRBUILD@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_BUILD = @PACKAGE_VERSION_BUILD@ +PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@ +PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@ +PACKAGE_VERSION_REVIEW = @PACKAGE_VERSION_REVIEW@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +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@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ +RUBYINCLUDE = @RUBYINCLUDE@ +RUBYLIB = @RUBYLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +UNWINDLIB = @UNWINDLIB@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +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@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +cmd_plugins = @cmd_plugins@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +fips_mode = @fips_mode@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ +sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ +systemdsystemunitdir = @systemdsystemunitdir@ +t_plugins = @t_plugins@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +imcv_LTLIBRARIES = imc-attestation.la +imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +imc_attestation_la_SOURCES = imc_attestation.c \ + imc_attestation_state.h imc_attestation_state.c \ + imc_attestation_process.h imc_attestation_process.c + +imc_attestation_la_LDFLAGS = -module -avoid-version -no-undefined +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libimcv/plugins/imc_attestation/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libimcv/plugins/imc_attestation/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-imcvLTLIBRARIES: $(imcv_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(imcvdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(imcvdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imcvdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imcvdir)"; \ + } + +uninstall-imcvLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imcvdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imcvdir)/$$f"; \ + done + +clean-imcvLTLIBRARIES: + -test -z "$(imcv_LTLIBRARIES)" || rm -f $(imcv_LTLIBRARIES) + @list='$(imcv_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +imc-attestation.la: $(imc_attestation_la_OBJECTS) $(imc_attestation_la_DEPENDENCIES) $(EXTRA_imc_attestation_la_DEPENDENCIES) + $(AM_V_CCLD)$(imc_attestation_la_LINK) -rpath $(imcvdir) $(imc_attestation_la_OBJECTS) $(imc_attestation_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imc_attestation.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imc_attestation_process.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imc_attestation_state.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(imcvdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-imcvLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-imcvLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-imcvLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-imcvLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-imcvLTLIBRARIES install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-imcvLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation.c b/src/libimcv/plugins/imc_attestation/imc_attestation.c new file mode 100644 index 000000000..0dd88b6a7 --- /dev/null +++ b/src/libimcv/plugins/imc_attestation/imc_attestation.c @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imc_attestation_state.h" +#include "imc_attestation_process.h" + +#include <imc/imc_agent.h> +#include <imc/imc_msg.h> +#include <ietf/ietf_attr.h> +#include <ietf/ietf_attr_pa_tnc_error.h> +#include <ietf/ietf_attr_product_info.h> +#include <ietf/ietf_attr_string_version.h> +#include <ietf/ietf_attr_assess_result.h> +#include <tcg/pts/tcg_pts_attr_proto_caps.h> +#include <tcg/pts/tcg_pts_attr_meas_algo.h> +#include <os_info/os_info.h> +#include <pts/pts_error.h> + +#include <tncif_pa_subtypes.h> + +#include <pen/pen.h> +#include <utils/debug.h> +#include <collections/linked_list.h> + +/* IMC definitions */ + +static const char imc_name[] = "Attestation"; + +static pen_type_t msg_types[] = { + { PEN_TCG, PA_SUBTYPE_TCG_PTS } +}; + +static imc_agent_t *imc_attestation; + +/** + * Supported PTS measurement algorithms + */ +static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE; + +/** + * Supported PTS Diffie Hellman Groups + */ +static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE; + +/** + * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_Initialize(TNC_IMCID imc_id, + TNC_Version min_version, + TNC_Version max_version, + TNC_Version *actual_version) +{ + bool mandatory_dh_groups; + + if (imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name); + return TNC_RESULT_ALREADY_INITIALIZED; + } + imc_attestation = imc_agent_create(imc_name, msg_types, countof(msg_types), + imc_id, actual_version); + if (!imc_attestation) + { + return TNC_RESULT_FATAL; + } + + mandatory_dh_groups = lib->settings->get_bool(lib->settings, + "%s.plugins.imc-attestation.mandatory_dh_groups", TRUE, lib->ns); + + if (!pts_meas_algo_probe(&supported_algorithms) || + !pts_dh_group_probe(&supported_dh_groups, mandatory_dh_groups)) + { + imc_attestation->destroy(imc_attestation); + imc_attestation = NULL; + return TNC_RESULT_FATAL; + } + + if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1) + { + DBG1(DBG_IMC, "no common IF-IMC version"); + return TNC_RESULT_NO_COMMON_VERSION; + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imc_state_t *state; + + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imc_attestation_state_create(connection_id); + return imc_attestation->create_state(imc_attestation, state); + case TNC_CONNECTION_STATE_HANDSHAKE: + if (imc_attestation->change_state(imc_attestation, connection_id, + new_state, &state) != TNC_RESULT_SUCCESS) + { + return TNC_RESULT_FATAL; + } + state->set_result(state, imc_id, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + return TNC_RESULT_SUCCESS; + case TNC_CONNECTION_STATE_DELETE: + return imc_attestation->delete_state(imc_attestation, connection_id); + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + case TNC_CONNECTION_STATE_ACCESS_NONE: + default: + return imc_attestation->change_state(imc_attestation, connection_id, + new_state, NULL); + } +} + + +/** + * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_BeginHandshake(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + + return TNC_RESULT_SUCCESS; +} + +static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) +{ + imc_msg_t *out_msg; + imc_attestation_state_t *attestation_state; + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + pen_type_t type; + TNC_Result result; + bool fatal_error = FALSE; + + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imc_msg_create_as_reply(in_msg); + + /* parse received PA-TNC message and handle local and remote errors */ + result = in_msg->receive(in_msg, out_msg, &fatal_error); + if (result != TNC_RESULT_SUCCESS) + { + out_msg->destroy(out_msg); + return result; + } + + /* analyze PA-TNC attributes */ + enumerator = in_msg->create_attribute_enumerator(in_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF) + { + if (type.type == IETF_ATTR_PA_TNC_ERROR) + { + ietf_attr_pa_tnc_error_t *error_attr; + pen_type_t error_code; + chunk_t msg_info; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; + error_code = error_attr->get_error_code(error_attr); + + if (error_code.vendor_id == PEN_TCG) + { + msg_info = error_attr->get_msg_info(error_attr); + + DBG1(DBG_IMC, "received TCG-PTS error '%N'", + pts_error_code_names, error_code.type); + DBG1(DBG_IMC, "error information: %B", &msg_info); + + result = TNC_RESULT_FATAL; + } + } + } + else if (type.vendor_id == PEN_TCG) + { + attestation_state = (imc_attestation_state_t*)state; + + if (!imc_attestation_process(attr, out_msg, attestation_state, + supported_algorithms, supported_dh_groups)) + { + result = TNC_RESULT_FATAL; + break; + } + } + } + enumerator->destroy(enumerator); + + if (result == TNC_RESULT_SUCCESS) + { + /* send PA-TNC message with the EXCL flag set */ + result = out_msg->send(out_msg, TRUE); + } + out_msg->destroy(out_msg); + + return result; +} + +/** + * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + imc_state_t *state; + imc_msg_t *in_msg; + TNC_Result result; + + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + if (!imc_attestation->get_state(imc_attestation, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + + in_msg = imc_msg_create_from_data(imc_attestation, state, connection_id, + msg_type, chunk_create(msg, msg_len)); + result = receive_message(state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_UInt32 msg_flags, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, + TNC_UInt32 dst_imc_id) +{ + imc_state_t *state; + imc_msg_t *in_msg; + TNC_Result result; + + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + if (!imc_attestation->get_state(imc_attestation, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imc_msg_create_from_long_data(imc_attestation, state, connection_id, + src_imv_id, dst_imc_id, msg_vid, msg_subtype, + chunk_create(msg, msg_len)); + result =receive_message(state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +/** + * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_BatchEnding(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_Terminate(TNC_IMCID imc_id) +{ + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + imc_attestation->destroy(imc_attestation); + imc_attestation = NULL; + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_API TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, + TNC_TNCC_BindFunctionPointer bind_function) +{ + if (!imc_attestation) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imc_attestation->bind_functions(imc_attestation, bind_function); +} diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_process.c b/src/libimcv/plugins/imc_attestation/imc_attestation_process.c new file mode 100644 index 000000000..2fc2998e1 --- /dev/null +++ b/src/libimcv/plugins/imc_attestation/imc_attestation_process.c @@ -0,0 +1,480 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE + +#include <stdio.h> +/* for isdigit */ +#include <ctype.h> + +#include "imc_attestation_process.h" + +#include <ietf/ietf_attr_pa_tnc_error.h> + +#include <pts/pts.h> + +#include <tcg/pts/tcg_pts_attr_proto_caps.h> +#include <tcg/pts/tcg_pts_attr_meas_algo.h> +#include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h> +#include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h> +#include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h> +#include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h> +#include <tcg/pts/tcg_pts_attr_tpm_version_info.h> +#include <tcg/pts/tcg_pts_attr_get_aik.h> +#include <tcg/pts/tcg_pts_attr_aik.h> +#include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h> +#include <tcg/pts/tcg_pts_attr_gen_attest_evid.h> +#include <tcg/pts/tcg_pts_attr_simple_comp_evid.h> +#include <tcg/pts/tcg_pts_attr_simple_evid_final.h> +#include <tcg/pts/tcg_pts_attr_req_file_meas.h> +#include <tcg/pts/tcg_pts_attr_file_meas.h> +#include <tcg/pts/tcg_pts_attr_req_file_meta.h> +#include <tcg/pts/tcg_pts_attr_unix_file_meta.h> + +#include <utils/debug.h> +#include <utils/lexparser.h> + +#define DEFAULT_NONCE_LEN 20 + +bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg, + imc_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups) +{ + chunk_t attr_info; + pts_t *pts; + pts_error_code_t pts_error; + pen_type_t attr_type; + bool valid_path; + + pts = attestation_state->get_pts(attestation_state); + attr_type = attr->get_type(attr); + + switch (attr_type.type) + { + case TCG_PTS_REQ_PROTO_CAPS: + { + tcg_pts_attr_proto_caps_t *attr_cast; + pts_proto_caps_flag_t imc_caps, imv_caps; + + attr_cast = (tcg_pts_attr_proto_caps_t*)attr; + imv_caps = attr_cast->get_flags(attr_cast); + imc_caps = pts->get_proto_caps(pts); + pts->set_proto_caps(pts, imc_caps & imv_caps); + + /* Send PTS Protocol Capabilities attribute */ + attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps, FALSE); + msg->add_attribute(msg, attr); + break; + } + case TCG_PTS_MEAS_ALGO: + { + tcg_pts_attr_meas_algo_t *attr_cast; + pts_meas_algorithms_t offered_algorithms, selected_algorithm; + + attr_cast = (tcg_pts_attr_meas_algo_t*)attr; + offered_algorithms = attr_cast->get_algorithms(attr_cast); + selected_algorithm = pts_meas_algo_select(supported_algorithms, + offered_algorithms); + if (selected_algorithm == PTS_MEAS_ALGO_NONE) + { + attr = pts_hash_alg_error_create(supported_algorithms); + msg->add_attribute(msg, attr); + break; + } + + /* Send Measurement Algorithm Selection attribute */ + pts->set_meas_algorithm(pts, selected_algorithm); + attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE); + msg->add_attribute(msg, attr); + break; + } + case TCG_PTS_DH_NONCE_PARAMS_REQ: + { + tcg_pts_attr_dh_nonce_params_req_t *attr_cast; + pts_dh_group_t offered_dh_groups, selected_dh_group; + chunk_t responder_value, responder_nonce; + int nonce_len, min_nonce_len; + + nonce_len = lib->settings->get_int(lib->settings, + "%s.plugins.imc-attestation.nonce_len", + DEFAULT_NONCE_LEN, lib->ns); + + attr_cast = (tcg_pts_attr_dh_nonce_params_req_t*)attr; + min_nonce_len = attr_cast->get_min_nonce_len(attr_cast); + if (nonce_len < PTS_MIN_NONCE_LEN || + (min_nonce_len > 0 && nonce_len < min_nonce_len)) + { + attr = pts_dh_nonce_error_create(nonce_len, PTS_MAX_NONCE_LEN); + msg->add_attribute(msg, attr); + break; + } + + offered_dh_groups = attr_cast->get_dh_groups(attr_cast); + selected_dh_group = pts_dh_group_select(supported_dh_groups, + offered_dh_groups); + if (selected_dh_group == PTS_DH_GROUP_NONE) + { + attr = pts_dh_group_error_create(supported_dh_groups); + msg->add_attribute(msg, attr); + break; + } + + /* Create own DH factor and nonce */ + if (!pts->create_dh_nonce(pts, selected_dh_group, nonce_len)) + { + return FALSE; + } + pts->get_my_public_value(pts, &responder_value, &responder_nonce); + + /* Send DH Nonce Parameters Response attribute */ + attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group, + supported_algorithms, responder_nonce, responder_value); + msg->add_attribute(msg, attr); + break; + } + case TCG_PTS_DH_NONCE_FINISH: + { + tcg_pts_attr_dh_nonce_finish_t *attr_cast; + pts_meas_algorithms_t selected_algorithm; + chunk_t initiator_nonce, initiator_value; + int nonce_len; + + attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr; + selected_algorithm = attr_cast->get_hash_algo(attr_cast); + if (!(selected_algorithm & supported_algorithms)) + { + DBG1(DBG_IMC, "PTS-IMV selected unsupported DH hash algorithm"); + return FALSE; + } + pts->set_dh_hash_algorithm(pts, selected_algorithm); + + initiator_value = attr_cast->get_initiator_value(attr_cast); + initiator_nonce = attr_cast->get_initiator_nonce(attr_cast); + + nonce_len = lib->settings->get_int(lib->settings, + "%s.plugins.imc-attestation.nonce_len", + DEFAULT_NONCE_LEN, lib->ns); + if (nonce_len != initiator_nonce.len) + { + DBG1(DBG_IMC, "initiator and responder DH nonces " + "have differing lengths"); + return FALSE; + } + + pts->set_peer_public_value(pts, initiator_value, initiator_nonce); + if (!pts->calculate_secret(pts)) + { + return FALSE; + } + break; + } + case TCG_PTS_GET_TPM_VERSION_INFO: + { + chunk_t tpm_version_info, attr_info; + pen_type_t error_code = { PEN_TCG, TCG_PTS_TPM_VERS_NOT_SUPPORTED }; + + if (!pts->get_tpm_version_info(pts, &tpm_version_info)) + { + attr_info = attr->get_value(attr); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + + /* Send TPM Version Info attribute */ + attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info); + msg->add_attribute(msg, attr); + break; + } + case TCG_PTS_GET_AIK: + { + certificate_t *aik; + + aik = pts->get_aik(pts); + if (!aik) + { + DBG1(DBG_IMC, "no AIK certificate or public key available"); + break; + } + + /* Send AIK attribute */ + attr = tcg_pts_attr_aik_create(aik); + msg->add_attribute(msg, attr); + break; + } + case TCG_PTS_REQ_FILE_MEAS: + { + tcg_pts_attr_req_file_meas_t *attr_cast; + char *pathname; + u_int16_t request_id; + bool is_directory; + u_int32_t delimiter; + pts_file_meas_t *measurements; + pen_type_t error_code; + + attr_info = attr->get_value(attr); + attr_cast = (tcg_pts_attr_req_file_meas_t*)attr; + is_directory = attr_cast->get_directory_flag(attr_cast); + request_id = attr_cast->get_request_id(attr_cast); + delimiter = attr_cast->get_delimiter(attr_cast); + pathname = attr_cast->get_pathname(attr_cast); + valid_path = pts->is_path_valid(pts, pathname, &pts_error); + + if (valid_path && pts_error) + { + error_code = pen_type_create(PEN_TCG, pts_error); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + else if (!valid_path) + { + break; + } + + if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF) + { + error_code = pen_type_create(PEN_TCG, + TCG_PTS_INVALID_DELIMITER); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + + /* Do PTS File Measurements and send them to PTS-IMV */ + DBG2(DBG_IMC, "measurement request %d for %s '%s'", + request_id, is_directory ? "directory" : "file", + pathname); + measurements = pts_file_meas_create_from_path(request_id, + pathname, is_directory, TRUE, + pts->get_meas_algorithm(pts)); + if (!measurements) + { + /* TODO handle error codes from measurements */ + return FALSE; + } + attr = tcg_pts_attr_file_meas_create(measurements); + attr->set_noskip_flag(attr, TRUE); + msg->add_attribute(msg, attr); + break; + } + case TCG_PTS_REQ_FILE_META: + { + tcg_pts_attr_req_file_meta_t *attr_cast; + char *pathname; + bool is_directory; + u_int8_t delimiter; + pts_file_meta_t *metadata; + pen_type_t error_code; + + attr_info = attr->get_value(attr); + attr_cast = (tcg_pts_attr_req_file_meta_t*)attr; + is_directory = attr_cast->get_directory_flag(attr_cast); + delimiter = attr_cast->get_delimiter(attr_cast); + pathname = attr_cast->get_pathname(attr_cast); + + valid_path = pts->is_path_valid(pts, pathname, &pts_error); + if (valid_path && pts_error) + { + error_code = pen_type_create(PEN_TCG, pts_error); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + else if (!valid_path) + { + break; + } + if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF) + { + error_code = pen_type_create(PEN_TCG, + TCG_PTS_INVALID_DELIMITER); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + /* Get File Metadata and send them to PTS-IMV */ + DBG2(DBG_IMC, "metadata request for %s '%s'", + is_directory ? "directory" : "file", + pathname); + metadata = pts->get_metadata(pts, pathname, is_directory); + + if (!metadata) + { + /* TODO handle error codes from measurements */ + return FALSE; + } + attr = tcg_pts_attr_unix_file_meta_create(metadata); + attr->set_noskip_flag(attr, TRUE); + msg->add_attribute(msg, attr); + break; + } + case TCG_PTS_REQ_FUNC_COMP_EVID: + { + tcg_pts_attr_req_func_comp_evid_t *attr_cast; + pts_proto_caps_flag_t negotiated_caps; + pts_comp_func_name_t *name; + pts_comp_evidence_t *evid; + pts_component_t *comp; + pen_type_t error_code; + u_int32_t depth; + u_int8_t flags; + status_t status; + enumerator_t *e; + + attr_info = attr->get_value(attr); + attr_cast = (tcg_pts_attr_req_func_comp_evid_t*)attr; + + DBG1(DBG_IMC, "evidence requested for %d functional components", + attr_cast->get_count(attr_cast)); + + e = attr_cast->create_enumerator(attr_cast); + while (e->enumerate(e, &flags, &depth, &name)) + { + name->log(name, "* "); + negotiated_caps = pts->get_proto_caps(pts); + + if (flags & PTS_REQ_FUNC_COMP_EVID_TTC) + { + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_DET_TTC); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + if (flags & PTS_REQ_FUNC_COMP_EVID_VER && + !(negotiated_caps & PTS_PROTO_CAPS_V)) + { + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_LOCAL_VAL); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + if (flags & PTS_REQ_FUNC_COMP_EVID_CURR && + !(negotiated_caps & PTS_PROTO_CAPS_C)) + { + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_CUR_EVID); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + if (flags & PTS_REQ_FUNC_COMP_EVID_PCR && + !(negotiated_caps & PTS_PROTO_CAPS_T)) + { + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_DET_PCR); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); + msg->add_attribute(msg, attr); + break; + } + if (depth > 0) + { + DBG1(DBG_IMC, "the Attestation IMC currently does not " + "support sub component measurements"); + return FALSE; + } + comp = attestation_state->create_component(attestation_state, + name, depth); + if (!comp) + { + DBG2(DBG_IMC, " not registered: no evidence provided"); + continue; + } + + /* do the component evidence measurement[s] and cache them */ + do + { + status = comp->measure(comp, name->get_qualifier(name), + pts, &evid); + if (status == FAILED) + { + break; + } + attestation_state->add_evidence(attestation_state, evid); + } + while (status == NEED_MORE); + } + e->destroy(e); + break; + } + case TCG_PTS_GEN_ATTEST_EVID: + { + pts_simple_evid_final_flag_t flags; + pts_meas_algorithms_t comp_hash_algorithm; + pts_comp_evidence_t *evid; + chunk_t pcr_composite, quote_sig; + bool use_quote2; + + /* Send cached Component Evidence entries */ + while (attestation_state->next_evidence(attestation_state, &evid)) + { + attr = tcg_pts_attr_simple_comp_evid_create(evid); + msg->add_attribute(msg, attr); + } + + use_quote2 = lib->settings->get_bool(lib->settings, + "%s.plugins.imc-attestation.use_quote2", TRUE, + lib->ns); + if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, "e_sig)) + { + DBG1(DBG_IMC, "error occurred during TPM quote operation"); + return FALSE; + } + + /* Send Simple Evidence Final attribute */ + flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 : + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO; + comp_hash_algorithm = PTS_MEAS_ALGO_SHA1; + + attr = tcg_pts_attr_simple_evid_final_create(flags, + comp_hash_algorithm, pcr_composite, quote_sig); + msg->add_attribute(msg, attr); + break; + } + case TCG_SEG_MAX_ATTR_SIZE_REQ: + case TCG_SEG_NEXT_SEG_REQ: + break; + + /* TODO: Not implemented yet */ + case TCG_PTS_REQ_INTEG_MEAS_LOG: + /* Attributes using XML */ + case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META: + case TCG_PTS_UPDATE_TEMPL_REF_MANI: + /* On Windows only*/ + case TCG_PTS_REQ_REGISTRY_VALUE: + /* Received on IMV side only*/ + case TCG_PTS_PROTO_CAPS: + case TCG_PTS_DH_NONCE_PARAMS_RESP: + case TCG_PTS_MEAS_ALGO_SELECTION: + case TCG_PTS_TPM_VERSION_INFO: + case TCG_PTS_TEMPL_REF_MANI_SET_META: + case TCG_PTS_AIK: + case TCG_PTS_SIMPLE_COMP_EVID: + case TCG_PTS_SIMPLE_EVID_FINAL: + case TCG_PTS_VERIFICATION_RESULT: + case TCG_PTS_INTEG_REPORT: + case TCG_PTS_UNIX_FILE_META: + case TCG_PTS_FILE_MEAS: + case TCG_PTS_INTEG_MEAS_LOG: + default: + DBG1(DBG_IMC, "received unsupported attribute '%N/%N'", + pen_names, PEN_TCG, tcg_attr_names, attr_type.type); + break; + } + return TRUE; +} diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_process.h b/src/libimcv/plugins/imc_attestation/imc_attestation_process.h new file mode 100644 index 000000000..a2f1b4e3c --- /dev/null +++ b/src/libimcv/plugins/imc_attestation/imc_attestation_process.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imc_attestation_process_t imc_attestation_process + * @{ @ingroup imc_attestation + */ + +#ifndef IMC_ATTESTATION_PROCESS_H_ +#define IMC_ATTESTATION_PROCESS_H_ + +#include "imc_attestation_state.h" + +#include <library.h> + +#include <imc/imc_msg.h> +#include <pa_tnc/pa_tnc_attr.h> + +#include <pts/pts_dh_group.h> +#include <pts/pts_meas_algo.h> + +/** + * Process a TCG PTS attribute + * + * @param attr PA-TNC attribute to be processed + * @param msg outbound PA-TNC message to be assembled + * @param attestation_state attestation state of a given connection + * @param supported_algorithms supported PTS measurement algorithms + * @param supported_dh_groups supported DH groups + * @return TRUE if successful + */ +bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg, + imc_attestation_state_t *attestation_state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups); + +#endif /** IMC_ATTESTATION_PROCESS_H_ @}*/ diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_state.c b/src/libimcv/plugins/imc_attestation/imc_attestation_state.c new file mode 100644 index 000000000..0b594cb10 --- /dev/null +++ b/src/libimcv/plugins/imc_attestation/imc_attestation_state.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imc_attestation_state.h" + +#include <imcv.h> + +#include <tncif_names.h> + +#include <collections/linked_list.h> +#include <utils/debug.h> + +typedef struct private_imc_attestation_state_t private_imc_attestation_state_t; +typedef struct func_comp_t func_comp_t; + +/** + * Private data of an imc_attestation_state_t object. + */ +struct private_imc_attestation_state_t { + + /** + * Public members of imc_attestation_state_t + */ + imc_attestation_state_t public; + + /** + * TNCCS connection ID + */ + TNC_ConnectionID connection_id; + + /** + * TNCCS connection state + */ + TNC_ConnectionState state; + + /** + * Assessment/Evaluation Result + */ + TNC_IMV_Evaluation_Result result; + + /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; + + /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** + * PTS object + */ + pts_t *pts; + + /** + * List of Functional Components + */ + linked_list_t *components; + + /** + * Functional Component Evidence cache list + */ + linked_list_t *list; + +}; + +METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, + private_imc_attestation_state_t *this) +{ + return this->connection_id; +} + +METHOD(imc_state_t, has_long, bool, + private_imc_attestation_state_t *this) +{ + return this->has_long; +} + +METHOD(imc_state_t, has_excl, bool, + private_imc_attestation_state_t *this) +{ + return this->has_excl; +} + +METHOD(imc_state_t, set_flags, void, + private_imc_attestation_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + +METHOD(imc_state_t, set_max_msg_len, void, + private_imc_attestation_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imc_state_t, get_max_msg_len, u_int32_t, + private_imc_attestation_state_t *this) +{ + return this->max_msg_len; +} + +METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, + private_imc_attestation_state_t *this) +{ + return this->contracts; +} + +METHOD(imc_state_t, change_state, void, + private_imc_attestation_state_t *this, TNC_ConnectionState new_state) +{ + this->state = new_state; +} + +METHOD(imc_state_t, set_result, void, + private_imc_attestation_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result result) +{ + this->result = result; +} + +METHOD(imc_state_t, get_result, bool, + private_imc_attestation_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result *result) +{ + if (result) + { + *result = this->result; + } + return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + +METHOD(imc_state_t, destroy, void, + private_imc_attestation_state_t *this) +{ + this->pts->destroy(this->pts); + this->components->destroy_offset(this->components, + offsetof(pts_component_t, destroy)); + this->list->destroy_offset(this->list, + offsetof(pts_comp_evidence_t, destroy)); + this->contracts->destroy(this->contracts); + free(this); +} + +METHOD(imc_attestation_state_t, get_pts, pts_t*, + private_imc_attestation_state_t *this) +{ + return this->pts; +} + +METHOD(imc_attestation_state_t, create_component, pts_component_t*, + private_imc_attestation_state_t *this, pts_comp_func_name_t *name, + u_int32_t depth) +{ + enumerator_t *enumerator; + pts_component_t *component; + bool found = FALSE; + + enumerator = this->components->create_enumerator(this->components); + while (enumerator->enumerate(enumerator, &component)) + { + if (name->equals(name, component->get_comp_func_name(component))) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + component = imcv_pts_components->create(imcv_pts_components, + name, depth, NULL); + if (!component) + { + return NULL; + } + this->components->insert_last(this->components, component); + + } + return component; +} + +METHOD(imc_attestation_state_t, add_evidence, void, + private_imc_attestation_state_t *this, pts_comp_evidence_t *evid) +{ + this->list->insert_last(this->list, evid); +} + +METHOD(imc_attestation_state_t, next_evidence, bool, + private_imc_attestation_state_t *this, pts_comp_evidence_t **evid) +{ + return this->list->remove_first(this->list, (void**)evid) == SUCCESS; +} + +/** + * Described in header. + */ +imc_state_t *imc_attestation_state_create(TNC_ConnectionID connection_id) +{ + private_imc_attestation_state_t *this; + + INIT(this, + .public = { + .interface = { + .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, + .get_contracts = _get_contracts, + .change_state = _change_state, + .set_result = _set_result, + .get_result = _get_result, + .destroy = _destroy, + }, + .get_pts = _get_pts, + .create_component = _create_component, + .add_evidence = _add_evidence, + .next_evidence = _next_evidence, + }, + .connection_id = connection_id, + .state = TNC_CONNECTION_STATE_CREATE, + .result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, + .contracts = seg_contract_manager_create(), + .pts = pts_create(TRUE), + .components = linked_list_create(), + .list = linked_list_create(), + ); + + return &this->public.interface; +} + + diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation_state.h b/src/libimcv/plugins/imc_attestation/imc_attestation_state.h new file mode 100644 index 000000000..854c8825b --- /dev/null +++ b/src/libimcv/plugins/imc_attestation/imc_attestation_state.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imc_attestation imc_attestation + * @ingroup libimcv_plugins + * + * @defgroup imc_attestation_state_t imc_attestation_state + * @{ @ingroup imc_attestation + */ + +#ifndef IMC_ATTESTATION_STATE_H_ +#define IMC_ATTESTATION_STATE_H_ + +#include <imc/imc_state.h> +#include <pts/pts.h> +#include <pts/components/pts_component.h> +#include <pts/components/pts_comp_evidence.h> +#include <library.h> + +typedef struct imc_attestation_state_t imc_attestation_state_t; + +/** + * Internal state of an imc_attestation_t connection instance + */ +struct imc_attestation_state_t { + + /** + * imc_state_t interface + */ + imc_state_t interface; + + /** + * Get the PTS object + * + * @return PTS object + */ + pts_t* (*get_pts)(imc_attestation_state_t *this); + + /** + * Create and add an entry to the list of Functional Components + * + * @param name Component Functional Name + * @param depth Sub-component Depth + * @return created functional component instance or NULL + */ + pts_component_t* (*create_component)(imc_attestation_state_t *this, + pts_comp_func_name_t *name, u_int32_t depth); + + /** + * Add an entry to the Component Evidence cache list + * + * @param evid Component Evidence entry + */ + void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *evid); + + /** + * Removes next entry from the Component Evidence cache list and returns it + * + * @param evid Next Component Evidence entry + * @return TRUE if next entry is available + */ + bool (*next_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t** evid); + +}; + +/** + * Create an imc_attestation_state_t instance + * + * @param id connection ID + */ +imc_state_t* imc_attestation_state_create(TNC_ConnectionID id); + +#endif /** IMC_ATTESTATION_STATE_H_ @}*/ diff --git a/src/libimcv/plugins/imc_os/Makefile.in b/src/libimcv/plugins/imc_os/Makefile.in index 2f0b85404..3f4cf41a9 100644 --- a/src/libimcv/plugins/imc_os/Makefile.in +++ b/src/libimcv/plugins/imc_os/Makefile.in @@ -230,6 +230,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ GPRBUILD = @GPRBUILD@ @@ -290,6 +291,7 @@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ RUBYINCLUDE = @RUBYINCLUDE@ RUBYLIB = @RUBYLIB@ SED = @SED@ @@ -355,6 +357,8 @@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -402,6 +406,10 @@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ target_alias = @target_alias@ diff --git a/src/libimcv/plugins/imc_os/imc_os.c b/src/libimcv/plugins/imc_os/imc_os.c index c624d26b1..86d2e09ca 100644 --- a/src/libimcv/plugins/imc_os/imc_os.c +++ b/src/libimcv/plugins/imc_os/imc_os.c @@ -30,7 +30,6 @@ #include <ita/ita_attr.h> #include <ita/ita_attr_get_settings.h> #include <ita/ita_attr_settings.h> -#include <ita/ita_attr_angel.h> #include <ita/ita_attr_device_id.h> #include <tncif_pa_subtypes.h> @@ -341,69 +340,24 @@ static void add_device_id(imc_msg_t *msg) */ static void add_installed_packages(imc_state_t *state, imc_msg_t *msg) { - pa_tnc_attr_t *attr = NULL, *attr_angel; + pa_tnc_attr_t *attr; ietf_attr_installed_packages_t *attr_cast; enumerator_t *enumerator; chunk_t name, version; - size_t max_attr_size, attr_size, entry_size; - bool first = TRUE; - - /** - * Compute the maximum IETF Installed Packages 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; - /* At least one IETF Installed Packages attribute is sent */ attr = ietf_attr_installed_packages_create(); - attr_size = PA_TNC_ATTR_HEADER_SIZE + IETF_INSTALLED_PACKAGES_MIN_SIZE; enumerator = os->create_package_enumerator(os); - if (enumerator) + while (enumerator->enumerate(enumerator, &name, &version)) { - while (enumerator->enumerate(enumerator, &name, &version)) - { - DBG2(DBG_IMC, "package '%.*s' (%.*s)", - name.len, name.ptr, version.len, version.ptr); - - entry_size = 2 + name.len + version.len; - if (attr_size + entry_size > max_attr_size) - { - if (first) - { - /** - * Send an ITA Start Angel attribute to the IMV signalling - * that multiple ITA Installed Package 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 IETF Installed Packages attribute */ - attr = ietf_attr_installed_packages_create(); - attr_size = PA_TNC_ATTR_HEADER_SIZE + - IETF_INSTALLED_PACKAGES_MIN_SIZE; - } - attr_cast = (ietf_attr_installed_packages_t*)attr; - attr_cast->add(attr_cast, name, version); - attr_size += entry_size; - } - enumerator->destroy(enumerator); + DBG2(DBG_IMC, "package '%.*s' (%.*s)", + name.len, name.ptr, version.len, version.ptr); + attr_cast = (ietf_attr_installed_packages_t*)attr; + attr_cast->add(attr_cast, name, version); } - msg->add_attribute(msg, attr); + enumerator->destroy(enumerator); - 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); - } + msg->add_attribute(msg, attr); } /** @@ -491,13 +445,16 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) TNC_Result result; bool fatal_error = FALSE; + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imc_msg_create_as_reply(in_msg); + /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); + result = in_msg->receive(in_msg, out_msg, &fatal_error); if (result != TNC_RESULT_SUCCESS) { + out_msg->destroy(out_msg); return result; } - out_msg = imc_msg_create_as_reply(in_msg); /* analyze PA-TNC attributes */ enumerator = in_msg->create_attribute_enumerator(in_msg); @@ -582,6 +539,7 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) } else { + /* send PA-TNC message with the EXCL flag set */ result = out_msg->send(out_msg, TRUE); } out_msg->destroy(out_msg); diff --git a/src/libimcv/plugins/imc_os/imc_os_state.c b/src/libimcv/plugins/imc_os/imc_os_state.c index f49959ab9..139ab0597 100644 --- a/src/libimcv/plugins/imc_os/imc_os_state.c +++ b/src/libimcv/plugins/imc_os/imc_os_state.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Andreas Steffen + * Copyright (C) 2012-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -60,6 +60,11 @@ struct private_imc_os_state_t { * Maximum PA-TNC message size for this TNCCS connection */ u_int32_t max_msg_len; + + /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; }; METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, @@ -99,6 +104,12 @@ METHOD(imc_state_t, get_max_msg_len, u_int32_t, return this->max_msg_len; } +METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, + private_imc_os_state_t *this) +{ + return this->contracts; +} + METHOD(imc_state_t, change_state, void, private_imc_os_state_t *this, TNC_ConnectionState new_state) { @@ -126,6 +137,7 @@ METHOD(imc_state_t, get_result, bool, METHOD(imc_state_t, destroy, void, private_imc_os_state_t *this) { + this->contracts->destroy(this->contracts); free(this); } @@ -145,6 +157,7 @@ imc_state_t *imc_os_state_create(TNC_ConnectionID connection_id) .set_flags = _set_flags, .set_max_msg_len = _set_max_msg_len, .get_max_msg_len = _get_max_msg_len, + .get_contracts = _get_contracts, .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, @@ -154,6 +167,7 @@ imc_state_t *imc_os_state_create(TNC_ConnectionID connection_id) .state = TNC_CONNECTION_STATE_CREATE, .result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, + .contracts = seg_contract_manager_create(), ); return &this->public.interface; diff --git a/src/libimcv/plugins/imc_scanner/Makefile.in b/src/libimcv/plugins/imc_scanner/Makefile.in index c66bb1afa..a192b0a41 100644 --- a/src/libimcv/plugins/imc_scanner/Makefile.in +++ b/src/libimcv/plugins/imc_scanner/Makefile.in @@ -231,6 +231,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ GPRBUILD = @GPRBUILD@ @@ -291,6 +292,7 @@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ RUBYINCLUDE = @RUBYINCLUDE@ RUBYLIB = @RUBYLIB@ SED = @SED@ @@ -356,6 +358,8 @@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -403,6 +407,10 @@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ target_alias = @target_alias@ diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner.c b/src/libimcv/plugins/imc_scanner/imc_scanner.c index 2be6a87df..0478841cb 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner.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 @@ -299,13 +299,16 @@ static TNC_Result receive_message(imc_msg_t *in_msg) TNC_Result result = TNC_RESULT_SUCCESS; bool fatal_error = FALSE; + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imc_msg_create_as_reply(in_msg); + /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); + result = in_msg->receive(in_msg, out_msg, &fatal_error); if (result != TNC_RESULT_SUCCESS) { + out_msg->destroy(out_msg); return result; } - out_msg = imc_msg_create_as_reply(in_msg); /* analyze PA-TNC attributes */ enumerator = in_msg->create_attribute_enumerator(in_msg); @@ -352,6 +355,7 @@ static TNC_Result receive_message(imc_msg_t *in_msg) } else if (result == TNC_RESULT_SUCCESS) { + /* send PA-TNC message with the EXCL flag set */ result = out_msg->send(out_msg, TRUE); } out_msg->destroy(out_msg); diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c index b5a6cdd20..d357859fa 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner_state.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 @@ -60,6 +60,11 @@ struct private_imc_scanner_state_t { * Maximum PA-TNC message size for this TNCCS connection */ u_int32_t max_msg_len; + + /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; }; METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, @@ -99,6 +104,12 @@ METHOD(imc_state_t, get_max_msg_len, u_int32_t, return this->max_msg_len; } +METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, + private_imc_scanner_state_t *this) +{ + return this->contracts; +} + METHOD(imc_state_t, change_state, void, private_imc_scanner_state_t *this, TNC_ConnectionState new_state) { @@ -126,6 +137,7 @@ METHOD(imc_state_t, get_result, bool, METHOD(imc_state_t, destroy, void, private_imc_scanner_state_t *this) { + this->contracts->destroy(this->contracts); free(this); } @@ -145,6 +157,7 @@ imc_state_t *imc_scanner_state_create(TNC_ConnectionID connection_id) .set_flags = _set_flags, .set_max_msg_len = _set_max_msg_len, .get_max_msg_len = _get_max_msg_len, + .get_contracts = _get_contracts, .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, @@ -154,6 +167,7 @@ imc_state_t *imc_scanner_state_create(TNC_ConnectionID connection_id) .state = TNC_CONNECTION_STATE_CREATE, .result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, + .contracts = seg_contract_manager_create(), ); return &this->public.interface; diff --git a/src/libimcv/plugins/imc_swid/Makefile.am b/src/libimcv/plugins/imc_swid/Makefile.am new file mode 100644 index 000000000..c1cdb988a --- /dev/null +++ b/src/libimcv/plugins/imc_swid/Makefile.am @@ -0,0 +1,37 @@ +regid = regid.2004-03.org.strongswan +unique_sw_id = strongSwan-$(PACKAGE_VERSION_MAJOR)-$(PACKAGE_VERSION_MINOR)-$(PACKAGE_VERSION_BUILD)$(PACKAGE_VERSION_REVIEW) +swid_tag = $(regid)_$(unique_sw_id).swidtag + +swiddir = $(prefix)/share/$(regid) +swid_DATA = $(swid_tag) +ipsec_DATA = $(swid_tag) +EXTRA_DIST = $(regid)_strongSwan.swidtag.in +CLEANFILES = $(regid)_strongSwan*.swidtag + +$(swid_tag) : regid.2004-03.org.strongswan_strongSwan.swidtag.in + $(AM_V_GEN) \ + sed \ + -e "s:@VERSION_MAJOR@:$(PACKAGE_VERSION_MAJOR):" \ + -e "s:@VERSION_MINOR@:$(PACKAGE_VERSION_MINOR):" \ + -e "s:@VERSION_BUILD@:$(PACKAGE_VERSION_BUILD):" \ + -e "s:@VERSION_REVIEW@:$(PACKAGE_VERSION_REVIEW):" \ + $(srcdir)/$(regid)_strongSwan.swidtag.in > $@ + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv \ + -DSWID_DIRECTORY=\"${prefix}/share\" + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +imcv_LTLIBRARIES = imc-swid.la + +imc_swid_la_LIBADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +imc_swid_la_SOURCES = imc_swid.c imc_swid_state.h imc_swid_state.c + +imc_swid_la_LDFLAGS = -module -avoid-version -no-undefined diff --git a/src/libimcv/plugins/imc_swid/Makefile.in b/src/libimcv/plugins/imc_swid/Makefile.in new file mode 100644 index 000000000..f1859a2cb --- /dev/null +++ b/src/libimcv/plugins/imc_swid/Makefile.in @@ -0,0 +1,826 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libimcv/plugins/imc_swid +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/split-package-version.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(imcvdir)" "$(DESTDIR)$(ipsecdir)" \ + "$(DESTDIR)$(swiddir)" +LTLIBRARIES = $(imcv_LTLIBRARIES) +imc_swid_la_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +am_imc_swid_la_OBJECTS = imc_swid.lo imc_swid_state.lo +imc_swid_la_OBJECTS = $(am_imc_swid_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +imc_swid_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(imc_swid_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(imc_swid_la_SOURCES) +DIST_SOURCES = $(imc_swid_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DATA = $(ipsec_DATA) $(swid_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COVERAGE_CFLAGS = @COVERAGE_CFLAGS@ +COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GEM = @GEM@ +GENHTML = @GENHTML@ +GPERF = @GPERF@ +GPRBUILD = @GPRBUILD@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_BUILD = @PACKAGE_VERSION_BUILD@ +PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@ +PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@ +PACKAGE_VERSION_REVIEW = @PACKAGE_VERSION_REVIEW@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +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@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ +RUBYINCLUDE = @RUBYINCLUDE@ +RUBYLIB = @RUBYLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +UNWINDLIB = @UNWINDLIB@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +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@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +cmd_plugins = @cmd_plugins@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +fips_mode = @fips_mode@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ +sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ +systemdsystemunitdir = @systemdsystemunitdir@ +t_plugins = @t_plugins@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +regid = regid.2004-03.org.strongswan +unique_sw_id = strongSwan-$(PACKAGE_VERSION_MAJOR)-$(PACKAGE_VERSION_MINOR)-$(PACKAGE_VERSION_BUILD)$(PACKAGE_VERSION_REVIEW) +swid_tag = $(regid)_$(unique_sw_id).swidtag +swiddir = $(prefix)/share/$(regid) +swid_DATA = $(swid_tag) +ipsec_DATA = $(swid_tag) +EXTRA_DIST = $(regid)_strongSwan.swidtag.in +CLEANFILES = $(regid)_strongSwan*.swidtag +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv \ + -DSWID_DIRECTORY=\"${prefix}/share\" + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +imcv_LTLIBRARIES = imc-swid.la +imc_swid_la_LIBADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +imc_swid_la_SOURCES = imc_swid.c imc_swid_state.h imc_swid_state.c +imc_swid_la_LDFLAGS = -module -avoid-version -no-undefined +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libimcv/plugins/imc_swid/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libimcv/plugins/imc_swid/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-imcvLTLIBRARIES: $(imcv_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(imcvdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(imcvdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imcvdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imcvdir)"; \ + } + +uninstall-imcvLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imcvdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imcvdir)/$$f"; \ + done + +clean-imcvLTLIBRARIES: + -test -z "$(imcv_LTLIBRARIES)" || rm -f $(imcv_LTLIBRARIES) + @list='$(imcv_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +imc-swid.la: $(imc_swid_la_OBJECTS) $(imc_swid_la_DEPENDENCIES) $(EXTRA_imc_swid_la_DEPENDENCIES) + $(AM_V_CCLD)$(imc_swid_la_LINK) -rpath $(imcvdir) $(imc_swid_la_OBJECTS) $(imc_swid_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imc_swid.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imc_swid_state.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-ipsecDATA: $(ipsec_DATA) + @$(NORMAL_INSTALL) + @list='$(ipsec_DATA)'; test -n "$(ipsecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(ipsecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(ipsecdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(ipsecdir)" || exit $$?; \ + done + +uninstall-ipsecDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_DATA)'; test -n "$(ipsecdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(ipsecdir)'; $(am__uninstall_files_from_dir) +install-swidDATA: $(swid_DATA) + @$(NORMAL_INSTALL) + @list='$(swid_DATA)'; test -n "$(swiddir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(swiddir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(swiddir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(swiddir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(swiddir)" || exit $$?; \ + done + +uninstall-swidDATA: + @$(NORMAL_UNINSTALL) + @list='$(swid_DATA)'; test -n "$(swiddir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(swiddir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(imcvdir)" "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(swiddir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-imcvLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-imcvLTLIBRARIES install-ipsecDATA \ + install-swidDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-imcvLTLIBRARIES uninstall-ipsecDATA \ + uninstall-swidDATA + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-imcvLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-imcvLTLIBRARIES install-info install-info-am \ + install-ipsecDATA install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip install-swidDATA \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-imcvLTLIBRARIES \ + uninstall-ipsecDATA uninstall-swidDATA + + +$(swid_tag) : regid.2004-03.org.strongswan_strongSwan.swidtag.in + $(AM_V_GEN) \ + sed \ + -e "s:@VERSION_MAJOR@:$(PACKAGE_VERSION_MAJOR):" \ + -e "s:@VERSION_MINOR@:$(PACKAGE_VERSION_MINOR):" \ + -e "s:@VERSION_BUILD@:$(PACKAGE_VERSION_BUILD):" \ + -e "s:@VERSION_REVIEW@:$(PACKAGE_VERSION_REVIEW):" \ + $(srcdir)/$(regid)_strongSwan.swidtag.in > $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libimcv/plugins/imc_swid/imc_swid.c b/src/libimcv/plugins/imc_swid/imc_swid.c new file mode 100644 index 000000000..40f352ad9 --- /dev/null +++ b/src/libimcv/plugins/imc_swid/imc_swid.c @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2013-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imc_swid_state.h" + +#include <imc/imc_agent.h> +#include <imc/imc_msg.h> +#include "tcg/seg/tcg_seg_attr_max_size.h" +#include "tcg/seg/tcg_seg_attr_seg_env.h" +#include "tcg/swid/tcg_swid_attr_req.h" +#include "tcg/swid/tcg_swid_attr_tag_inv.h" +#include "tcg/swid/tcg_swid_attr_tag_id_inv.h" +#include "swid/swid_inventory.h" +#include "swid/swid_error.h" + +#include <tncif_pa_subtypes.h> + +#include <pen/pen.h> +#include <utils/debug.h> + +#define SWID_GENERATOR "/usr/local/bin/swid_generator" + +/* IMC definitions */ + +static const char imc_name[] = "SWID"; + +static pen_type_t msg_types[] = { + { PEN_TCG, PA_SUBTYPE_TCG_SWID } +}; + +static imc_agent_t *imc_swid; + +/** + * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id, + TNC_Version min_version, + TNC_Version max_version, + TNC_Version *actual_version) +{ + if (imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name); + return TNC_RESULT_ALREADY_INITIALIZED; + } + imc_swid = imc_agent_create(imc_name, msg_types, countof(msg_types), + imc_id, actual_version); + if (!imc_swid) + { + return TNC_RESULT_FATAL; + } + if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1) + { + DBG1(DBG_IMC, "no common IF-IMC version"); + return TNC_RESULT_NO_COMMON_VERSION; + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_ConnectionState new_state) +{ + imc_state_t *state; + + if (!imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imc_swid_state_create(connection_id); + return imc_swid->create_state(imc_swid, state); + case TNC_CONNECTION_STATE_HANDSHAKE: + if (imc_swid->change_state(imc_swid, connection_id, new_state, + &state) != TNC_RESULT_SUCCESS) + { + return TNC_RESULT_FATAL; + } + state->set_result(state, imc_id, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + return TNC_RESULT_SUCCESS; + case TNC_CONNECTION_STATE_DELETE: + return imc_swid->delete_state(imc_swid, connection_id); + default: + return imc_swid->change_state(imc_swid, connection_id, + new_state, NULL); + } +} + +/** + * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + imc_state_t *state; + imc_msg_t *out_msg; + pa_tnc_attr_t *attr; + seg_contract_t *contract; + seg_contract_manager_t *contracts; + size_t max_attr_size = SWID_MAX_ATTR_SIZE; + size_t max_seg_size; + char buf[BUF_LEN]; + TNC_Result result = TNC_RESULT_SUCCESS; + + if (!imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + if (!imc_swid->get_state(imc_swid, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + + /* Determine maximum PA-TNC attribute segment size */ + max_seg_size = state->get_max_msg_len(state) - PA_TNC_HEADER_SIZE + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_SEG_ENV_HEADER + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_MAX_SIZE_SIZE; + + /* Announce support of PA-TNC segmentation to IMV */ + contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size, + TRUE, imc_id, TRUE); + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMC, "%s", buf); + contracts = state->get_contracts(state); + contracts->add_contract(contracts, contract); + attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE); + + /* send PA-TNC message with the excl flag not set */ + out_msg = imc_msg_create(imc_swid, state, connection_id, imc_id, + TNC_IMVID_ANY, msg_types[0]); + out_msg->add_attribute(out_msg, attr); + result = out_msg->send(out_msg, FALSE); + out_msg->destroy(out_msg); + + return result; +} + +/** + * Add one or multiple SWID Inventory attributes to the send queue + */ +static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg, + uint32_t request_id, bool full_tags, + swid_inventory_t *targets) +{ + pa_tnc_attr_t *attr, *attr_error; + imc_swid_state_t *swid_state; + swid_inventory_t *swid_inventory; + char *swid_directory, *swid_generator; + uint32_t eid_epoch; + bool 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); + + if (full_tags) + { + tcg_swid_attr_tag_inv_t *swid_attr; + swid_tag_t *tag; + + /* Send a TCG SWID Tag Inventory attribute */ + attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1); + swid_attr = (tcg_swid_attr_tag_inv_t*)attr; + + enumerator = swid_inventory->create_enumerator(swid_inventory); + while (enumerator->enumerate(enumerator, &tag)) + { + swid_attr->add(swid_attr, tag->get_ref(tag)); + } + enumerator->destroy(enumerator); + } + else + { + tcg_swid_attr_tag_id_inv_t *swid_id_attr; + swid_tag_id_t *tag_id; + + /* Send a TCG SWID Tag ID Inventory attribute */ + attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1); + swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr; + + enumerator = swid_inventory->create_enumerator(swid_inventory); + while (enumerator->enumerate(enumerator, &tag_id)) + { + swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id)); + } + enumerator->destroy(enumerator); + } + + msg->add_attribute(msg, attr); + swid_inventory->destroy(swid_inventory); + + return TRUE; +} + +static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) +{ + imc_msg_t *out_msg; + pa_tnc_attr_t *attr; + enumerator_t *enumerator; + pen_type_t type; + TNC_Result result; + bool fatal_error = FALSE; + + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imc_msg_create_as_reply(in_msg); + + /* parse received PA-TNC message and handle local and remote errors */ + result = in_msg->receive(in_msg, out_msg, &fatal_error); + if (result != TNC_RESULT_SUCCESS) + { + out_msg->destroy(out_msg); + return result; + } + + /* analyze PA-TNC attributes */ + enumerator = in_msg->create_attribute_enumerator(in_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + tcg_swid_attr_req_t *attr_req; + uint8_t flags; + uint32_t request_id; + bool full_tags; + swid_inventory_t *targets; + + type = attr->get_type(attr); + + if (type.vendor_id != PEN_TCG || type.type != TCG_SWID_REQUEST) + { + continue; + } + + attr_req = (tcg_swid_attr_req_t*)attr; + flags = attr_req->get_flags(attr_req); + request_id = attr_req->get_request_id(attr_req); + targets = attr_req->get_targets(attr_req); + + if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C)) + { + attr = swid_error_create(TCG_SWID_SUBSCRIPTION_DENIED, request_id, + 0, "no subscription available yet"); + out_msg->add_attribute(out_msg, attr); + break; + } + full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0; + + if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets)) + { + break; + } + } + enumerator->destroy(enumerator); + + if (fatal_error) + { + result = TNC_RESULT_FATAL; + } + else + { + /* send PA-TNC message with the EXCL flag set */ + result = out_msg->send(out_msg, TRUE); + } + out_msg->destroy(out_msg); + + return result; +} + +/** + * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3 + + */ +TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) +{ + imc_state_t *state; + imc_msg_t *in_msg; + TNC_Result result; + + if (!imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + if (!imc_swid->get_state(imc_swid, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imc_msg_create_from_data(imc_swid, state, connection_id, msg_type, + chunk_create(msg, msg_len)); + result = receive_message(state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +/** + * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3 + */ +TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id, + TNC_ConnectionID connection_id, + TNC_UInt32 msg_flags, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, + TNC_UInt32 dst_imc_id) +{ + imc_state_t *state; + imc_msg_t *in_msg; + TNC_Result result; + + if (!imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + if (!imc_swid->get_state(imc_swid, connection_id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imc_msg_create_from_long_data(imc_swid, state, connection_id, + src_imv_id, dst_imc_id,msg_vid, msg_subtype, + chunk_create(msg, msg_len)); + result =receive_message(state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +/** + * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id, + TNC_ConnectionID connection_id) +{ + if (!imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return TNC_RESULT_SUCCESS; +} + +/** + * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id) +{ + if (!imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + imc_swid->destroy(imc_swid); + imc_swid = NULL; + + return TNC_RESULT_SUCCESS; +} + +/** + * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3 + */ +TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id, + TNC_TNCC_BindFunctionPointer bind_function) +{ + if (!imc_swid) + { + DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name); + return TNC_RESULT_NOT_INITIALIZED; + } + return imc_swid->bind_functions(imc_swid, bind_function); +} diff --git a/src/libimcv/plugins/imc_swid/imc_swid_state.c b/src/libimcv/plugins/imc_swid/imc_swid_state.c new file mode 100644 index 000000000..65c279b3f --- /dev/null +++ b/src/libimcv/plugins/imc_swid/imc_swid_state.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2013-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imc_swid_state.h" + +#include <tncif_names.h> + +#include <utils/debug.h> + +typedef struct private_imc_swid_state_t private_imc_swid_state_t; + +/** + * Private data of an imc_swid_state_t object. + */ +struct private_imc_swid_state_t { + + /** + * Public members of imc_swid_state_t + */ + imc_swid_state_t public; + + /** + * TNCCS connection ID + */ + TNC_ConnectionID connection_id; + + /** + * TNCCS connection state + */ + TNC_ConnectionState state; + + /** + * Assessment/Evaluation Result + */ + TNC_IMV_Evaluation_Result result; + + /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; + + /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** + * Event ID Epoch + */ + u_int32_t eid_epoch; +}; + +METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, + private_imc_swid_state_t *this) +{ + return this->connection_id; +} + +METHOD(imc_state_t, has_long, bool, + private_imc_swid_state_t *this) +{ + return this->has_long; +} + +METHOD(imc_state_t, has_excl, bool, + private_imc_swid_state_t *this) +{ + return this->has_excl; +} + +METHOD(imc_state_t, set_flags, void, + private_imc_swid_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + +METHOD(imc_state_t, set_max_msg_len, void, + private_imc_swid_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imc_state_t, get_max_msg_len, u_int32_t, + private_imc_swid_state_t *this) +{ + return this->max_msg_len; +} + +METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, + private_imc_swid_state_t *this) +{ + return this->contracts; +} + +METHOD(imc_state_t, change_state, void, + private_imc_swid_state_t *this, TNC_ConnectionState new_state) +{ + this->state = new_state; +} + +METHOD(imc_state_t, set_result, void, + private_imc_swid_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result result) +{ + this->result = result; +} + +METHOD(imc_state_t, get_result, bool, + private_imc_swid_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result *result) +{ + if (result) + { + *result = this->result; + } + return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + +METHOD(imc_state_t, destroy, void, + private_imc_swid_state_t *this) +{ + this->contracts->destroy(this->contracts); + free(this); +} + +METHOD(imc_swid_state_t, get_eid_epoch, u_int32_t, + private_imc_swid_state_t *this) +{ + return this->eid_epoch; +} + +/** + * Described in header. + */ +imc_state_t *imc_swid_state_create(TNC_ConnectionID connection_id) +{ + private_imc_swid_state_t *this; + u_int32_t eid_epoch; + nonce_gen_t *ng; + + ng = lib->crypto->create_nonce_gen(lib->crypto); + if (!ng || !ng->get_nonce(ng, 4, (u_int8_t*)&eid_epoch)) + { + DBG1(DBG_TNC, "failed to generate random EID epoch value"); + DESTROY_IF(ng); + return NULL; + } + ng->destroy(ng); + + DBG1(DBG_IMC, "creating random EID epoch 0x%08x", eid_epoch); + + INIT(this, + .public = { + .interface = { + .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, + .get_contracts = _get_contracts, + .change_state = _change_state, + .set_result = _set_result, + .get_result = _get_result, + .destroy = _destroy, + }, + .get_eid_epoch = _get_eid_epoch, + }, + .state = TNC_CONNECTION_STATE_CREATE, + .result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, + .connection_id = connection_id, + .contracts = seg_contract_manager_create(), + .eid_epoch = eid_epoch, + ); + + + return &this->public.interface; +} + + diff --git a/src/libimcv/plugins/imc_swid/imc_swid_state.h b/src/libimcv/plugins/imc_swid/imc_swid_state.h new file mode 100644 index 000000000..cb3ac4589 --- /dev/null +++ b/src/libimcv/plugins/imc_swid/imc_swid_state.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imc_swid imc_swid + * @ingroup libimcv_plugins + * + * @defgroup imc_swid_state_t imc_swid_state + * @{ @ingroup imc_swid + */ + +#ifndef IMC_SWID_STATE_H_ +#define IMC_SWID_STATE_H_ + +#include <imc/imc_state.h> +#include <library.h> + +typedef struct imc_swid_state_t imc_swid_state_t; + +/** + * Internal state of an imc_swid_t connection instance + */ +struct imc_swid_state_t { + + /** + * imc_state_t interface + */ + imc_state_t interface; + + /** + * Get Event ID Epoch + * + * @return Event ID Epoch + */ + u_int32_t (*get_eid_epoch)(imc_swid_state_t *this); + +}; + +/** + * Create an imc_swid_state_t instance + * + * @param id connection ID + */ +imc_state_t* imc_swid_state_create(TNC_ConnectionID id); + +#endif /** IMC_SWID_STATE_H_ @}*/ diff --git a/src/libimcv/plugins/imc_swid/regid.2004-03.org.strongswan_strongSwan.swidtag.in b/src/libimcv/plugins/imc_swid/regid.2004-03.org.strongswan_strongSwan.swidtag.in new file mode 100644 index 000000000..8b7b50fdf --- /dev/null +++ b/src/libimcv/plugins/imc_swid/regid.2004-03.org.strongswan_strongSwan.swidtag.in @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> + +<SoftwareIdentity + name="strongSwan" + uniqueId="strongSwan-@VERSION_MAJOR@-@VERSION_MINOR@-@VERSION_BUILD@@VERSION_REVIEW@" + version="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_BUILD@@VERSION_REVIEW@" versionScheme="alphanumeric" + xmlns="http://standards.iso.org/iso/19770/-2/2014/schema.xsd"> + <Entity + name="strongSwan Project" + regid="regid.2004-03.org.strongswan" + role="publisher licensor tagcreator"/> +</SoftwareIdentity> diff --git a/src/libimcv/plugins/imc_test/Makefile.in b/src/libimcv/plugins/imc_test/Makefile.in index 1702574f9..3e1d0232f 100644 --- a/src/libimcv/plugins/imc_test/Makefile.in +++ b/src/libimcv/plugins/imc_test/Makefile.in @@ -230,6 +230,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ GPRBUILD = @GPRBUILD@ @@ -290,6 +291,7 @@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ RUBYINCLUDE = @RUBYINCLUDE@ RUBYLIB = @RUBYLIB@ SED = @SED@ @@ -355,6 +357,8 @@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -402,6 +406,10 @@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ target_alias = @target_alias@ diff --git a/src/libimcv/plugins/imc_test/imc_test.c b/src/libimcv/plugins/imc_test/imc_test.c index ee982d93b..d38ace140 100644 --- a/src/libimcv/plugins/imc_test/imc_test.c +++ b/src/libimcv/plugins/imc_test/imc_test.c @@ -181,7 +181,7 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, } } -static TNC_Result send_message(imc_state_t *state, imc_msg_t *out_msg) +static void create_message(imc_state_t *state, imc_msg_t *out_msg) { imc_test_state_t *test_state; pa_tnc_attr_t *attr; @@ -196,9 +196,6 @@ static TNC_Result send_message(imc_state_t *state, imc_msg_t *out_msg) attr = ita_attr_command_create(test_state->get_command(test_state)); attr->set_noskip_flag(attr, TRUE); out_msg->add_attribute(out_msg, attr); - - /* send PA-TNC message with the excl flag set */ - return out_msg->send(out_msg, TRUE); } /** @@ -224,10 +221,11 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, return TNC_RESULT_FATAL; } - /* send PA message for primary IMC ID */ + /* send PA message for primary IMC ID with the EXCL flag set */ out_msg = imc_msg_create(imc_test, state, connection_id, imc_id, TNC_IMVID_ANY, msg_types[0]); - result = send_message(state, out_msg); + create_message(state, out_msg); + result = out_msg->send(out_msg, TRUE); out_msg->destroy(out_msg); /* Exit if there are no additional IMC IDs */ @@ -253,7 +251,8 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, additional_id = (TNC_UInt32)pointer; out_msg = imc_msg_create(imc_test, state, connection_id, additional_id, TNC_IMVID_ANY, msg_types[0]); - result = send_message(state, out_msg); + create_message(state, out_msg); + result = out_msg->send(out_msg, TRUE); out_msg->destroy(out_msg); } enumerator->destroy(enumerator); @@ -267,13 +266,17 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) enumerator_t *enumerator; pa_tnc_attr_t *attr; pen_type_t attr_type; - TNC_Result result; + TNC_Result result = TNC_RESULT_SUCCESS; bool fatal_error = FALSE; + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imc_msg_create_as_reply(in_msg); + /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); + result = in_msg->receive(in_msg, out_msg, &fatal_error); if (result != TNC_RESULT_SUCCESS) { + out_msg->destroy(out_msg); return result; } @@ -308,16 +311,17 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg) if (fatal_error) { - return TNC_RESULT_FATAL; + result = TNC_RESULT_FATAL; } - - /* if no assessment result is known then repeat the measurement */ - if (state->get_result(state, in_msg->get_dst_id(in_msg), NULL)) + else { - return TNC_RESULT_SUCCESS; + /* if no assessment result is known then repeat the measurement */ + if (!state->get_result(state, in_msg->get_dst_id(in_msg), NULL)) + { + create_message(state, out_msg); + } + result = out_msg->send(out_msg, TRUE); } - out_msg = imc_msg_create_as_reply(in_msg); - result = send_message(state, out_msg); out_msg->destroy(out_msg); return result; diff --git a/src/libimcv/plugins/imc_test/imc_test_state.c b/src/libimcv/plugins/imc_test/imc_test_state.c index e7beca0aa..d3f6805ad 100644 --- a/src/libimcv/plugins/imc_test/imc_test_state.c +++ b/src/libimcv/plugins/imc_test/imc_test_state.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 @@ -64,6 +64,11 @@ struct private_imc_test_state_t { u_int32_t max_msg_len; /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** * Command to transmit to IMV */ char *command; @@ -130,6 +135,12 @@ METHOD(imc_state_t, get_max_msg_len, u_int32_t, return this->max_msg_len; } +METHOD(imc_state_t, get_contracts, seg_contract_manager_t*, + private_imc_test_state_t *this) +{ + return this->contracts; +} + METHOD(imc_state_t, change_state, void, private_imc_test_state_t *this, TNC_ConnectionState new_state) { @@ -195,6 +206,7 @@ METHOD(imc_state_t, destroy, void, private_imc_test_state_t *this) { this->results->destroy_function(this->results, free); + this->contracts->destroy(this->contracts); free(this->command); free(this); } @@ -261,6 +273,7 @@ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id, .set_flags = _set_flags, .set_max_msg_len = _set_max_msg_len, .get_max_msg_len = _get_max_msg_len, + .get_contracts = _get_contracts, .change_state = _change_state, .set_result = _set_result, .get_result = _get_result, @@ -275,6 +288,7 @@ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id, .state = TNC_CONNECTION_STATE_CREATE, .results = linked_list_create(), .connection_id = connection_id, + .contracts = seg_contract_manager_create(), .command = strdup(command), .dummy_size = dummy_size, .first_handshake = TRUE, diff --git a/src/libimcv/plugins/imv_attestation/Makefile.am b/src/libimcv/plugins/imv_attestation/Makefile.am new file mode 100644 index 000000000..6c5bf8913 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/Makefile.am @@ -0,0 +1,33 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv \ + -DPLUGINS=\""${attest_plugins}\"" + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +imcv_LTLIBRARIES = imv-attestation.la + +imv_attestation_la_LIBADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +imv_attestation_la_SOURCES = imv_attestation.c \ + imv_attestation_state.h imv_attestation_state.c \ + imv_attestation_agent.h imv_attestation_agent.c \ + imv_attestation_process.h imv_attestation_process.c \ + imv_attestation_build.h imv_attestation_build.c + +imv_attestation_la_LDFLAGS = -module -avoid-version -no-undefined + +ipsec_PROGRAMS = attest +attest_SOURCES = attest.c \ + attest_usage.h attest_usage.c \ + attest_db.h attest_db.c +attest_LDADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +attest.o : $(top_builddir)/config.status + +EXTRA_DIST = build-database.sh diff --git a/src/libimcv/plugins/imv_attestation/Makefile.in b/src/libimcv/plugins/imv_attestation/Makefile.in new file mode 100644 index 000000000..3ba7c8c88 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/Makefile.in @@ -0,0 +1,847 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +ipsec_PROGRAMS = attest$(EXEEXT) +subdir = src/libimcv/plugins/imv_attestation +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/split-package-version.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(imcvdir)" "$(DESTDIR)$(ipsecdir)" +LTLIBRARIES = $(imcv_LTLIBRARIES) +imv_attestation_la_DEPENDENCIES = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +am_imv_attestation_la_OBJECTS = imv_attestation.lo \ + imv_attestation_state.lo imv_attestation_agent.lo \ + imv_attestation_process.lo imv_attestation_build.lo +imv_attestation_la_OBJECTS = $(am_imv_attestation_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +imv_attestation_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(imv_attestation_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +PROGRAMS = $(ipsec_PROGRAMS) +am_attest_OBJECTS = attest.$(OBJEXT) attest_usage.$(OBJEXT) \ + attest_db.$(OBJEXT) +attest_OBJECTS = $(am_attest_OBJECTS) +attest_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(imv_attestation_la_SOURCES) $(attest_SOURCES) +DIST_SOURCES = $(imv_attestation_la_SOURCES) $(attest_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COVERAGE_CFLAGS = @COVERAGE_CFLAGS@ +COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GEM = @GEM@ +GENHTML = @GENHTML@ +GPERF = @GPERF@ +GPRBUILD = @GPRBUILD@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_BUILD = @PACKAGE_VERSION_BUILD@ +PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@ +PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@ +PACKAGE_VERSION_REVIEW = @PACKAGE_VERSION_REVIEW@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +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@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ +RUBYINCLUDE = @RUBYINCLUDE@ +RUBYLIB = @RUBYLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +UNWINDLIB = @UNWINDLIB@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +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@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +cmd_plugins = @cmd_plugins@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +fips_mode = @fips_mode@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ +sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ +systemdsystemunitdir = @systemdsystemunitdir@ +t_plugins = @t_plugins@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv \ + -DPLUGINS=\""${attest_plugins}\"" + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +imcv_LTLIBRARIES = imv-attestation.la +imv_attestation_la_LIBADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +imv_attestation_la_SOURCES = imv_attestation.c \ + imv_attestation_state.h imv_attestation_state.c \ + imv_attestation_agent.h imv_attestation_agent.c \ + imv_attestation_process.h imv_attestation_process.c \ + imv_attestation_build.h imv_attestation_build.c + +imv_attestation_la_LDFLAGS = -module -avoid-version -no-undefined +attest_SOURCES = attest.c \ + attest_usage.h attest_usage.c \ + attest_db.h attest_db.c + +attest_LDADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la + +EXTRA_DIST = build-database.sh +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libimcv/plugins/imv_attestation/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libimcv/plugins/imv_attestation/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-imcvLTLIBRARIES: $(imcv_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(imcvdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(imcvdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imcvdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imcvdir)"; \ + } + +uninstall-imcvLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imcvdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imcvdir)/$$f"; \ + done + +clean-imcvLTLIBRARIES: + -test -z "$(imcv_LTLIBRARIES)" || rm -f $(imcv_LTLIBRARIES) + @list='$(imcv_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +imv-attestation.la: $(imv_attestation_la_OBJECTS) $(imv_attestation_la_DEPENDENCIES) $(EXTRA_imv_attestation_la_DEPENDENCIES) + $(AM_V_CCLD)$(imv_attestation_la_LINK) -rpath $(imcvdir) $(imv_attestation_la_OBJECTS) $(imv_attestation_la_LIBADD) $(LIBS) +install-ipsecPROGRAMS: $(ipsec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(ipsecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(ipsecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(ipsecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-ipsecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(ipsecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(ipsecdir)" && rm -f $$files + +clean-ipsecPROGRAMS: + @list='$(ipsec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +attest$(EXEEXT): $(attest_OBJECTS) $(attest_DEPENDENCIES) $(EXTRA_attest_DEPENDENCIES) + @rm -f attest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(attest_OBJECTS) $(attest_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attest_db.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attest_usage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_attestation.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_attestation_agent.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_attestation_build.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_attestation_process.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_attestation_state.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(imcvdir)" "$(DESTDIR)$(ipsecdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-imcvLTLIBRARIES clean-ipsecPROGRAMS \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-imcvLTLIBRARIES install-ipsecPROGRAMS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-imcvLTLIBRARIES uninstall-ipsecPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-imcvLTLIBRARIES clean-ipsecPROGRAMS clean-libtool \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-imcvLTLIBRARIES install-info install-info-am \ + install-ipsecPROGRAMS install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-imcvLTLIBRARIES \ + uninstall-ipsecPROGRAMS + +attest.o : $(top_builddir)/config.status + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libimcv/plugins/imv_attestation/attest.c b/src/libimcv/plugins/imv_attestation/attest.c new file mode 100644 index 000000000..1143a0356 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/attest.c @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE +#include <getopt.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <libgen.h> +#ifdef HAVE_SYSLOG +# include <syslog.h> +#endif + +#include <library.h> +#include <utils/debug.h> + +#include <imcv.h> +#include <pts/pts_meas_algo.h> + +#include "attest_db.h" +#include "attest_usage.h" + +/** + * global debug output variables + */ +static int debug_level = 1; +static bool stderr_quiet = TRUE; + +/** + * attest dbg function + */ +static void attest_dbg(debug_t group, level_t level, char *fmt, ...) +{ + va_list args; + + if (level <= debug_level) + { + if (!stderr_quiet) + { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + } + +#ifdef HAVE_SYSLOG + { + int priority = LOG_INFO; + char buffer[8192]; + char *current = buffer, *next; + + /* write in memory buffer first */ + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + /* do a syslog with every line */ + while (current) + { + next = strchr(current, '\n'); + if (next) + { + *(next++) = '\0'; + } + syslog(priority, "%s\n", current); + current = next; + } + } +#endif /* HAVE_SYSLOG */ + } +} + +/** + * global attestation database object + */ +attest_db_t *attest; + + +/** + * atexit handler to close db on shutdown + */ +static void cleanup(void) +{ + attest->destroy(attest); + libimcv_deinit(); +#ifdef HAVE_SYSLOG + closelog(); +#endif +} + +static void do_args(int argc, char *argv[]) +{ + enum { + OP_UNDEF, + OP_USAGE, + OP_KEYS, + OP_COMPONENTS, + OP_DEVICES, + OP_DIRECTORIES, + OP_FILES, + OP_HASHES, + OP_MEASUREMENTS, + OP_PACKAGES, + OP_PRODUCTS, + OP_SESSIONS, + OP_ADD, + OP_DEL, + } op = OP_UNDEF; + + /* reinit getopt state */ + optind = 0; + + while (TRUE) + { + int c; + + struct option long_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "components", no_argument, NULL, 'c' }, + { "devices", no_argument, NULL, 'e' }, + { "directories", no_argument, NULL, 'd' }, + { "dirs", no_argument, NULL, 'd' }, + { "files", no_argument, NULL, 'f' }, + { "keys", no_argument, NULL, 'k' }, + { "packages", no_argument, NULL, 'g' }, + { "products", no_argument, NULL, 'p' }, + { "hashes", no_argument, NULL, 'H' }, + { "measurements", no_argument, NULL, 'm' }, + { "sessions", no_argument, NULL, 's' }, + { "add", no_argument, NULL, 'a' }, + { "delete", no_argument, NULL, 'r' }, + { "del", no_argument, NULL, 'r' }, + { "remove", no_argument, NULL, 'r' }, + { "aik", required_argument, NULL, 'A' }, + { "blacklist", no_argument, NULL, 'B' }, + { "component", required_argument, NULL, 'C' }, + { "comp", required_argument, NULL, 'C' }, + { "directory", required_argument, NULL, 'D' }, + { "dir", required_argument, NULL, 'D' }, + { "file", required_argument, NULL, 'F' }, + { "package", required_argument, NULL, 'G' }, + { "key", required_argument, NULL, 'K' }, + { "measdir", required_argument, NULL, 'M' }, + { "owner", required_argument, NULL, 'O' }, + { "product", required_argument, NULL, 'P' }, + { "relative", no_argument, NULL, 'R' }, + { "rel", no_argument, NULL, 'R' }, + { "sequence", required_argument, NULL, 'S' }, + { "seq", required_argument, NULL, 'S' }, + { "utc", no_argument, NULL, 'U' }, + { "version", required_argument, NULL, 'V' }, + { "security", no_argument, NULL, 'Y' }, + { "sha1", no_argument, NULL, '1' }, + { "sha256", no_argument, NULL, '2' }, + { "sha384", no_argument, NULL, '3' }, + { "did", required_argument, NULL, '4' }, + { "fid", required_argument, NULL, '5' }, + { "pid", required_argument, NULL, '6' }, + { "cid", required_argument, NULL, '7' }, + { "kid", required_argument, NULL, '8' }, + { "gid", required_argument, NULL, '9' }, + { 0,0,0,0 } + }; + + c = getopt_long(argc, argv, "", long_opts, NULL); + switch (c) + { + case EOF: + break; + case 'h': + op = OP_USAGE; + break; + case 'c': + op = OP_COMPONENTS; + continue; + case 'd': + op = OP_DIRECTORIES; + continue; + case 'e': + op = OP_DEVICES; + continue; + case 'f': + op = OP_FILES; + continue; + case 'g': + op = OP_PACKAGES; + continue; + case 'k': + op = OP_KEYS; + continue; + case 'p': + op = OP_PRODUCTS; + continue; + case 'H': + op = OP_HASHES; + continue; + case 'm': + op = OP_MEASUREMENTS; + continue; + case 's': + op = OP_SESSIONS; + continue; + case 'a': + op = OP_ADD; + continue; + case 'r': + op = OP_DEL; + continue; + case 'A': + { + certificate_t *aik_cert; + public_key_t *aik_key; + chunk_t aik; + + aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_X509, BUILD_FROM_FILE, optarg, BUILD_END); + if (!aik_cert) + { + printf("AIK certificate '%s' could not be loaded\n", optarg); + exit(EXIT_FAILURE); + } + aik_key = aik_cert->get_public_key(aik_cert); + aik_cert->destroy(aik_cert); + + if (!aik_key) + { + printf("AIK public key could not be retrieved\n"); + exit(EXIT_FAILURE); + } + if (!aik_key->get_fingerprint(aik_key, KEYID_PUBKEY_INFO_SHA1, + &aik)) + { + printf("AIK fingerprint could not be computed\n"); + aik_key->destroy(aik_key); + exit(EXIT_FAILURE); + } + aik = chunk_clone(aik); + aik_key->destroy(aik_key); + + if (!attest->set_key(attest, aik, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + } + case 'B': + attest->set_package_state(attest, OS_PACKAGE_STATE_BLACKLIST); + continue; + case 'C': + if (!attest->set_component(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case 'D': + if (!attest->set_directory(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case 'F': + { + char *dir = path_dirname(optarg); + char *file = path_basename(optarg); + + if (*dir != '.') + { + if (!attest->set_directory(attest, dir, op == OP_ADD)) + { + free(file); + free(dir); + exit(EXIT_FAILURE); + } + } + free(dir); + + if (!attest->set_file(attest, file, op == OP_ADD)) + { + free(file); + exit(EXIT_FAILURE); + } + free(file); + continue; + } + case 'G': + if (!attest->set_package(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case 'K': + { + chunk_t aik; + + aik = chunk_from_hex(chunk_create(optarg, strlen(optarg)), NULL); + if (!attest->set_key(attest, aik, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + } + case 'M': + if (!attest->set_meas_directory(attest, optarg)) + { + exit(EXIT_FAILURE); + } + continue; + case 'O': + attest->set_owner(attest, optarg); + continue; + case 'P': + if (!attest->set_product(attest, optarg, op == OP_ADD)) + { + exit(EXIT_FAILURE); + } + continue; + case 'R': + attest->set_relative(attest); + continue; + case 'S': + attest->set_sequence(attest, atoi(optarg)); + continue; + case 'U': + attest->set_utc(attest); + continue; + case 'V': + if (!attest->set_version(attest, optarg)) + { + exit(EXIT_FAILURE); + } + continue; + case 'Y': + attest->set_package_state(attest, OS_PACKAGE_STATE_SECURITY); + continue; + case '1': + attest->set_algo(attest, PTS_MEAS_ALGO_SHA1); + continue; + case '2': + attest->set_algo(attest, PTS_MEAS_ALGO_SHA256); + continue; + case '3': + attest->set_algo(attest, PTS_MEAS_ALGO_SHA384); + continue; + case '4': + if (!attest->set_did(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '5': + if (!attest->set_fid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '6': + if (!attest->set_pid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '7': + if (!attest->set_cid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '8': + if (!attest->set_kid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + case '9': + if (!attest->set_gid(attest, atoi(optarg))) + { + exit(EXIT_FAILURE); + } + continue; + } + break; + } + + switch (op) + { + case OP_USAGE: + usage(); + break; + case OP_PACKAGES: + attest->list_packages(attest); + break; + case OP_PRODUCTS: + attest->list_products(attest); + break; + case OP_KEYS: + attest->list_keys(attest); + break; + case OP_COMPONENTS: + attest->list_components(attest); + break; + case OP_DEVICES: + attest->list_devices(attest); + break; + case OP_DIRECTORIES: + attest->list_directories(attest); + break; + case OP_FILES: + attest->list_files(attest); + break; + case OP_HASHES: + attest->list_hashes(attest); + break; + case OP_MEASUREMENTS: + attest->list_measurements(attest); + break; + case OP_SESSIONS: + attest->list_sessions(attest); + break; + case OP_ADD: + attest->add(attest); + break; + case OP_DEL: + attest->delete(attest); + break; + default: + usage(); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char *argv[]) +{ + char *uri; + + /* enable attest debugging hook */ + dbg = attest_dbg; +#ifdef HAVE_SYSLOG + openlog("attest", 0, LOG_DEBUG); +#endif + + atexit(library_deinit); + + /* initialize library */ + if (!library_init(NULL, "attest")) + { + exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); + } + if (!lib->plugins->load(lib->plugins, + lib->settings->get_str(lib->settings, "attest.load", PLUGINS))) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + + uri = lib->settings->get_str(lib->settings, "attest.database", NULL); + if (!uri) + { + fprintf(stderr, "database URI attest.database not set.\n"); + exit(SS_RC_INITIALIZATION_FAILED); + } + attest = attest_db_create(uri); + if (!attest) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + atexit(cleanup); + libimcv_init(FALSE); + + do_args(argc, argv); + + exit(EXIT_SUCCESS); +} diff --git a/src/libimcv/plugins/imv_attestation/attest_db.c b/src/libimcv/plugins/imv_attestation/attest_db.c new file mode 100644 index 000000000..f85a02b3d --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/attest_db.c @@ -0,0 +1,1995 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <libgen.h> +#include <time.h> + +#include <tncif_names.h> + +#include "attest_db.h" + +#include "imcv.h" +#include "pts/pts_meas_algo.h" +#include "pts/pts_file_meas.h" +#include "pts/components/pts_comp_func_name.h" + +#define IMA_MAX_NAME_LEN 255 +#define DEVICE_MAX_LEN 20 + +typedef struct private_attest_db_t private_attest_db_t; + +/** + * Private data of an attest_db_t object. + */ +struct private_attest_db_t { + + /** + * Public members of attest_db_state_t + */ + attest_db_t public; + + /** + * Component Functional Name to be queried + */ + pts_comp_func_name_t *cfn; + + /** + * Primary key of the Component Functional Name to be queried + */ + int cid; + + /** + * TRUE if Component Functional Name has been set + */ + bool comp_set; + + /** + * Directory containing the Measurement file to be queried + */ + char *dir; + + /** + * Primary key of the directory to be queried + */ + int did; + + /** + * Measurement file to be queried + */ + char *file; + + /** + * Primary key of measurement file to be queried + */ + int fid; + + /** + * Directory where file measurement are to be taken + */ + char *meas_dir; + + /** + * AIK to be queried + */ + chunk_t key; + + /** + * Primary key of the AIK to be queried + */ + int kid; + + /** + * TRUE if AIK has been set + */ + bool key_set; + + /** + * Software package to be queried + */ + char *package; + + /** + * Primary key of software package to be queried + */ + int gid; + + /** + * TRUE if package has been set + */ + bool package_set; + + /** + * Software product to be queried + */ + char *product; + + /** + * Primary key of software product to be queried + */ + int pid; + + /** + * TRUE if product has been set + */ + bool product_set; + + /** + * Software package version to be queried + */ + char *version; + + /** + * TRUE if version has been set + */ + bool version_set; + + /** + * TRUE if relative filenames are to be used + */ + bool relative; + + /** + * TRUE if dates are to be displayed in UTC + */ + bool utc; + + /** + * Package security or blacklist state + */ + os_package_state_t package_state; + + /** + * Sequence number for ordering entries + */ + int seq_no; + + /** + * File measurement hash algorithm + */ + pts_meas_algorithms_t algo; + + /** + * Optional owner (user/host name) + */ + char *owner; + + /** + * Attestation database + */ + database_t *db; + +}; + +char* print_cfn(pts_comp_func_name_t *cfn) +{ + static char buf[BUF_LEN]; + char flags[8]; + int type, vid, name, qualifier, n; + enum_name_t *names, *types; + + vid = cfn->get_vendor_id(cfn), + name = cfn->get_name(cfn); + qualifier = cfn->get_qualifier(cfn); + n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier); + + names = imcv_pts_components->get_comp_func_names(imcv_pts_components, vid); + types = imcv_pts_components->get_qualifier_type_names(imcv_pts_components, + vid); + type = imcv_pts_components->get_qualifier(imcv_pts_components, cfn, flags); + if (names && types) + { + n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N", + pen_names, vid, names, name, flags, types, type); + } + 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) +{ + enumerator_t *e; + char *pos1, *pos2; + int vid, name, qualifier; + pts_comp_func_name_t *cfn; + + if (this->comp_set) + { + printf("component has already been set\n"); + return FALSE; + } + + /* parse component string */ + pos1 = strchr(comp, '/'); + pos2 = strchr(comp, '-'); + if (!pos1 || !pos2) + { + printf("component string must have the form \"vendor_id/name-qualifier\"\n"); + return FALSE; + } + vid = atoi(comp); + name = atoi(pos1 + 1); + qualifier = atoi(pos2 + 1); + cfn = pts_comp_func_name_create(vid, name, qualifier); + + e = this->db->query(this->db, + "SELECT id FROM components " + "WHERE vendor_id = ? AND name = ? AND qualifier = ?", + DB_UINT, vid, DB_INT, name, DB_INT, qualifier, DB_INT); + if (e) + { + if (e->enumerate(e, &this->cid)) + { + this->comp_set = TRUE; + this->cfn = cfn; + } + e->destroy(e); + } + if (this->comp_set) + { + return TRUE; + } + + if (!create) + { + printf("component '%s' not found in database\n", print_cfn(cfn)); + cfn->destroy(cfn); + return FALSE; + } + + /* Add a new database entry */ + this->comp_set = this->db->execute(this->db, &this->cid, + "INSERT INTO components (vendor_id, name, qualifier) " + "VALUES (?, ?, ?)", + DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1; + + printf("component '%s' %sinserted into database\n", print_cfn(cfn), + this->comp_set ? "" : "could not be "); + if (this->comp_set) + { + this->cfn = cfn; + } + else + { + cfn->destroy(cfn); + } + return this->comp_set; +} + +METHOD(attest_db_t, set_cid, bool, + private_attest_db_t *this, int cid) +{ + enumerator_t *e; + int vid, name, qualifier; + + if (this->comp_set) + { + printf("component has already been set\n"); + return FALSE; + } + this->cid = cid; + + e = this->db->query(this->db, "SELECT vendor_id, name, qualifier " + "FROM components WHERE id = ?", + DB_UINT, cid, DB_INT, DB_INT, DB_INT); + if (e) + { + if (e->enumerate(e, &vid, &name, &qualifier)) + { + this->cfn = pts_comp_func_name_create(vid, name, qualifier); + this->comp_set = TRUE; + } + else + { + printf("no component found with cid %d\n", cid); + } + e->destroy(e); + } + return this->comp_set; +} + +METHOD(attest_db_t, set_directory, bool, + private_attest_db_t *this, char *dir, bool create) +{ + enumerator_t *e; + int did; + size_t len; + + if (this->did) + { + printf("directory has already been set\n"); + return FALSE; + } + + /* remove trailing '/' or '\' character if not root directory */ + len = strlen(dir); + if (len > 1 && dir[len-1] == DIRECTORY_SEPARATOR[0]) + { + dir[len-1] = '\0'; + } + this->dir = strdup(dir); + + e = this->db->query(this->db, + "SELECT id FROM directories WHERE path = ?", + DB_TEXT, dir, DB_INT); + if (e) + { + if (e->enumerate(e, &did)) + { + this->did = did; + } + e->destroy(e); + } + if (this->did) + { + return TRUE; + } + + if (!create) + { + printf("directory '%s' not found in database\n", dir); + return FALSE; + } + + /* Add a new database entry */ + if (1 == this->db->execute(this->db, &did, + "INSERT INTO directories (path) VALUES (?)", DB_TEXT, dir)) + { + this->did = did; + } + printf("directory '%s' %sinserted into database\n", dir, + this->did ? "" : "could not be "); + + return this->did > 0; +} + +METHOD(attest_db_t, set_did, bool, + private_attest_db_t *this, int did) +{ + enumerator_t *e; + char *dir; + + if (this->did) + { + printf("directory has already been set\n"); + return FALSE; + } + + e = this->db->query(this->db, "SELECT path FROM directories WHERE id = ?", + DB_UINT, did, DB_TEXT); + if (e) + { + if (e->enumerate(e, &dir)) + { + this->dir = strdup(dir); + this->did = did; + } + else + { + printf("no directory found with did %d\n", did); + } + e->destroy(e); + } + return this->did > 0; +} + +METHOD(attest_db_t, set_file, bool, + private_attest_db_t *this, char *file, bool create) +{ + int fid; + enumerator_t *e; + + if (this->file) + { + printf("file has already been set\n"); + return FALSE; + } + this->file = strdup(file); + + if (!this->did) + { + return TRUE; + } + e = this->db->query(this->db, "SELECT id FROM files " + "WHERE dir = ? AND name = ?", + DB_INT, this->did, DB_TEXT, file, DB_INT); + if (e) + { + if (e->enumerate(e, &fid)) + { + this->fid = fid; + } + e->destroy(e); + } + if (this->fid) + { + return TRUE; + } + + if (!create) + { + printf("file '%s%s%s' not found in database\n", + this->dir, get_separator(this->dir), file); + return FALSE; + } + + /* Add a new database entry */ + if (1 == this->db->execute(this->db, &fid, + "INSERT INTO files (dir, name) VALUES (?, ?)", + DB_INT, this->did, DB_TEXT, file)) + { + this->fid = fid; + } + 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; +} + +METHOD(attest_db_t, set_fid, bool, + private_attest_db_t *this, int fid) +{ + enumerator_t *e; + int did; + char *file; + + if (this->fid) + { + printf("file has already been set\n"); + return FALSE; + } + + e = this->db->query(this->db, "SELECT dir, name FROM files WHERE id = ?", + DB_UINT, fid, DB_INT, DB_TEXT); + if (e) + { + if (e->enumerate(e, &did, &file)) + { + if (did) + { + set_did(this, did); + } + this->file = strdup(file); + this->fid = fid; + } + else + { + printf("no file found with fid %d\n", fid); + } + e->destroy(e); + } + 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) +{ + enumerator_t *e; + char *owner; + + if (this->key_set) + { + printf("key has already been set\n"); + return FALSE; + } + this->key = key; + + e = this->db->query(this->db, "SELECT id, owner FROM keys WHERE keyid= ?", + DB_BLOB, this->key, DB_INT, DB_TEXT); + if (e) + { + if (e->enumerate(e, &this->kid, &owner)) + { + free(this->owner); + this->owner = strdup(owner); + this->key_set = TRUE; + } + e->destroy(e); + } + if (this->key_set) + { + return TRUE; + } + + if (!create) + { + printf("key '%#B' not found in database\n", &this->key); + return FALSE; + } + + /* Add a new database entry */ + if (!this->owner) + { + this->owner = strdup(""); + } + this->key_set = this->db->execute(this->db, &this->kid, + "INSERT INTO keys (keyid, owner) VALUES (?, ?)", + DB_BLOB, this->key, DB_TEXT, this->owner) == 1; + + printf("key '%#B' %sinserted into database\n", &this->key, + this->key_set ? "" : "could not be "); + + return this->key_set; + +}; + +METHOD(attest_db_t, set_kid, bool, + private_attest_db_t *this, int kid) +{ + enumerator_t *e; + chunk_t key; + char *owner; + + if (this->key_set) + { + printf("key has already been set\n"); + return FALSE; + } + this->kid = kid; + + e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?", + DB_UINT, kid, DB_BLOB, DB_TEXT); + if (e) + { + if (e->enumerate(e, &key, &owner)) + { + this->owner = strdup(owner); + this->key = chunk_clone(key); + this->key_set = TRUE; + } + else + { + printf("no key found with kid %d\n", kid); + } + e->destroy(e); + } + return this->key_set; + +}; + +METHOD(attest_db_t, set_product, bool, + private_attest_db_t *this, char *product, bool create) +{ + enumerator_t *e; + + if (this->product_set) + { + printf("product has already been set\n"); + return FALSE; + } + this->product = strdup(product); + + e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?", + DB_TEXT, product, DB_INT); + if (e) + { + if (e->enumerate(e, &this->pid)) + { + this->product_set = TRUE; + } + e->destroy(e); + } + if (this->product_set) + { + return TRUE; + } + + if (!create) + { + printf("product '%s' not found in database\n", product); + return FALSE; + } + + /* Add a new database entry */ + this->product_set = this->db->execute(this->db, &this->pid, + "INSERT INTO products (name) VALUES (?)", + DB_TEXT, product) == 1; + + printf("product '%s' %sinserted into database\n", product, + this->product_set ? "" : "could not be "); + + return this->product_set; +} + +METHOD(attest_db_t, set_pid, bool, + private_attest_db_t *this, int pid) +{ + enumerator_t *e; + char *product; + + if (this->product_set) + { + printf("product has already been set\n"); + return FALSE; + } + this->pid = pid; + + e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?", + DB_UINT, pid, DB_TEXT); + if (e) + { + if (e->enumerate(e, &product)) + { + this->product = strdup(product); + this->product_set = TRUE; + } + else + { + printf("no product found with pid %d in database\n", pid); + } + e->destroy(e); + } + return this->product_set; +} + +METHOD(attest_db_t, set_package, bool, + private_attest_db_t *this, char *package, bool create) +{ + enumerator_t *e; + + if (this->package_set) + { + printf("package has already been set\n"); + return FALSE; + } + this->package = strdup(package); + + e = this->db->query(this->db, "SELECT id FROM packages WHERE name = ?", + DB_TEXT, package, DB_INT); + if (e) + { + if (e->enumerate(e, &this->gid)) + { + this->package_set = TRUE; + } + e->destroy(e); + } + if (this->package_set) + { + return TRUE; + } + + if (!create) + { + printf("package '%s' not found in database\n", package); + return FALSE; + } + + /* Add a new database entry */ + this->package_set = this->db->execute(this->db, &this->gid, + "INSERT INTO packages (name) VALUES (?)", + DB_TEXT, package) == 1; + + printf("package '%s' %sinserted into database\n", package, + this->package_set ? "" : "could not be "); + + return this->package_set; +} + +METHOD(attest_db_t, set_gid, bool, + private_attest_db_t *this, int gid) +{ + enumerator_t *e; + char *package; + + if (this->package_set) + { + printf("package has already been set\n"); + return FALSE; + } + this->gid = gid; + + e = this->db->query(this->db, "SELECT name FROM packages WHERE id = ?", + DB_UINT, gid, DB_TEXT); + if (e) + { + if (e->enumerate(e, &package)) + { + this->package = strdup(package); + this->package_set = TRUE; + } + else + { + printf("no package found with gid %d in database\n", gid); + } + e->destroy(e); + } + return this->package_set; +} + +METHOD(attest_db_t, set_version, bool, + private_attest_db_t *this, char *version) +{ + if (this->version_set) + { + printf("version has already been set\n"); + return FALSE; + } + this->version = strdup(version); + this->version_set = TRUE; + + return TRUE; +} + + +METHOD(attest_db_t, set_algo, void, + private_attest_db_t *this, pts_meas_algorithms_t algo) +{ + this->algo = algo; +} + +METHOD(attest_db_t, set_relative, void, + private_attest_db_t *this) +{ + this->relative = TRUE; +} + +METHOD(attest_db_t, set_package_state, void, + private_attest_db_t *this, os_package_state_t package_state) +{ + this->package_state = package_state; +} + +METHOD(attest_db_t, set_sequence, void, + private_attest_db_t *this, int seq_no) +{ + this->seq_no = seq_no; +} + +METHOD(attest_db_t, set_owner, void, + private_attest_db_t *this, char *owner) +{ + free(this->owner); + this->owner = strdup(owner); +} + +METHOD(attest_db_t, set_utc, void, + private_attest_db_t *this) +{ + this->utc = TRUE; +} + +METHOD(attest_db_t, list_components, void, + private_attest_db_t *this) +{ + enumerator_t *e; + pts_comp_func_name_t *cfn; + int seq_no, cid, vid, name, qualifier, count = 0; + + if (this->kid) + { + e = this->db->query(this->db, + "SELECT kc.seq_no, c.id, c.vendor_id, c.name, c.qualifier " + "FROM components AS c " + "JOIN key_component AS kc ON c.id = kc.component " + "WHERE kc.key = ? ORDER BY kc.seq_no", + DB_UINT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &cid, &seq_no, &vid, &name, &qualifier)) + { + cfn = pts_comp_func_name_create(vid, name, qualifier); + printf("%4d: #%-2d %s\n", seq_no, cid, print_cfn(cfn)); + cfn->destroy(cfn); + count++; + } + e->destroy(e); + printf("%d component%s found for key %#B\n", count, + (count == 1) ? "" : "s", &this->key); + } + } + else + { + e = this->db->query(this->db, + "SELECT id, vendor_id, name, qualifier FROM components " + "ORDER BY vendor_id, name, qualifier", + DB_INT, DB_INT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &cid, &vid, &name, &qualifier)) + { + cfn = pts_comp_func_name_create(vid, name, qualifier); + printf("%4d: %s\n", cid, print_cfn(cfn)); + cfn->destroy(cfn); + count++; + } + e->destroy(e); + printf("%d component%s found\n", count, (count == 1) ? "" : "s"); + } + } +} + +METHOD(attest_db_t, list_devices, void, + private_attest_db_t *this) +{ + enumerator_t *e, *e_ar; + chunk_t ar_id_value = chunk_empty; + char *product, *device; + time_t timestamp; + int id, last_id = 0, ar_id = 0, last_ar_id = 0, device_count = 0; + int session_id, rec; + u_int32_t ar_id_type; + u_int tstamp; + + e = this->db->query(this->db, + "SELECT d.id, d.value, s.id, s.time, s.identity, s.rec, p.name " + "FROM devices AS d " + "JOIN sessions AS s ON d.id = s.device " + "JOIN products AS p ON p.id = s.product " + "ORDER BY d.value, s.time DESC", DB_INT, DB_TEXT, DB_INT, DB_UINT, + DB_INT, DB_INT, DB_TEXT); + + if (e) + { + while (e->enumerate(e, &id, &device, &session_id, &tstamp, &ar_id, &rec, + &product)) + { + if (id != last_id) + { + printf("%4d: %s - %s\n", id, device, product); + device_count++; + last_id = id; + } + timestamp = tstamp; + printf("%4d: %T", session_id, ×tamp, this->utc); + if (ar_id) + { + if (ar_id != last_ar_id) + { + chunk_free(&ar_id_value); + e_ar = this->db->query(this->db, + "SELECT type, value FROM identities " + "WHERE id = ?", DB_INT, ar_id, DB_INT, DB_BLOB); + if (e_ar) + { + e_ar->enumerate(e_ar, &ar_id_type, &ar_id_value); + ar_id_value = chunk_clone(ar_id_value); + e_ar->destroy(e_ar); + } + } + if (ar_id_value.len) + { + printf(" %.*s", (int)ar_id_value.len, ar_id_value.ptr); + } + last_ar_id = ar_id; + } + printf(" - %N\n", TNC_IMV_Action_Recommendation_names, rec); + } + e->destroy(e); + free(ar_id_value.ptr); + + printf("%d device%s found\n", device_count, + (device_count == 1) ? "" : "s"); + } +} + +METHOD(attest_db_t, list_keys, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t keyid; + char *owner; + int kid, count = 0; + + if (this->cid) + { + e = this->db->query(this->db, + "SELECT k.id, k.keyid, k.owner FROM keys AS k " + "JOIN key_component AS kc ON k.id = kc.key " + "WHERE kc.component = ? ORDER BY k.keyid", + DB_UINT, this->cid, DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &kid, &keyid, &owner)) + { + printf("%4d: %#B '%s'\n", kid, &keyid, owner); + count++; + } + e->destroy(e); + } + } + else + { + e = this->db->query(this->db, "SELECT id, keyid, owner FROM keys " + "ORDER BY keyid", + DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &kid, &keyid, &owner)) + { + printf("%4d: %#B '%s'\n", kid, &keyid, owner); + count++; + } + e->destroy(e); + } + } + + printf("%d key%s found", count, (count == 1) ? "" : "s"); + if (this->comp_set) + { + printf(" for component '%s'", print_cfn(this->cfn)); + } + printf("\n"); +} + +METHOD(attest_db_t, list_files, void, + private_attest_db_t *this) +{ + enumerator_t *e; + char *dir, *file; + int did, last_did = 0, fid, count = 0; + + if (this->did) + { + e = this->db->query(this->db, + "SELECT id, name FROM files WHERE dir = ? ORDER BY name", + DB_INT, this->did, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &fid, &file)) + { + printf("%4d: %s\n", fid, file); + count++; + } + e->destroy(e); + } + printf("%d file%s found in directory '%s'\n", count, + (count == 1) ? "" : "s", this->dir); + } + else + { + e = this->db->query(this->db, + "SELECT d.id, d.path, f.id, f.name FROM files AS f " + "JOIN directories AS d ON f.dir = d.id " + "ORDER BY d.path, f.name", + DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &did, &dir, &fid, &file)) + { + if (did != last_did) + { + printf("%4d: %s\n", did, dir); + last_did = did; + } + printf("%4d: %s\n", fid, file); + count++; + } + e->destroy(e); + } + printf("%d file%s found\n", count, (count == 1) ? "" : "s"); + } +} + +METHOD(attest_db_t, list_directories, void, + private_attest_db_t *this) +{ + enumerator_t *e; + char *dir; + int did, count = 0; + + if (this->file) + { + e = this->db->query(this->db, + "SELECT d.id, d.path FROM directories AS d " + "JOIN files AS f ON f.dir = d.id WHERE f.name = ? " + "ORDER BY path", DB_TEXT, this->file, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &did, &dir)) + { + printf("%4d: %s\n", did, dir); + count++; + } + e->destroy(e); + } + printf("%d director%s found containing file '%s'\n", count, + (count == 1) ? "y" : "ies", this->file); + } + else + { + e = this->db->query(this->db, + "SELECT id, path FROM directories ORDER BY path", + DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &did, &dir)) + { + printf("%4d: %s\n", did, dir); + count++; + } + e->destroy(e); + } + printf("%d director%s found\n", count, (count == 1) ? "y" : "ies"); + } +} + +METHOD(attest_db_t, list_packages, void, + private_attest_db_t *this) +{ + enumerator_t *e; + char *package, *version; + os_package_state_t package_state; + int blacklist, security, gid, gid_old = 0, spaces, count = 0, t; + time_t timestamp; + + if (this->pid) + { + e = this->db->query(this->db, + "SELECT p.id, p.name, " + "v.release, v.security, v.blacklist, v.time " + "FROM packages AS p JOIN versions AS v ON v.package = p.id " + "WHERE v.product = ? ORDER BY p.name, v.release", + DB_INT, this->pid, + DB_INT, DB_TEXT, DB_TEXT, DB_INT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &gid, &package, + &version, &security, &blacklist, &t)) + { + if (gid != gid_old) + { + printf("%5d: %s,", gid, package); + gid_old = gid; + } + else + { + spaces = 8 + strlen(package); + while (spaces--) + { + printf(" "); + } + } + timestamp = t; + if (blacklist) + { + package_state = OS_PACKAGE_STATE_BLACKLIST; + } + else + { + package_state = security ? OS_PACKAGE_STATE_SECURITY : + OS_PACKAGE_STATE_UPDATE; + } + printf(" %T (%s)%N\n", ×tamp, this->utc, version, + os_package_state_names, package_state); + count++; + } + e->destroy(e); + } + } + else + { + e = this->db->query(this->db, "SELECT id, name FROM packages " + "ORDER BY name", + DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &gid, &package)) + { + printf("%4d: %s\n", gid, package); + count++; + } + e->destroy(e); + } + } + + printf("%d package%s found", count, (count == 1) ? "" : "s"); + if (this->product_set) + { + printf(" for product '%s'", this->product); + } + printf("\n"); +} + +METHOD(attest_db_t, list_products, void, + private_attest_db_t *this) +{ + enumerator_t *e; + char *product; + int pid, meas, meta, count = 0; + + if (this->fid) + { + e = this->db->query(this->db, + "SELECT p.id, p.name, pf.measurement, pf.metadata " + "FROM products AS p " + "JOIN product_file AS pf ON p.id = pf.product " + "WHERE pf.file = ? ORDER BY p.name", + DB_UINT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &pid, &product, &meas, &meta)) + { + printf("%4d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ", + product); + count++; + } + e->destroy(e); + } + } + else + { + e = this->db->query(this->db, "SELECT id, name FROM products " + "ORDER BY name", + DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &pid, &product)) + { + printf("%4d: %s\n", pid, product); + count++; + } + e->destroy(e); + } + } + + printf("%d product%s found", count, (count == 1) ? "" : "s"); + if (this->fid) + { + printf(" for file '%s'", this->file); + } + printf("\n"); +} + +METHOD(attest_db_t, list_hashes, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t hash; + char *file, *dir, *product; + int id, fid, fid_old = 0, did, did_old = 0, pid, pid_old = 0, count = 0; + + if (this->pid && this->fid && this->did) + { + printf("%4d: %s\n", this->did, this->dir); + printf("%4d: %s\n", this->fid, this->file); + e = this->db->query(this->db, + "SELECT id, hash FROM file_hashes " + "WHERE algo = ? AND file = ? AND product = ?", + DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->pid, + DB_INT, DB_BLOB); + if (e) + { + while (e->enumerate(e, &id, &hash)) + { + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for product '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->product); + } + } + else if (this->pid && this->file) + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, d.id, d.path " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "WHERE h.algo = ? AND h.product = ? AND f.name = ? " + "ORDER BY d.path, f.name, h.hash", + DB_INT, this->algo, DB_INT, this->pid, DB_TEXT, this->file, + DB_INT, DB_BLOB, DB_INT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &did, &dir)) + { + if (did != did_old) + { + printf("%4d: %s\n", did, dir); + did_old = did; + } + if (fid != fid_old) + { + printf("%4d: %s\n", fid, this->file); + fid_old = fid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for product '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->product); + } + } + else if (this->pid && this->did) + { + printf("%4d: %s\n", this->did, this->dir); + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, f.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "WHERE h.algo = ? AND h.product = ? AND f.dir = ? " + "ORDER BY f.name, h.hash", + DB_INT, this->algo, DB_INT, this->pid, DB_INT, this->did, + DB_INT, DB_BLOB, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &file)) + { + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); + fid_old = fid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for product '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->product); + } + } + else if (this->pid) + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, f.name, d.id, d.path " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "WHERE h.algo = ? AND h.product = ? " + "ORDER BY d.path, f.name, h.hash", + DB_INT, this->algo, DB_INT, this->pid, + DB_INT, DB_BLOB, DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir)) + { + if (did != did_old) + { + printf("%4d: %s\n", did, dir); + did_old = did; + } + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); + fid_old = fid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for product '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->product); + } + } + else if (this->fid && this->did) + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, p.id, p.name FROM file_hashes AS h " + "JOIN products AS p ON h.product = p.id " + "WHERE h.algo = ? AND h.file = ? " + "ORDER BY p.name, h.hash", + DB_INT, this->algo, DB_INT, this->fid, + DB_INT, DB_BLOB, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &pid, &product)) + { + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for file '%s%s%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->dir, + get_separator(this->dir), this->file); + } + } + else if (this->file) + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, d.id, d.path, p.id, p.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "JOIN products AS p ON h.product = p.id " + "WHERE h.algo = ? AND f.name = ? " + "ORDER BY d.path, f.name, p.name, h.hash", + DB_INT, this->algo, DB_TEXT, this->file, + DB_INT, DB_BLOB, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &did, &dir, &pid, &product)) + { + if (did != did_old) + { + printf("%4d: %s\n", did, dir); + did_old = did; + } + if (fid != fid_old) + { + printf("%4d: %s\n", fid, this->file); + fid_old = fid; + pid_old = 0; + } + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found\n", count, pts_meas_algorithm_names, + this->algo, (count == 1) ? "" : "s"); + } + + } + else if (this->did) + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, f.name, p.id, p.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN products AS p ON h.product = p.id " + "WHERE h.algo = ? AND f.dir = ? " + "ORDER BY f.name, p.name, h.hash", + DB_INT, this->algo, DB_INT, this->did, + DB_INT, DB_BLOB, DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &file, &pid, &product)) + { + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); + fid_old = fid; + pid_old = 0; + } + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for directory '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->dir); + } + } + else + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, f.name, d.id, d.path, p.id, p.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "JOIN products AS p on h.product = p.id " + "WHERE h.algo = ? " + "ORDER BY d.path, f.name, p.name, h.hash", + DB_INT, this->algo, DB_INT, DB_BLOB, DB_INT, DB_TEXT, + DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir, &pid, + &product)) + { + if (did != did_old) + { + printf("%4d: %s\n", did, dir); + did_old = did; + } + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); + fid_old = fid; + pid_old = 0; + } + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found\n", count, pts_meas_algorithm_names, + this->algo, (count == 1) ? "" : "s"); + } + } +} + +METHOD(attest_db_t, list_measurements, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t hash, keyid; + pts_comp_func_name_t *cfn; + char *owner; + int seq_no, pcr, vid, name, qualifier; + int cid, cid_old = 0, kid, kid_old = 0, count = 0; + + if (this->kid && this->cid) + { + e = this->db->query(this->db, + "SELECT ch.seq_no, ch.pcr, ch.hash, k.owner " + "FROM component_hashes AS ch " + "JOIN keys AS k ON k.id = ch.key " + "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? " + "ORDER BY seq_no", + DB_INT, this->algo, DB_UINT, this->kid, DB_UINT, this->cid, + DB_INT, DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &seq_no, &pcr, &hash, &owner)) + { + if (this->kid != kid_old) + { + printf("%4d: %#B '%s'\n", this->kid, &this->key, owner); + kid_old = this->kid; + } + printf("%7d %02d %#B\n", seq_no, pcr, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for component '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", print_cfn(this->cfn)); + } + } + else if (this->cid) + { + e = this->db->query(this->db, + "SELECT ch.seq_no, ch.pcr, ch.hash, k.id, k.keyid, k.owner " + "FROM component_hashes AS ch " + "JOIN keys AS k ON k.id = ch.key " + "WHERE ch.algo = ? AND ch.component = ? " + "ORDER BY keyid, seq_no", + DB_INT, this->algo, DB_UINT, this->cid, + DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT); + if (e) + { + while (e->enumerate(e, &seq_no, &pcr, &hash, &kid, &keyid, &owner)) + { + if (kid != kid_old) + { + printf("%4d: %#B '%s'\n", kid, &keyid, owner); + kid_old = kid; + } + printf("%7d %02d %#B\n", seq_no, pcr, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for component '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", print_cfn(this->cfn)); + } + + } + else if (this->kid) + { + e = this->db->query(this->db, + "SELECT ch.seq_no, ch.pcr, ch.hash, " + "c.id, c.vendor_id, c.name, c.qualifier " + "FROM component_hashes AS ch " + "JOIN components AS c ON c.id = ch.component " + "WHERE ch.algo = ? AND ch.key = ? " + "ORDER BY vendor_id, name, qualifier, seq_no", + DB_INT, this->algo, DB_UINT, this->kid, DB_INT, DB_INT, DB_BLOB, + DB_INT, DB_INT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &seq_no, &pcr, &hash, &cid, &vid, &name, + &qualifier)) + { + if (cid != cid_old) + { + cfn = pts_comp_func_name_create(vid, name, qualifier); + printf("%4d: %s\n", cid, print_cfn(cfn)); + cfn->destroy(cfn); + cid_old = cid; + } + printf("%5d %02d %#B\n", seq_no, pcr, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for key %#B '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", &this->key, this->owner); + } + } +} + +METHOD(attest_db_t, list_sessions, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t identity; + char *product, *device; + int session_id, conn_id, rec, device_len; + time_t created; + u_int t; + + e = this->db->query(this->db, + "SELECT s.id, s.time, s.connection, s.rec, p.name, d.value, i.value " + "FROM sessions AS s " + "LEFT JOIN products AS p ON s.product = p.id " + "LEFT JOIN devices AS d ON s.device = d.id " + "LEFT JOIN identities AS i ON s.identity = i.id " + "ORDER BY s.time DESC", + DB_INT, DB_UINT, DB_INT, DB_INT, DB_TEXT, DB_TEXT, DB_BLOB); + if (e) + { + while (e->enumerate(e, &session_id, &t, &conn_id, &rec, &product, + &device, &identity)) + { + created = t; + product = product ? product : "-"; + device = strlen(device) ? device : "-"; + device_len = min(strlen(device), DEVICE_MAX_LEN); + identity = identity.len ? identity : chunk_from_str("-"); + printf("%4d: %T %2d %-20s %.*s%*s%.*s - %N\n", session_id, &created, + this->utc, conn_id, product, device_len, device, + DEVICE_MAX_LEN - device_len + 1, " ", (int)identity.len, + identity.ptr, TNC_IMV_Action_Recommendation_names, rec); + } + e->destroy(e); + } +} + +/** + * Insert a file hash into the database + */ +static bool insert_file_hash(private_attest_db_t *this, + pts_meas_algorithms_t algo, + 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"; + + e = this->db->query(this->db, + "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; + } + + while (e->enumerate(e, &hash)) + { + update = TRUE; + + if (chunk_equals(measurement, hash)) + { + label = "exists and equals"; + insert = FALSE; + break; + } + } + 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) + { + printf("file_hash insertion failed\n"); + return FALSE; + } + if (update) + { + label = "updated"; + (*hashes_updated)++; + } + else + { + label = "created"; + (*hashes_added)++; + } + } + printf(" %#B - %s\n", &measurement, label); + return TRUE; +} + +/** + * Add hash measurement for a single file or all files in a directory + */ +static bool add_hash(private_attest_db_t *this) +{ + char *pathname, *filename, *label; + const char *sep; + pts_file_meas_t *measurements; + chunk_t measurement; + hasher_t *hasher = NULL; + int fid, files_added = 0, hashes_added = 0, hashes_updated = 0; + enumerator_t *enumerator, *e; + + if (!this->meas_dir) + { + this->meas_dir = strdup(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->meas_dir, sep, this->file) == -1) + { + return FALSE; + } + measurements = pts_file_meas_create_from_path(0, pathname, FALSE, + TRUE, this->algo); + free(pathname); + } + else + { + measurements = pts_file_meas_create_from_path(0, this->meas_dir, TRUE, + TRUE, this->algo); + } + if (!measurements) + { + printf("file measurement failed\n"); + DESTROY_IF(hasher); + return FALSE; + } + + enumerator = measurements->create_enumerator(measurements); + while (enumerator->enumerate(enumerator, &filename, &measurement)) + { + if (this->fid) + { + /* a single file already exists */ + filename = this->file; + fid = this->fid; + label = "exists"; + } + else + { + /* retrieve or create filename */ + label = "could not be created"; + + e = this->db->query(this->db, + "SELECT id FROM files WHERE name = ? AND dir = ?", + DB_TEXT, filename, DB_INT, this->did, DB_INT); + if (!e) + { + printf("files query failed\n"); + break; + } + if (e->enumerate(e, &fid)) + { + label = "exists"; + } + else + { + if (this->db->execute(this->db, &fid, + "INSERT INTO files (name, dir) VALUES (?, ?)", + DB_TEXT, filename, DB_INT, this->did) == 1) + { + label = "created"; + files_added++; + } + } + e->destroy(e); + } + printf("%4d: %s - %s\n", fid, filename, label); + + /* compute file measurement hash */ + if (!insert_file_hash(this, this->algo, measurement, fid, + &hashes_added, &hashes_updated)) + { + break; + } + } + enumerator->destroy(enumerator); + + 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; +} + +METHOD(attest_db_t, add, bool, + private_attest_db_t *this) +{ + bool success = FALSE; + + /* add directory or file hash measurement for a given product */ + if (this->did && this->pid) + { + return add_hash(this); + } + + /* insert package version */ + if (this->version_set && this->gid && this->pid) + { + time_t t = time(NULL); + int security, blacklist; + + security = this->package_state == OS_PACKAGE_STATE_SECURITY; + blacklist = this->package_state == OS_PACKAGE_STATE_BLACKLIST; + + success = this->db->execute(this->db, NULL, + "INSERT INTO versions " + "(package, product, release, security, blacklist, time) " + "VALUES (?, ?, ?, ?, ?, ?)", + DB_UINT, this->gid, DB_INT, this->pid, DB_TEXT, + this->version, DB_INT, security, DB_INT, blacklist, + DB_INT, t) == 1; + + printf("'%s' package %s (%s)%N %sinserted into database\n", + this->product, this->package, this->version, + os_package_state_names, this->package_state, + success ? "" : "could not be "); + } + return success; +} + +METHOD(attest_db_t, delete, bool, + private_attest_db_t *this) +{ + bool success; + int id, count = 0; + char *name; + enumerator_t *e; + + /* delete a file measurement hash for a given product */ + if (this->algo && this->pid && this->fid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM file_hashes " + "WHERE algo = ? AND product = ? AND file = ?", + DB_UINT, this->algo, DB_UINT, this->pid, + DB_UINT, this->fid) > 0; + + 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 "); + + return success; + } + + /* delete product/file entries */ + if (this->pid && (this->fid || this->did)) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM product_file " + "WHERE product = ? AND file = ?", + DB_UINT, this->pid, + DB_UINT, this->fid ? this->fid : this->did) > 0; + + printf("product/file pair (%d/%d) %sdeleted from database\n", + this->pid, this->fid ? this->fid : this->did, + success ? "" : "could not be "); + + return success; + } + + if (this->cid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM components WHERE id = ?", + DB_UINT, this->cid) > 0; + + printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn), + success ? "" : "could not be "); + return success; + } + + if (this->fid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM files WHERE id = ?", + DB_UINT, this->fid) > 0; + + printf("file '%s%s%s' %sdeleted from database\n", this->dir, + get_separator(this->dir), this->file, + success ? "" : "could not be "); + return success; + } + + if (this->did) + { + e = this->db->query(this->db, + "SELECT id, name FROM files WHERE dir = ? ORDER BY name", + DB_INT, this->did, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &name)) + { + printf("%4d: %s\n", id, name); + count++; + } + e->destroy(e); + + if (count) + { + printf("%d dependent file%s found, " + "directory '%s' could not deleted\n", + count, (count == 1) ? "" : "s", this->dir); + return FALSE; + } + } + success = this->db->execute(this->db, NULL, + "DELETE FROM directories WHERE id = ?", + DB_UINT, this->did) > 0; + printf("directory '%s' %sdeleted from database\n", this->dir, + success ? "" : "could not be "); + return success; + } + + if (this->kid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM keys WHERE id = ?", + DB_UINT, this->kid) > 0; + + printf("key %#B %sdeleted from database\n", &this->key, + success ? "" : "could not be "); + return success; + } + if (this->pid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM products WHERE id = ?", + DB_UINT, this->pid) > 0; + + printf("product '%s' %sdeleted from database\n", this->product, + success ? "" : "could not be "); + return success; + } + + printf("empty delete command\n"); + return FALSE; +} + +METHOD(attest_db_t, destroy, void, + private_attest_db_t *this) +{ + DESTROY_IF(this->db); + DESTROY_IF(this->cfn); + free(this->package); + free(this->product); + free(this->version); + free(this->file); + free(this->dir); + free(this->meas_dir); + free(this->owner); + free(this->key.ptr); + free(this); +} + +/** + * Described in header. + */ +attest_db_t *attest_db_create(char *uri) +{ + private_attest_db_t *this; + + INIT(this, + .public = { + .set_component = _set_component, + .set_cid = _set_cid, + .set_directory = _set_directory, + .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, + .set_gid = _set_gid, + .set_product = _set_product, + .set_pid = _set_pid, + .set_version = _set_version, + .set_algo = _set_algo, + .set_relative = _set_relative, + .set_package_state = _set_package_state, + .set_sequence = _set_sequence, + .set_owner = _set_owner, + .set_utc = _set_utc, + .list_packages = _list_packages, + .list_products = _list_products, + .list_files = _list_files, + .list_directories = _list_directories, + .list_components = _list_components, + .list_devices = _list_devices, + .list_keys = _list_keys, + .list_hashes = _list_hashes, + .list_measurements = _list_measurements, + .list_sessions = _list_sessions, + .add = _add, + .delete = _delete, + .destroy = _destroy, + }, + .db = lib->db->create(lib->db, uri), + ); + + if (!this->db) + { + fprintf(stderr, "opening database failed.\n"); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libimcv/plugins/imv_attestation/attest_db.h b/src/libimcv/plugins/imv_attestation/attest_db.h new file mode 100644 index 000000000..ab3d046b3 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/attest_db.h @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup attest_db_t attest_db + * @{ @ingroup libimcv + */ + +#ifndef ATTEST_DB_H_ +#define ATTEST_DB_H_ + +#include <pts/pts_meas_algo.h> +#include <os_info/os_info.h> +#include <library.h> + +typedef struct attest_db_t attest_db_t; + +/** + * Attestation database object + */ +struct attest_db_t { + + /** + * Set functional component to be queried + * + * @param comp functional component + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_component)(attest_db_t *this, char *comp, bool create); + + /** + * Set primary key of the functional component to be queried + * + * @param fid primary key of functional component + * @return TRUE if successful + */ + bool (*set_cid)(attest_db_t *this, int fid); + + /** + * Set directory to be queried + * + * @param dir directory + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_directory)(attest_db_t *this, char *dir, bool create); + + /** + * Set primary key of the directory to be queried + * + * @param did primary key of directory + * @return TRUE if successful + */ + bool (*set_did)(attest_db_t *this, int did); + + /** + * Set measurement file to be queried + * + * @param file measurement file + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_file)(attest_db_t *this, char *file, bool create); + + /** + * Set primary key of the measurement file to be queried + * + * @param fid primary key of measurement file + * @return TRUE if successful + */ + bool (*set_fid)(attest_db_t *this, int fid); + + /** + * Set path to directory where file[s] are to be measured + * + * @param meas_dir measurement directory + * @return TRUE if successful + */ + bool (*set_meas_directory)(attest_db_t *this, char *dir); + + /** + * Set functional component to be queried + * + * @param key AIK + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_key)(attest_db_t *this, chunk_t key, bool create); + + /** + * Set primary key of the AIK to be queried + * + * @param kid primary key of AIK + * @return TRUE if successful + */ + bool (*set_kid)(attest_db_t *this, int kid); + + /** + * Set software package to be queried + * + * @param product software package + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_package)(attest_db_t *this, char *package, bool create); + + /** + * Set primary key of the software package to be queried + * + * @param gid primary key of software package + * @return TRUE if successful + */ + bool (*set_gid)(attest_db_t *this, int gid); + + /** + * Set software product to be queried + * + * @param product software product + * @param create if TRUE create database entry if it doesn't exist + * @return TRUE if successful + */ + bool (*set_product)(attest_db_t *this, char *product, bool create); + + /** + * Set primary key of the software product to be queried + * + * @param pid primary key of software product + * @return TRUE if successful + */ + bool (*set_pid)(attest_db_t *this, int pid); + + /** + * Set software package version to be queried + * + * @param version software package version + * @return TRUE if successful + */ + bool (*set_version)(attest_db_t *this, char *version); + + /** + * Set measurement hash algorithm + * + * @param algo hash algorithm + */ + void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo); + + /** + * Set that the IMA-specific SHA-1 template hash be computed + */ + void (*set_ima)(attest_db_t *this); + + /** + * Set that relative filenames are to be used + */ + void (*set_relative)(attest_db_t *this); + + /** + * Set the package security or blacklist state + */ + void (*set_package_state)(attest_db_t *this, os_package_state_t package_state); + + /** + * Set the sequence number + */ + void (*set_sequence)(attest_db_t *this, int seq_no); + + /** + * Set owner [user/host] of an AIK + * + * @param owner user/host name + * @return TRUE if successful + */ + void (*set_owner)(attest_db_t *this, char *owner); + + /** + * Display all dates in UTC + */ + void (*set_utc)(attest_db_t *this); + + /** + * List all packages stored in the database + */ + void (*list_packages)(attest_db_t *this); + + /** + * List all products stored in the database + */ + void (*list_products)(attest_db_t *this); + + /** + * List all directories stored in the database + */ + void (*list_directories)(attest_db_t *this); + + /** + * List selected files stored in the database + */ + void (*list_files)(attest_db_t *this); + + /** + * List all components stored in the database + */ + void (*list_components)(attest_db_t *this); + + /** + * List all devices stored in the database + */ + void (*list_devices)(attest_db_t *this); + + /** + * List all AIKs stored in the database + */ + void (*list_keys)(attest_db_t *this); + + /** + * List selected measurement hashes stored in the database + */ + void (*list_hashes)(attest_db_t *this); + + /** + * List selected component measurement stored in the database + */ + void (*list_measurements)(attest_db_t *this); + + /** + * List sessions stored in the database + */ + void (*list_sessions)(attest_db_t *this); + + /** + * Add an entry to the database + */ + bool (*add)(attest_db_t *this); + + /** + * Delete an entry from the database + */ + bool (*delete)(attest_db_t *this); + + /** + * Destroy attest_db_t object + */ + void (*destroy)(attest_db_t *this); + +}; + +/** + * Create an attest_db_t instance + * + * @param uri database URI + */ +attest_db_t* attest_db_create(char *uri); + +#endif /** ATTEST_DB_H_ @}*/ diff --git a/src/libimcv/plugins/imv_attestation/attest_usage.c b/src/libimcv/plugins/imv_attestation/attest_usage.c new file mode 100644 index 000000000..8f4afdbad --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/attest_usage.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdio.h> + +#include "attest_usage.h" + +/** + * print attest usage info + */ +void usage(void) +{ + printf("\ +Usage:\n\ + ipsec attest --components|--devices|--sessions|--files|--hashes|--keys [options]\n\ + \n\ + ipsec attest --measurements|--packages|--products|--add|--del [options]\n\ + \n\ + ipsec attest --components [--key <digest>|--kid <id>]\n\ + Show a list of components with an AIK digest or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --devices [--utc]\n\ + Show a list of registered devices and associated collected information\n\ + \n\ + ipsec attest --sessions [--utc]\n\ + Show a chronologically sorted list of all TNC sessions\n\ + \n\ + ipsec attest --files [--product <name>|--pid <id>]\n\ + Show a list of files with a software product name or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --hashes [--sha1|--sha256|--sha384] [--product <name>|--pid <id>]\n\ + Show a list of measurement hashes for a given software product or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --hashes [--sha1|--sha1-ima|--sha256|--sha384] [--file <path>|--fid <id>]\n\ + Show a list of measurement hashes for a given file or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --keys [--components <cfn>|--cid <id>]\n\ + Show a list of AIK key digests with a component or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --measurements --sha1|--sha256|--sha384 [--component <cfn>|--cid <id>]\n\ + Show a list of component measurements for a given component or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --measurements --sha1|--sha256|--sha384 [--key <digest>|--kid <id>|--aik <path>]\n\ + Show a list of component measurements for a given AIK or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --packages [--product <name>|--pid <id>] [--utc]\n\ + Show a list of software packages for a given product or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --products [--file <path>|--fid <id>]\n\ + Show a list of supported software products with a file path or\n\ + its primary key as an optional selector.\n\ + \n\ + ipsec attest --add --file <path>|--dir <path>|--product <name>|--component <cfn>\n\ + Add a file, directory, product or component entry\n\ + Component <cfn> entries must be of the form <vendor_id>/<name>-<qualifier>\n\ + \n\ + ipsec attest --add [--owner <name>] --key <digest>|--aik <path>\n\ + Add an AIK public key digest entry preceded by an optional owner name\n\ + \n\ + ipsec attest --add --product <name>|--pid <id> --sha1|--sha1-ima|--sha256|--sha384\n\ + [--relative|--rel] --dir <path>|--file <path>\n\ + Add hashes of a single file or all files in a directory under absolute or relative filenames\n\ + \n\ + ipsec attest --add --key <digest|--kid <id> --component <cfn>|--cid <id> --sequence <no>|--seq <no>\n\ + Add an ordered key/component entry\n\ + \n\ + ipsec attest --add --package <name> --version <string> [--security|--blacklist]\n\ + [--product <name>|--pid <id>]\n\ + Add a package version for a given product optionally with security or blacklist flag\n\ + \n\ + ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>\n\ + Delete a file or directory entry referenced either by value or primary key\n\ + \n\ + ipsec attest --del --product <name>|--pid <id>|--component <cfn>|--cid <id>\n\ + Delete a product or component entry referenced either by value or primary key\n\ + \n\ + ipsec attest --del --product <name>|--pid <id> --file <path>|--fid <id>|--dir <path>|--did <id>\n\ + Delete a product/file entry referenced either by value or primary key\n\ + \n\ + ipsec attest --del --key <digest>|--kid <id>|--aik <path>\n\ + Delete an AIK entry referenced either by value or primary key\n\ + \n\ + ipsec attest --del --key <digest|--kid <id> --component <cfn>|--cid <id>\n\ + Delete a key/component entry\n\ + \n\ + ipsec attest --del --product <name>|--pid <id> --sha1|--sha1-ima|--sha256|--sha384\n\ + [--dir <path>|--did <id>] --file <path>|--fid <id>\n\ + Delete a file hash given an absolute or relative filename\n\ + \n"); +} + diff --git a/src/libimcv/plugins/imv_attestation/attest_usage.h b/src/libimcv/plugins/imv_attestation/attest_usage.h new file mode 100644 index 000000000..bce801e9d --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/attest_usage.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2011 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef ATTEST_USAGE_H_ +#define ATTEST_USAGE_H_ + +/** + * print attest usage info + */ +void usage(void); + + +#endif /* ATTEST_USAGE_H_ */ diff --git a/src/libimcv/plugins/imv_attestation/build-database.sh b/src/libimcv/plugins/imv_attestation/build-database.sh new file mode 100755 index 000000000..ca2939b49 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/build-database.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +p="Ubuntu 14.04 x86_64" +a="x86_64-linux-gnu" +k="3.13.0-37-generic" + +for hash in sha1 sha256 +do + ipsec attest --add --product "$p" --$hash --dir /sbin + ipsec attest --add --product "$p" --$hash --dir /usr/sbin + ipsec attest --add --product "$p" --$hash --dir /bin + ipsec attest --add --product "$p" --$hash --dir /usr/bin + + ipsec attest --add --product "$p" --$hash --file /etc/init.d/rc + ipsec attest --add --product "$p" --$hash --file /etc/init.d/rcS + ipsec attest --add --product "$p" --$hash --dir /etc/network/if-pre-up.d + ipsec attest --add --product "$p" --$hash --dir /etc/network/if-up.d + ipsec attest --add --product "$p" --$hash --dir /etc/ppp/ip-down.d + ipsec attest --add --product "$p" --$hash --dir /etc/rcS.d + ipsec attest --add --product "$p" --$hash --dir /etc/rc2.d + ipsec attest --add --product "$p" --$hash --file /etc/rc.local + ipsec attest --add --product "$p" --$hash --dir /etc/resolvconf/update.d + ipsec attest --add --product "$p" --$hash --file /etc/resolvconf/update-libc.d/avahi-daemon + ipsec attest --add --product "$p" --$hash --dir /etc/update-motd.d + + ipsec attest --add --product "$p" --$hash --dir /lib + ipsec attest --add --product "$p" --$hash --file /lib/crda/setregdomain + ipsec attest --add --product "$p" --$hash --dir /lib/ebtables + ipsec attest --add --product "$p" --$hash --file /lib/init/apparmor-profile-load + ipsec attest --add --product "$p" --$hash --file /lib/resolvconf/list-records + ipsec attest --add --product "$p" --$hash --dir /lib/ufw + ipsec attest --add --product "$p" --$hash --dir /lib/udev + ipsec attest --add --product "$p" --$hash --dir /lib/systemd + ipsec attest --add --product "$p" --$hash --dir /lib/xtables + ipsec attest --add --product "$p" --$hash --dir /lib/$a + ipsec attest --add --product "$p" --$hash --dir /lib/$a/plymouth + ipsec attest --add --product "$p" --$hash --dir /lib/$a/plymouth/renderers + ipsec attest --add --product "$p" --$hash --dir /lib/$a/security + + ipsec attest --add --product "$p" --$hash --file /lib64/ld-linux-x86-64.so.2 + + for file in `find /usr/lib -name *.so` + do + ipsec attest --add --product "$p" --$hash --file $file + done + + for file in `find /usr/lib -name *service` + do + ipsec attest --add --product "$p" --$hash --file $file + done + + ipsec attest --add --product "$p" --$hash --dir /usr/lib + ipsec attest --add --product "$p" --$hash --dir /usr/lib/accountsservice + ipsec attest --add --product "$p" --$hash --dir /usr/lib/at-spi2-core + ipsec attest --add --product "$p" --$hash --file /usr/lib/avahi/avahi-daemon-check-dns.sh + ipsec attest --add --product "$p" --$hash --file /usr/lib/dbus-1.0/dbus-daemon-launch-helper + ipsec attest --add --product "$p" --$hash --dir /usr/lib/gvfs + ipsec attest --add --product "$p" --$hash --file /usr/lib/firefox/firefox + ipsec attest --add --product "$p" --$hash --dir /usr/lib/NetworkManager + ipsec attest --add --product "$p" --$hash --dir /usr/lib/pm-utils/power.d + ipsec attest --add --product "$p" --$hash --file /usr/lib/policykit-1/polkitd + ipsec attest --add --product "$p" --$hash --file /usr/lib/thunderbird/thunderbird + ipsec attest --add --product "$p" --$hash --dir /usr/lib/ubuntu-release-upgrader + ipsec attest --add --product "$p" --$hash --dir /usr/lib/update-notifier + + ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a + ipsec attest --add --product "$p" --$hash --file /usr/lib/$a/mesa/libGL.so.1.2.0 + ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a/samba + ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a/sasl2 + + ipsec attest --add --product "$p" --$hash --dir /usr/share/language-tools + + ipsec attest --add --product "$p" --$hash --file /init \ + --measdir /usr/share/initramfs-tools + + ipsec attest --add --product "$p" --$hash --file /scripts/functions \ + --measdir /usr/share/initramfs-tools/scripts + + for file in `find /lib/modules/$k -name *.ko` + do + ipsec attest --add --product "$p" --$hash --file $file + done +done + diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation.c b/src/libimcv/plugins/imv_attestation/imv_attestation.c new file mode 100644 index 000000000..542a561aa --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imv_attestation_agent.h" + +static const char imv_name[] = "Attestation"; +static const imv_agent_create_t imv_agent_create = imv_attestation_agent_create; + +/* include generic TGC TNC IF-IMV API code below */ + +#include <imv/imv_if.h> + diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c new file mode 100644 index 000000000..8e3736857 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c @@ -0,0 +1,931 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE /* for stdndup() */ +#include <string.h> + +#include "imv_attestation_agent.h" +#include "imv_attestation_state.h" +#include "imv_attestation_process.h" +#include "imv_attestation_build.h" + +#include <imcv.h> +#include <imv/imv_agent.h> +#include <imv/imv_msg.h> +#include <imv/imv_session.h> +#include <imv/imv_os_info.h> +#include <ietf/ietf_attr.h> +#include <ietf/ietf_attr_attr_request.h> +#include <ietf/ietf_attr_pa_tnc_error.h> +#include <ietf/ietf_attr_product_info.h> +#include <ietf/ietf_attr_string_version.h> +#include <ita/ita_attr.h> +#include <ita/ita_attr_device_id.h> +#include <tcg/tcg_attr.h> +#include <tcg/pts/tcg_pts_attr_meas_algo.h> +#include <tcg/pts/tcg_pts_attr_proto_caps.h> +#include <tcg/pts/tcg_pts_attr_req_file_meas.h> +#include <tcg/pts/tcg_pts_attr_req_file_meta.h> +#include "tcg/seg/tcg_seg_attr_max_size.h" +#include "tcg/seg/tcg_seg_attr_seg_env.h" +#include <pts/pts.h> +#include <pts/pts_database.h> +#include <pts/pts_creds.h> +#include <pts/components/ita/ita_comp_func_name.h> + +#include <tncif_pa_subtypes.h> + +#include <pen/pen.h> +#include <utils/debug.h> +#include <credentials/credential_manager.h> +#include <collections/linked_list.h> + +#define FILE_MEAS_MAX_ATTR_SIZE 100000000 + +typedef struct private_imv_attestation_agent_t private_imv_attestation_agent_t; + +/* Subscribed PA-TNC message subtypes */ +static pen_type_t msg_types[] = { + { PEN_TCG, PA_SUBTYPE_TCG_PTS }, + { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM } +}; + +/** + * Private data of an imv_attestation_agent_t object. + */ +struct private_imv_attestation_agent_t { + + /** + * Public members of imv_attestation_agent_t + */ + imv_agent_if_t public; + + /** + * IMV agent responsible for generic functions + */ + imv_agent_t *agent; + + /** + * Supported PTS measurement algorithms + */ + pts_meas_algorithms_t supported_algorithms; + + /** + * Supported PTS Diffie Hellman Groups + */ + pts_dh_group_t supported_dh_groups; + + /** + * PTS file measurement database + */ + pts_database_t *pts_db; + + /** + * PTS credentials + */ + pts_creds_t *pts_creds; + + /** + * PTS credential manager + */ + credential_manager_t *pts_credmgr; + +}; + +METHOD(imv_agent_if_t, bind_functions, TNC_Result, + private_imv_attestation_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function) +{ + return this->agent->bind_functions(this->agent, bind_function); +} + +METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id, + TNC_ConnectionState new_state) +{ + TNC_IMV_Action_Recommendation rec; + imv_state_t *state; + imv_session_t *session; + + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imv_attestation_state_create(id); + return this->agent->create_state(this->agent, state); + case TNC_CONNECTION_STATE_DELETE: + return this->agent->delete_state(this->agent, id); + case TNC_CONNECTION_STATE_ACCESS_ALLOWED: + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + case TNC_CONNECTION_STATE_ACCESS_NONE: + if (this->agent->get_state(this->agent, id, &state) && imcv_db) + { + session = state->get_session(state); + + if (session->get_policy_started(session)) + { + switch (new_state) + { + case TNC_CONNECTION_STATE_ACCESS_ALLOWED: + rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW; + break; + case TNC_CONNECTION_STATE_ACCESS_ISOLATED: + rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE; + break; + case TNC_CONNECTION_STATE_ACCESS_NONE: + default: + rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS; + } + imcv_db->add_recommendation(imcv_db, session, rec); + if (!imcv_db->policy_script(imcv_db, session, FALSE)) + { + DBG1(DBG_IMV, "error in policy script stop"); + } + } + } + /* fall through to default state */ + default: + return this->agent->change_state(this->agent, id, new_state, NULL); + } +} + +/** + * Process a received message + */ +static TNC_Result receive_msg(private_imv_attestation_agent_t *this, + imv_state_t *state, imv_msg_t *in_msg) +{ + imv_msg_t *out_msg; + imv_session_t *session; + imv_os_info_t *os_info; + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + pen_type_t type; + TNC_Result result; + chunk_t os_name, os_version; + bool fatal_error = FALSE; + + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imv_msg_create_as_reply(in_msg); + out_msg->set_msg_type(out_msg, msg_types[0]); + + /* parse received PA-TNC message and handle local and remote errors */ + result = in_msg->receive(in_msg, out_msg, &fatal_error); + if (result != TNC_RESULT_SUCCESS) + { + out_msg->destroy(out_msg); + return result; + } + + session = state->get_session(state); + os_info = session->get_os_info(session); + + /* analyze PA-TNC attributes */ + enumerator = in_msg->create_attribute_enumerator(in_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF) + { + switch (type.type) + { + case IETF_ATTR_PA_TNC_ERROR: + { + ietf_attr_pa_tnc_error_t *error_attr; + pen_type_t error_code; + chunk_t msg_info; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; + error_code = error_attr->get_error_code(error_attr); + + if (error_code.vendor_id == PEN_TCG) + { + msg_info = error_attr->get_msg_info(error_attr); + + DBG1(DBG_IMV, "received TCG-PTS error '%N'", + pts_error_code_names, error_code.type); + DBG1(DBG_IMV, "error information: %B", &msg_info); + fatal_error = TRUE; + } + break; + } + case IETF_ATTR_PRODUCT_INFORMATION: + { + ietf_attr_product_info_t *attr_cast; + pen_t vendor_id; + + state->set_action_flags(state, + IMV_ATTESTATION_ATTR_PRODUCT_INFO); + attr_cast = (ietf_attr_product_info_t*)attr; + os_name = attr_cast->get_info(attr_cast, &vendor_id, NULL); + os_info->set_name(os_info, os_name); + + if (vendor_id != PEN_IETF) + { + DBG1(DBG_IMV, "operating system name is '%.*s' " + "from vendor %N", os_name.len, os_name.ptr, + pen_names, vendor_id); + } + else + { + DBG1(DBG_IMV, "operating system name is '%.*s'", + os_name.len, os_name.ptr); + } + break; + + break; + } + case IETF_ATTR_STRING_VERSION: + { + ietf_attr_string_version_t *attr_cast; + + state->set_action_flags(state, + IMV_ATTESTATION_ATTR_STRING_VERSION); + attr_cast = (ietf_attr_string_version_t*)attr; + os_version = attr_cast->get_version(attr_cast, NULL, NULL); + os_info->set_version(os_info, os_version); + + if (os_version.len) + { + DBG1(DBG_IMV, "operating system version is '%.*s'", + os_version.len, os_version.ptr); + } + break; + } + default: + break; + } + } + else if (type.vendor_id == PEN_ITA) + { + switch (type.type) + { + case ITA_ATTR_DEVICE_ID: + { + chunk_t value; + + state->set_action_flags(state, + IMV_ATTESTATION_ATTR_DEVICE_ID); + + value = attr->get_value(attr); + DBG1(DBG_IMV, "device ID is %.*s", value.len, value.ptr); + session->set_device_id(session, value); + break; + } + default: + break; + } + } + else if (type.vendor_id == PEN_TCG) + { + if (!imv_attestation_process(attr, out_msg, state, + this->supported_algorithms, this->supported_dh_groups, + this->pts_db, this->pts_credmgr)) + { + result = TNC_RESULT_FATAL; + break; + } + } + } + enumerator->destroy(enumerator); + + if (fatal_error || result != TNC_RESULT_SUCCESS) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + result = out_msg->send_assessment(out_msg); + if (result == TNC_RESULT_SUCCESS) + { + result = this->agent->provide_recommendation(this->agent, state); + } + } + else + { + /* send PA-TNC message with the EXCL flag set */ + result = out_msg->send(out_msg, TRUE); + } + out_msg->destroy(out_msg); + + return result; +} + +METHOD(imv_agent_if_t, receive_message, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id, + TNC_MessageType msg_type, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +METHOD(imv_agent_if_t, receive_message_long, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, + TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_long_data(this->agent, state, id, + src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +/** + * Build an IETF Attribute Request attribute for missing attributes + */ +static pa_tnc_attr_t* build_attr_request(uint32_t received) +{ + pa_tnc_attr_t *attr; + ietf_attr_attr_request_t *attr_cast; + + attr = ietf_attr_attr_request_create(PEN_RESERVED, 0); + attr_cast = (ietf_attr_attr_request_t*)attr; + + if (!(received & IMV_ATTESTATION_ATTR_PRODUCT_INFO) || + !(received & IMV_ATTESTATION_ATTR_STRING_VERSION)) + { + attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION); + attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION); + } + if (!(received & IMV_ATTESTATION_ATTR_DEVICE_ID)) + { + attr_cast->add(attr_cast, PEN_ITA, ITA_ATTR_DEVICE_ID); + } + + return attr; +} + +METHOD(imv_agent_if_t, batch_ending, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id) +{ + imv_msg_t *out_msg; + imv_state_t *state; + imv_session_t *session; + imv_attestation_state_t *attestation_state; + imv_attestation_handshake_state_t handshake_state; + imv_workitem_t *workitem; + TNC_IMV_Action_Recommendation rec; + TNC_IMV_Evaluation_Result eval; + TNC_IMVID imv_id; + TNC_Result result = TNC_RESULT_SUCCESS; + pts_t *pts; + int pid; + uint32_t actions; + enumerator_t *enumerator; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imv_attestation_state_t*)state; + pts = attestation_state->get_pts(attestation_state); + handshake_state = attestation_state->get_handshake_state(attestation_state); + actions = state->get_action_flags(state); + session = state->get_session(state); + imv_id = this->agent->get_id(this->agent); + + /* exit if a recommendation has already been provided */ + if (actions & IMV_ATTESTATION_REC) + { + return TNC_RESULT_SUCCESS; + } + + /* send an IETF attribute request if no platform info was received */ + if (!(actions & IMV_ATTESTATION_ATTR_REQ)) + { + if ((actions & IMV_ATTESTATION_ATTR_MUST) != IMV_ATTESTATION_ATTR_MUST) + { + imv_msg_t *os_msg; + + /* create attribute request for missing mandatory attributes */ + os_msg = imv_msg_create(this->agent, state, id, imv_id, + TNC_IMCID_ANY, msg_types[1]); + os_msg->add_attribute(os_msg, build_attr_request(actions)); + result = os_msg->send(os_msg, FALSE); + os_msg->destroy(os_msg); + + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + } + state->set_action_flags(state, IMV_ATTESTATION_ATTR_REQ); + } + + if (!session->get_policy_started(session) && + (actions & IMV_ATTESTATION_ATTR_PRODUCT_INFO) && + (actions & IMV_ATTESTATION_ATTR_STRING_VERSION) && + (actions & IMV_ATTESTATION_ATTR_DEVICE_ID)) + { + if (imcv_db) + { + /* start the policy script */ + if (!imcv_db->policy_script(imcv_db, session, TRUE)) + { + DBG1(DBG_IMV, "error in policy script start"); + } + } + else + { + DBG2(DBG_IMV, "no workitems available - no evaluation possible"); + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + session->set_policy_started(session, TRUE); + } + } + + if (handshake_state == IMV_ATTESTATION_STATE_INIT) + { + size_t max_attr_size = FILE_MEAS_MAX_ATTR_SIZE; + size_t max_seg_size; + seg_contract_t *contract; + seg_contract_manager_t *contracts; + pa_tnc_attr_t *attr; + pts_proto_caps_flag_t flags; + char buf[BUF_LEN]; + + out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY, + msg_types[0]); + + /* Determine maximum PA-TNC attribute segment size */ + max_seg_size = state->get_max_msg_len(state) + - PA_TNC_HEADER_SIZE + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_SEG_ENV_HEADER + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_MAX_SIZE_SIZE; + + /* Announce support of PA-TNC segmentation to IMC */ + contract = seg_contract_create(msg_types[0], max_attr_size, + max_seg_size, TRUE, imv_id, FALSE); + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMV, "%s", buf); + contracts = state->get_contracts(state); + contracts->add_contract(contracts, contract); + attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE); + out_msg->add_attribute(out_msg, attr); + + /* Send Request Protocol Capabilities attribute */ + flags = pts->get_proto_caps(pts); + attr = tcg_pts_attr_proto_caps_create(flags, TRUE); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + + /* Send Measurement Algorithms attribute */ + attr = tcg_pts_attr_meas_algo_create(this->supported_algorithms, FALSE); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_DISCOVERY); + + /* send these initial PTS attributes and exit */ + result = out_msg->send(out_msg, FALSE); + out_msg->destroy(out_msg); + + return result; + } + + /* exit if we are not ready yet for PTS measurements */ + if (!(actions & IMV_ATTESTATION_ALGO)) + { + return TNC_RESULT_SUCCESS; + } + + session->get_session_id(session, &pid, NULL); + pts->set_platform_id(pts, pid); + + /* create an empty out message - we might need it */ + out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY, + msg_types[0]); + + /* establish the PTS measurements to be taken */ + if (!(actions & IMV_ATTESTATION_FILE_MEAS)) + { + bool is_dir, no_workitems = TRUE; + uint32_t delimiter = SOLIDUS_UTF; + uint16_t request_id; + pa_tnc_attr_t *attr; + char *pathname; + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_END); + + enumerator = session->create_workitem_enumerator(session); + if (enumerator) + { + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY) + { + continue; + } + + switch (workitem->get_type(workitem)) + { + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_FILE_META: + is_dir = FALSE; + break; + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + case IMV_WORKITEM_DIR_META: + is_dir = TRUE; + break; + case IMV_WORKITEM_TPM_ATTEST: + { + pts_component_t *comp; + pts_comp_func_name_t *comp_name; + bool no_d_flag, no_t_flag; + char result_str[BUF_LEN]; + + workitem->set_imv_id(workitem, imv_id); + no_workitems = FALSE; + no_d_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D); + no_t_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T); + if (no_d_flag || no_t_flag) + { + snprintf(result_str, BUF_LEN, "%s%s%s", + (no_t_flag) ? "no TPM available" : "", + (no_t_flag && no_d_flag) ? ", " : "", + (no_d_flag) ? "no DH nonce negotiation" : ""); + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + session->remove_workitem(session, enumerator); + rec = workitem->set_result(workitem, result_str, eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, workitem); + workitem->destroy(workitem); + continue; + } + + /* do TPM BIOS measurements */ + if (strchr(workitem->get_arg_str(workitem), 'B')) + { + comp_name = pts_comp_func_name_create(PEN_ITA, + PTS_ITA_COMP_FUNC_NAME_IMA, + PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED); + comp = attestation_state->create_component( + attestation_state, comp_name, + 0, this->pts_db); + if (!comp) + { + comp_name->log(comp_name, "unregistered "); + comp_name->destroy(comp_name); + } + } + + /* do TPM IMA measurements */ + if (strchr(workitem->get_arg_str(workitem), 'I')) + { + comp_name = pts_comp_func_name_create(PEN_ITA, + PTS_ITA_COMP_FUNC_NAME_IMA, + PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_OS); + comp = attestation_state->create_component( + attestation_state, comp_name, + 0, this->pts_db); + if (!comp) + { + comp_name->log(comp_name, "unregistered "); + comp_name->destroy(comp_name); + } + } + + /* do TPM TRUSTED BOOT measurements */ + if (strchr(workitem->get_arg_str(workitem), 'T')) + { + comp_name = pts_comp_func_name_create(PEN_ITA, + PTS_ITA_COMP_FUNC_NAME_TBOOT, + PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED); + comp = attestation_state->create_component( + attestation_state, comp_name, + 0, this->pts_db); + if (!comp) + { + comp_name->log(comp_name, "unregistered "); + comp_name->destroy(comp_name); + } + } + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_NONCE_REQ); + continue; + } + default: + continue; + } + + /* initiate file and directory measurements */ + pathname = this->pts_db->get_pathname(this->pts_db, is_dir, + workitem->get_arg_int(workitem)); + if (!pathname) + { + continue; + } + workitem->set_imv_id(workitem, imv_id); + no_workitems = FALSE; + + if (workitem->get_type(workitem) == IMV_WORKITEM_FILE_META) + { + TNC_IMV_Action_Recommendation rec; + TNC_IMV_Evaluation_Result eval; + char result_str[BUF_LEN]; + + DBG2(DBG_IMV, "IMV %d requests metadata for %s '%s'", + imv_id, is_dir ? "directory" : "file", pathname); + + /* currently just fire and forget metadata requests */ + attr = tcg_pts_attr_req_file_meta_create(is_dir, + delimiter, pathname); + snprintf(result_str, BUF_LEN, "%s metadata requested", + is_dir ? "directory" : "file"); + eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; + session->remove_workitem(session, enumerator); + rec = workitem->set_result(workitem, result_str, eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, workitem); + workitem->destroy(workitem); + } + else + { + /* use lower 16 bits of the workitem ID as request ID */ + request_id = workitem->get_id(workitem) & 0xffff; + + DBG2(DBG_IMV, "IMV %d requests measurement %d for %s '%s'", + imv_id, request_id, is_dir ? "directory" : "file", + pathname); + attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id, + delimiter, pathname); + } + free(pathname); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + } + enumerator->destroy(enumerator); + + /* sent all file and directory measurement and metadata requests */ + state->set_action_flags(state, IMV_ATTESTATION_FILE_MEAS); + + if (no_workitems) + { + DBG2(DBG_IMV, "IMV %d has no workitems - " + "no evaluation requested", imv_id); + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + } + } + } + + /* check the IMV state for the next PA-TNC attributes to send */ + enumerator = session->create_workitem_enumerator(session); + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST) + { + if (!imv_attestation_build(out_msg, state, + this->supported_dh_groups, this->pts_db)) + { + imv_reason_string_t *reason_string; + chunk_t result; + char *result_str; + + reason_string = imv_reason_string_create("en", ", "); + attestation_state->add_comp_evid_reasons(attestation_state, + reason_string); + result = reason_string->get_encoding(reason_string); + result_str = strndup(result.ptr, result.len); + reason_string->destroy(reason_string); + + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + session->remove_workitem(session, enumerator); + rec = workitem->set_result(workitem, result_str, eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, workitem); + } + break; + } + } + enumerator->destroy(enumerator); + + /* finalized all workitems? */ + if (session->get_policy_started(session) && + session->get_workitem_count(session, imv_id) == 0 && + attestation_state->get_handshake_state(attestation_state) == + IMV_ATTESTATION_STATE_END) + { + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + state->set_action_flags(state, IMV_ATTESTATION_REC); + + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + /* send non-empty PA-TNC message with excl flag not set */ + if (out_msg->get_attribute_count(out_msg)) + { + result = out_msg->send(out_msg, FALSE); + } + out_msg->destroy(out_msg); + + return result; +} + +METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, + private_imv_attestation_agent_t *this, TNC_ConnectionID id) +{ + TNC_IMVID imv_id; + imv_state_t *state; + imv_attestation_state_t *attestation_state; + imv_session_t *session; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imv_attestation_state_t*)state; + session = state->get_session(state); + imv_id = this->agent->get_id(this->agent); + + if (imcv_db) + { + TNC_IMV_Evaluation_Result eval; + TNC_IMV_Action_Recommendation rec; + imv_workitem_t *workitem; + enumerator_t *enumerator; + int pending_file_meas = 0; + char *result_str; + chunk_t result_buf; + bio_writer_t *result; + + enumerator = session->create_workitem_enumerator(session); + if (enumerator) + { + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_imv_id(workitem) != imv_id) + { + continue; + } + result = bio_writer_create(128); + + switch (workitem->get_type(workitem)) + { + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + result_str = "pending file measurements"; + pending_file_meas++; + break; + case IMV_WORKITEM_TPM_ATTEST: + attestation_state->finalize_components(attestation_state, + result); + result->write_data(result, + chunk_from_str("; pending component evidence")); + result->write_uint8(result, '\0'); + result_buf = result->get_buf(result); + result_str = result_buf.ptr; + break; + default: + result->destroy(result); + continue; + } + session->remove_workitem(session, enumerator); + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + rec = workitem->set_result(workitem, result_str, eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, workitem); + workitem->destroy(workitem); + result->destroy(result); + } + enumerator->destroy(enumerator); + + if (pending_file_meas) + { + DBG1(DBG_IMV, "failure due to %d pending file measurements", + pending_file_meas); + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_FILE_MEAS_PEND); + } + } + } + return this->agent->provide_recommendation(this->agent, state); +} + +METHOD(imv_agent_if_t, destroy, void, + private_imv_attestation_agent_t *this) +{ + if (this->pts_creds) + { + this->pts_credmgr->remove_set(this->pts_credmgr, + this->pts_creds->get_set(this->pts_creds)); + this->pts_creds->destroy(this->pts_creds); + } + DESTROY_IF(this->pts_db); + DESTROY_IF(this->pts_credmgr); + DESTROY_IF(this->agent); + free(this); +} + +/** + * Described in header. + */ +imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id, + TNC_Version *actual_version) +{ + private_imv_attestation_agent_t *this; + imv_agent_t *agent; + char *hash_alg, *dh_group, *cadir; + bool mandatory_dh_groups; + + agent = imv_agent_create(name, msg_types, countof(msg_types), id, + actual_version); + if (!agent) + { + return NULL; + } + + hash_alg = lib->settings->get_str(lib->settings, + "%s.plugins.imv-attestation.hash_algorithm", "sha256", lib->ns); + dh_group = lib->settings->get_str(lib->settings, + "%s.plugins.imv-attestation.dh_group", "ecp256", lib->ns); + mandatory_dh_groups = lib->settings->get_bool(lib->settings, + "%s.plugins.imv-attestation.mandatory_dh_groups", TRUE, lib->ns); + cadir = lib->settings->get_str(lib->settings, + "%s.plugins.imv-attestation.cadir", NULL, lib->ns); + + INIT(this, + .public = { + .bind_functions = _bind_functions, + .notify_connection_change = _notify_connection_change, + .receive_message = _receive_message, + .receive_message_long = _receive_message_long, + .batch_ending = _batch_ending, + .solicit_recommendation = _solicit_recommendation, + .destroy = _destroy, + }, + .agent = agent, + .supported_algorithms = PTS_MEAS_ALGO_NONE, + .supported_dh_groups = PTS_DH_GROUP_NONE, + .pts_credmgr = credential_manager_create(), + .pts_creds = pts_creds_create(cadir), + .pts_db = pts_database_create(imcv_db), + ); + + if (!pts_meas_algo_probe(&this->supported_algorithms) || + !pts_dh_group_probe(&this->supported_dh_groups, mandatory_dh_groups) || + !pts_meas_algo_update(hash_alg, &this->supported_algorithms) || + !pts_dh_group_update(dh_group, &this->supported_dh_groups)) + { + destroy(this); + return NULL; + } + + if (this->pts_creds) + { + this->pts_credmgr->add_set(this->pts_credmgr, + this->pts_creds->get_set(this->pts_creds)); + } + + return &this->public; +} diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.h b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.h new file mode 100644 index 000000000..cc421a29a --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imv_attestation_agent_t imv_attestation_agent + * @{ @ingroup imv_attestation + */ + +#ifndef IMV_ATTESTATION_AGENT_H_ +#define IMV_ATTESTATION_AGENT_H_ + +#include <imv/imv_agent_if.h> + +/** + * Creates a Attestation IMV agent + * + * @param name Name of the IMV + * @param id ID of the IMV + * @param actual_version TNC IF-IMV version + */ +imv_agent_if_t* imv_attestation_agent_create(const char* name, TNC_IMVID id, + TNC_Version *actual_version); + +#endif /** IMV_ATTESTATION_AGENT_H_ @}*/ diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_build.c b/src/libimcv/plugins/imv_attestation/imv_attestation_build.c new file mode 100644 index 000000000..c39fe8d47 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_build.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imv_attestation_build.h" +#include "imv_attestation_state.h" + +#include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h> +#include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h> +#include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h> +#include <tcg/pts/tcg_pts_attr_get_aik.h> +#include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h> +#include <tcg/pts/tcg_pts_attr_gen_attest_evid.h> + +#include <utils/debug.h> + +bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db) +{ + imv_attestation_state_t *attestation_state; + imv_attestation_handshake_state_t handshake_state; + pts_t *pts; + pa_tnc_attr_t *attr = NULL; + + attestation_state = (imv_attestation_state_t*)state; + handshake_state = attestation_state->get_handshake_state(attestation_state); + pts = attestation_state->get_pts(attestation_state); + + switch (handshake_state) + { + case IMV_ATTESTATION_STATE_NONCE_REQ: + { + int min_nonce_len; + + /* Send DH nonce parameters request attribute */ + min_nonce_len = lib->settings->get_int(lib->settings, + "%s.plugins.imv-attestation.min_nonce_len", 0, lib->ns); + attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len, + supported_dh_groups); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_TPM_INIT); + break; + } + case IMV_ATTESTATION_STATE_TPM_INIT: + { + pts_meas_algorithms_t selected_algorithm; + chunk_t initiator_value, initiator_nonce; + + if (!(state->get_action_flags(state) & IMV_ATTESTATION_DH_NONCE)) + { + break; + } + + /* Send DH nonce finish attribute */ + selected_algorithm = pts->get_meas_algorithm(pts); + pts->get_my_public_value(pts, &initiator_value, &initiator_nonce); + attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm, + initiator_value, initiator_nonce); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + + /* Send Get TPM Version attribute */ + attr = tcg_pts_attr_get_tpm_version_info_create(); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + + /* Send Get AIK attribute */ + attr = tcg_pts_attr_get_aik_create(); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_COMP_EVID); + break; + } + case IMV_ATTESTATION_STATE_COMP_EVID: + { + tcg_pts_attr_req_func_comp_evid_t *attr_cast; + enumerator_t *enumerator; + pts_comp_func_name_t *name; + uint8_t flags; + uint32_t depth; + bool first_component = TRUE; + + if (!(state->get_action_flags(state) & IMV_ATTESTATION_AIK)) + { + break; + } + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_END); + + if (!pts->get_aik_id(pts)) + { + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK); + return FALSE; + } + + enumerator = attestation_state->create_component_enumerator( + attestation_state); + while (enumerator->enumerate(enumerator, &flags, &depth, &name)) + { + if (first_component) + { + attr = tcg_pts_attr_req_func_comp_evid_create(); + attr->set_noskip_flag(attr, TRUE); + first_component = FALSE; + DBG2(DBG_IMV, "evidence request by"); + } + name->log(name, " "); + + /* TODO check flags against negotiated_caps */ + attr_cast = (tcg_pts_attr_req_func_comp_evid_t *)attr; + attr_cast->add_component(attr_cast, flags, depth, name); + } + enumerator->destroy(enumerator); + + if (attr) + { + /* Send Request Functional Component Evidence attribute */ + out_msg->add_attribute(out_msg, attr); + + /* Send Generate Attestation Evidence attribute */ + attr = tcg_pts_attr_gen_attest_evid_create(); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_EVID_FINAL); + } + break; + } + default: + break; + } + + return TRUE; +} diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_build.h b/src/libimcv/plugins/imv_attestation/imv_attestation_build.h new file mode 100644 index 000000000..88538b198 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_build.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imv_attestation_build_t imv_attestation_build + * @{ @ingroup imv_attestation + */ + +#ifndef IMV_ATTESTATION_BUILD_H_ +#define IMV_ATTESTATION_BUILD_H_ + +#include "imv_attestation_state.h" + +#include <imv/imv_msg.h> +#include <library.h> + +#include <pts/pts_database.h> +#include <pts/pts_dh_group.h> +#include <pts/pts_meas_algo.h> + +/** + * Process a TCG PTS attribute + * + * @param out_msg outbound PA-TNC message to be built + * @param state state of a given connection + * @param supported_dh_groups supported DH groups + * @param pts_db PTS configuration database + * @return TRUE if successful + */ +bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db); + +#endif /** IMV_ATTESTATION_BUILD_H_ @}*/ diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_process.c b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c new file mode 100644 index 000000000..89a1f02cf --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_process.c @@ -0,0 +1,567 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE /* for stdndup() */ +#include <string.h> + +#include "imv_attestation_process.h" + +#include <imcv.h> +#include <ietf/ietf_attr_pa_tnc_error.h> + +#include <pts/pts.h> + +#include <tcg/pts/tcg_pts_attr_aik.h> +#include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h> +#include <tcg/pts/tcg_pts_attr_file_meas.h> +#include <tcg/pts/tcg_pts_attr_meas_algo.h> +#include <tcg/pts/tcg_pts_attr_proto_caps.h> +#include <tcg/pts/tcg_pts_attr_simple_comp_evid.h> +#include <tcg/pts/tcg_pts_attr_simple_evid_final.h> +#include <tcg/pts/tcg_pts_attr_tpm_version_info.h> +#include <tcg/pts/tcg_pts_attr_unix_file_meta.h> + +#include <utils/debug.h> +#include <crypto/hashers/hasher.h> + +#include <inttypes.h> + +bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, + imv_state_t *state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db, + credential_manager_t *pts_credmgr) +{ + imv_session_t *session; + imv_attestation_state_t *attestation_state; + pen_type_t attr_type; + pts_t *pts; + + session = state->get_session(state); + attestation_state = (imv_attestation_state_t*)state; + pts = attestation_state->get_pts(attestation_state); + attr_type = attr->get_type(attr); + + switch (attr_type.type) + { + case TCG_PTS_PROTO_CAPS: + { + tcg_pts_attr_proto_caps_t *attr_cast; + pts_proto_caps_flag_t flags; + + attr_cast = (tcg_pts_attr_proto_caps_t*)attr; + flags = attr_cast->get_flags(attr_cast); + pts->set_proto_caps(pts, flags); + break; + } + case TCG_PTS_MEAS_ALGO_SELECTION: + { + tcg_pts_attr_meas_algo_t *attr_cast; + pts_meas_algorithms_t selected_algorithm; + + attr_cast = (tcg_pts_attr_meas_algo_t*)attr; + selected_algorithm = attr_cast->get_algorithms(attr_cast); + if (!(selected_algorithm & supported_algorithms)) + { + DBG1(DBG_IMV, "PTS-IMC selected unsupported" + " measurement algorithm"); + return FALSE; + } + pts->set_meas_algorithm(pts, selected_algorithm); + state->set_action_flags(state, IMV_ATTESTATION_ALGO); + break; + } + case TCG_PTS_DH_NONCE_PARAMS_RESP: + { + tcg_pts_attr_dh_nonce_params_resp_t *attr_cast; + int nonce_len, min_nonce_len; + pts_dh_group_t dh_group; + pts_meas_algorithms_t offered_algorithms, selected_algorithm; + chunk_t responder_value, responder_nonce; + + attr_cast = (tcg_pts_attr_dh_nonce_params_resp_t*)attr; + responder_nonce = attr_cast->get_responder_nonce(attr_cast); + + /* check compliance of responder nonce length */ + min_nonce_len = lib->settings->get_int(lib->settings, + "%s.plugins.imv-attestation.min_nonce_len", 0, lib->ns); + nonce_len = responder_nonce.len; + if (nonce_len < PTS_MIN_NONCE_LEN || + (min_nonce_len > 0 && nonce_len < min_nonce_len)) + { + attr = pts_dh_nonce_error_create( + max(PTS_MIN_NONCE_LEN, min_nonce_len), + PTS_MAX_NONCE_LEN); + out_msg->add_attribute(out_msg, attr); + break; + } + + dh_group = attr_cast->get_dh_group(attr_cast); + if (!(dh_group & supported_dh_groups)) + { + DBG1(DBG_IMV, "PTS-IMC selected unsupported DH group"); + return FALSE; + } + + offered_algorithms = attr_cast->get_hash_algo_set(attr_cast); + selected_algorithm = pts_meas_algo_select(supported_algorithms, + offered_algorithms); + if (selected_algorithm == PTS_MEAS_ALGO_NONE) + { + attr = pts_hash_alg_error_create(supported_algorithms); + out_msg->add_attribute(out_msg, attr); + break; + } + pts->set_dh_hash_algorithm(pts, selected_algorithm); + + if (!pts->create_dh_nonce(pts, dh_group, nonce_len)) + { + return FALSE; + } + + responder_value = attr_cast->get_responder_value(attr_cast); + pts->set_peer_public_value(pts, responder_value, + responder_nonce); + + /* Calculate secret assessment value */ + if (!pts->calculate_secret(pts)) + { + return FALSE; + } + state->set_action_flags(state, IMV_ATTESTATION_DH_NONCE); + break; + } + case TCG_PTS_TPM_VERSION_INFO: + { + tcg_pts_attr_tpm_version_info_t *attr_cast; + chunk_t tpm_version_info; + + attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr; + tpm_version_info = attr_cast->get_tpm_version_info(attr_cast); + pts->set_tpm_version_info(pts, tpm_version_info); + break; + } + case TCG_PTS_AIK: + { + tcg_pts_attr_aik_t *attr_cast; + certificate_t *aik, *issuer; + public_key_t *public; + chunk_t keyid, keyid_hex, device_id; + int aik_id; + enumerator_t *e; + bool trusted = FALSE, trusted_chain = FALSE; + + attr_cast = (tcg_pts_attr_aik_t*)attr; + aik = attr_cast->get_aik(attr_cast); + if (!aik) + { + DBG1(DBG_IMV, "AIK unavailable"); + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK); + break; + } + + /* check trust into public key as stored in the database */ + public = aik->get_public_key(aik); + public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid); + DBG1(DBG_IMV, "verifying AIK with keyid %#B", &keyid); + keyid_hex = chunk_to_hex(keyid, NULL, FALSE); + if (session->get_device_id(session, &device_id) && + chunk_equals(keyid_hex, device_id)) + { + trusted = session->get_device_trust(session); + } + else + { + DBG1(DBG_IMV, "device ID unknown or different from AIK keyid"); + } + DBG1(DBG_IMV, "AIK public key is %strusted", trusted ? "" : "not "); + public->destroy(public); + chunk_free(&keyid_hex); + + if (aik->get_type(aik) == CERT_X509) + { + + e = pts_credmgr->create_trusted_enumerator(pts_credmgr, + KEY_ANY, aik->get_issuer(aik), FALSE); + while (e->enumerate(e, &issuer)) + { + if (aik->issued_by(aik, issuer, NULL)) + { + trusted_chain = TRUE; + break; + } + } + e->destroy(e); + DBG1(DBG_IMV, "AIK certificate is %strusted", + trusted_chain ? "" : "not "); + if (!trusted || !trusted_chain) + { + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK); + break; + } + } + session->get_session_id(session, NULL, &aik_id); + pts->set_aik(pts, aik, aik_id); + state->set_action_flags(state, IMV_ATTESTATION_AIK); + break; + } + case TCG_PTS_FILE_MEAS: + { + TNC_IMV_Evaluation_Result eval; + TNC_IMV_Action_Recommendation rec; + tcg_pts_attr_file_meas_t *attr_cast; + uint16_t request_id; + int arg_int, file_count; + pts_meas_algorithms_t algo; + pts_file_meas_t *measurements; + imv_workitem_t *workitem, *found = NULL; + imv_workitem_type_t type; + char result_str[BUF_LEN]; + bool is_dir, correct; + enumerator_t *enumerator; + + eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; + algo = pts->get_meas_algorithm(pts); + attr_cast = (tcg_pts_attr_file_meas_t*)attr; + measurements = attr_cast->get_measurements(attr_cast); + request_id = measurements->get_request_id(measurements); + file_count = measurements->get_file_count(measurements); + + DBG1(DBG_IMV, "measurement request %d returned %d file%s:", + request_id, file_count, (file_count == 1) ? "":"s"); + + if (request_id) + { + enumerator = session->create_workitem_enumerator(session); + while (enumerator->enumerate(enumerator, &workitem)) + { + /* request ID consist of lower 16 bits of workitem ID */ + if ((workitem->get_id(workitem) & 0xffff) == request_id) + { + found = workitem; + break; + } + } + + if (!found) + { + DBG1(DBG_IMV, " no entry found for file measurement " + "request %d", request_id); + enumerator->destroy(enumerator); + break; + } + type = found->get_type(found); + arg_int = found->get_arg_int(found); + + switch (type) + { + default: + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + is_dir = FALSE; + break; + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + is_dir = TRUE; + } + + switch (type) + { + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_DIR_MEAS: + { + enumerator_t *e; + + /* check hashes from database against measurements */ + e = pts_db->create_file_hash_enumerator(pts_db, + pts->get_platform_id(pts), + algo, is_dir, arg_int); + if (!e) + { + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + break; + } + correct = measurements->verify(measurements, e, is_dir); + if (!correct) + { + attestation_state->set_measurement_error( + attestation_state, + IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL); + eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR; + } + e->destroy(e); + + snprintf(result_str, BUF_LEN, "%s measurement%s correct", + is_dir ? "directory" : "file", + correct ? "" : " not"); + break; + } + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_DIR_REF_MEAS: + { + enumerator_t *e; + char *filename; + chunk_t measurement; + + e = measurements->create_enumerator(measurements); + while (e->enumerate(e, &filename, &measurement)) + { + if (pts_db->add_file_measurement(pts_db, + pts->get_platform_id(pts), algo, measurement, + filename, is_dir, arg_int) != SUCCESS) + { + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + } + } + e->destroy(e); + snprintf(result_str, BUF_LEN, "%s reference measurement " + "successful", is_dir ? "directory" : "file"); + break; + } + default: + break; + } + + session->remove_workitem(session, enumerator); + enumerator->destroy(enumerator); + rec = found->set_result(found, result_str, eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, found); + found->destroy(found); + } + else + { + measurements->check(measurements, pts_db, + pts->get_platform_id(pts), algo); + } + break; + } + case TCG_PTS_UNIX_FILE_META: + { + tcg_pts_attr_file_meta_t *attr_cast; + int file_count; + pts_file_meta_t *metadata; + pts_file_metadata_t *entry; + time_t created, modified, accessed; + bool utc = FALSE; + enumerator_t *e; + + attr_cast = (tcg_pts_attr_file_meta_t*)attr; + metadata = attr_cast->get_metadata(attr_cast); + file_count = metadata->get_file_count(metadata); + + DBG1(DBG_IMV, "metadata request returned %d file%s:", + file_count, (file_count == 1) ? "":"s"); + + e = metadata->create_enumerator(metadata); + while (e->enumerate(e, &entry)) + { + DBG1(DBG_IMV, " '%s' (%"PRIu64" bytes)" + " owner %"PRIu64", group %"PRIu64", type %N", + entry->filename, entry->filesize, entry->owner, + entry->group, pts_file_type_names, entry->type); + + created = entry->created; + modified = entry->modified; + accessed = entry->accessed; + + DBG1(DBG_IMV, " created %T, modified %T, accessed %T", + &created, utc, &modified, utc, &accessed, utc); + } + e->destroy(e); + break; + } + case TCG_PTS_SIMPLE_COMP_EVID: + { + tcg_pts_attr_simple_comp_evid_t *attr_cast; + pts_comp_func_name_t *name; + pts_comp_evidence_t *evidence; + pts_component_t *comp; + uint32_t depth; + status_t status; + + attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr; + evidence = attr_cast->get_comp_evidence(attr_cast); + name = evidence->get_comp_func_name(evidence, &depth); + + comp = attestation_state->get_component(attestation_state, name); + if (!comp) + { + DBG1(DBG_IMV, " no entry found for component evidence request"); + break; + } + status = comp->verify(comp, name->get_qualifier(name), pts, evidence); + if (status == VERIFY_ERROR || status == FAILED) + { + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_COMP_EVID_FAIL); + name->log(name, " measurement mismatch for "); + } + break; + } + case TCG_PTS_SIMPLE_EVID_FINAL: + { + tcg_pts_attr_simple_evid_final_t *attr_cast; + uint8_t flags; + pts_meas_algorithms_t comp_hash_algorithm; + chunk_t pcr_comp, tpm_quote_sig, evid_sig; + chunk_t pcr_composite, quote_info, result_buf; + imv_workitem_t *workitem; + imv_reason_string_t *reason_string; + enumerator_t *enumerator; + bool use_quote2, use_ver_info; + bio_writer_t *result; + + attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr; + flags = attr_cast->get_quote_info(attr_cast, &comp_hash_algorithm, + &pcr_comp, &tpm_quote_sig); + + if (flags != PTS_SIMPLE_EVID_FINAL_NO) + { + use_quote2 = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 || + flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER); + use_ver_info = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER); + + /* Construct PCR Composite and TPM Quote Info structures */ + if (!pts->get_quote_info(pts, use_quote2, use_ver_info, + comp_hash_algorithm, &pcr_composite, "e_info)) + { + DBG1(DBG_IMV, "unable to construct TPM Quote Info"); + return FALSE; + } + + if (!chunk_equals(pcr_comp, pcr_composite)) + { + DBG1(DBG_IMV, "received PCR Composite does not match " + "constructed one"); + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL); + goto quote_error; + } + DBG2(DBG_IMV, "received PCR Composite matches constructed one"); + + if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig)) + { + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL); + goto quote_error; + } + DBG2(DBG_IMV, "TPM Quote Info signature verification successful"); + +quote_error: + free(pcr_composite.ptr); + free(quote_info.ptr); + + /** + * Finalize any pending measurement registrations and check + * if all expected component measurements were received + */ + result = bio_writer_create(128); + attestation_state->finalize_components(attestation_state, + result); + + enumerator = session->create_workitem_enumerator(session); + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST) + { + TNC_IMV_Action_Recommendation rec; + TNC_IMV_Evaluation_Result eval; + uint32_t error; + + error = attestation_state->get_measurement_error( + attestation_state); + if (error & (IMV_ATTESTATION_ERROR_COMP_EVID_FAIL | + IMV_ATTESTATION_ERROR_COMP_EVID_PEND | + IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL)) + { + reason_string = imv_reason_string_create("en", ", "); + attestation_state->add_comp_evid_reasons( + attestation_state, reason_string); + result->write_data(result, chunk_from_str("; ")); + result->write_data(result, + reason_string->get_encoding(reason_string)); + reason_string->destroy(reason_string); + eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR; + } + else + { + eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; + } + session->remove_workitem(session, enumerator); + + result->write_uint8(result, '\0'); + result_buf = result->get_buf(result); + rec = workitem->set_result(workitem, result_buf.ptr, + eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, workitem); + workitem->destroy(workitem); + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_END); + break; + } + } + enumerator->destroy(enumerator); + result->destroy(result); + } + + if (attr_cast->get_evid_sig(attr_cast, &evid_sig)) + { + /** TODO: What to do with Evidence Signature */ + DBG1(DBG_IMV, "this version of the Attestation IMV can not " + "handle Evidence Signatures"); + } + break; + } + case TCG_SEG_MAX_ATTR_SIZE_RESP: + case TCG_SEG_ATTR_SEG_ENV: + break; + + /* TODO: Not implemented yet */ + case TCG_PTS_INTEG_MEAS_LOG: + /* Attributes using XML */ + case TCG_PTS_TEMPL_REF_MANI_SET_META: + case TCG_PTS_VERIFICATION_RESULT: + case TCG_PTS_INTEG_REPORT: + /* On Windows only*/ + case TCG_PTS_WIN_FILE_META: + case TCG_PTS_REGISTRY_VALUE: + /* Received on IMC side only*/ + case TCG_PTS_REQ_PROTO_CAPS: + case TCG_PTS_DH_NONCE_PARAMS_REQ: + case TCG_PTS_DH_NONCE_FINISH: + case TCG_PTS_MEAS_ALGO: + case TCG_PTS_GET_TPM_VERSION_INFO: + case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META: + case TCG_PTS_UPDATE_TEMPL_REF_MANI: + case TCG_PTS_GET_AIK: + case TCG_PTS_REQ_FUNC_COMP_EVID: + case TCG_PTS_GEN_ATTEST_EVID: + case TCG_PTS_REQ_FILE_META: + case TCG_PTS_REQ_FILE_MEAS: + case TCG_PTS_REQ_INTEG_MEAS_LOG: + default: + DBG1(DBG_IMV, "received unsupported attribute '%N/%N'", + pen_names, PEN_TCG, tcg_attr_names, attr_type.type); + break; + } + return TRUE; +} + diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_process.h b/src/libimcv/plugins/imv_attestation/imv_attestation_process.h new file mode 100644 index 000000000..af8666b66 --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_process.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imv_attestation_process_t imv_attestation_process + * @{ @ingroup imv_attestation + */ + +#ifndef IMV_ATTESTATION_PROCESS_H_ +#define IMV_ATTESTATION_PROCESS_H_ + +#include "imv_attestation_state.h" + +#include <library.h> +#include <collections/linked_list.h> +#include <credentials/credential_manager.h> +#include <crypto/hashers/hasher.h> + +#include <imv/imv_msg.h> +#include <pa_tnc/pa_tnc_attr.h> + +#include <pts/pts_database.h> +#include <pts/pts_dh_group.h> +#include <pts/pts_meas_algo.h> + +/** + * Process a TCG PTS attribute + * + * @param attr PA-TNC attribute to be processed + * @param out_msg PA-TNC message containing error messages + * @param state state of a given connection + * @param supported_algorithms supported PTS measurement algorithms + * @param supported_dh_groups supported DH groups + * @param pts_db PTS configuration database + * @param pts_credmgr PTS credential manager + * @return TRUE if successful + */ +bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, + imv_state_t *state, + pts_meas_algorithms_t supported_algorithms, + pts_dh_group_t supported_dh_groups, + pts_database_t *pts_db, + credential_manager_t *pts_credmgr); + +#endif /** IMV_ATTESTATION_PROCESS_H_ @}*/ diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.c b/src/libimcv/plugins/imv_attestation/imv_attestation_state.c new file mode 100644 index 000000000..1c3b91aeb --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_state.c @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imv_attestation_state.h" + +#include <imcv.h> +#include <imv/imv_lang_string.h> +#include "imv/imv_reason_string.h" + +#include <tncif_policy.h> + +#include <collections/linked_list.h> +#include <utils/debug.h> + +typedef struct private_imv_attestation_state_t private_imv_attestation_state_t; +typedef struct file_meas_request_t file_meas_request_t; +typedef struct func_comp_t func_comp_t; + +/** + * Private data of an imv_attestation_state_t object. + */ +struct private_imv_attestation_state_t { + + /** + * Public members of imv_attestation_state_t + */ + imv_attestation_state_t public; + + /** + * TNCCS connection ID + */ + TNC_ConnectionID connection_id; + + /** + * TNCCS connection state + */ + TNC_ConnectionState state; + + /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + uint32_t max_msg_len; + + /** + * Flags set for completed actions + */ + uint32_t action_flags; + + /** + * IMV database session associated with TNCCS connection + */ + imv_session_t *session; + + /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** + * IMV Attestation handshake state + */ + imv_attestation_handshake_state_t handshake_state; + + /** + * IMV action recommendation + */ + TNC_IMV_Action_Recommendation rec; + + /** + * IMV evaluation result + */ + TNC_IMV_Evaluation_Result eval; + + /** + * List of Functional Components + */ + linked_list_t *components; + + /** + * PTS object + */ + pts_t *pts; + + /** + * Measurement error flags + */ + uint32_t measurement_error; + + /** + * TNC Reason String + */ + imv_reason_string_t *reason_string; + +}; + +/** + * PTS Functional Component entry + */ +struct func_comp_t { + pts_component_t *comp; + pts_comp_func_name_t* name; +}; + +/** + * Frees a func_comp_t object + */ +static void free_func_comp(func_comp_t *this) +{ + this->comp->destroy(this->comp); + this->name->destroy(this->name); + free(this); +} + +/** + * Supported languages + */ +static char* languages[] = { "en", "de", "mn" }; + +/** + * Table of reason strings + */ +static imv_lang_string_t reason_file_meas_fail[] = { + { "en", "Incorrect file measurement" }, + { "de", "Falsche Dateimessung" }, + { "mn", "Буруу байгаа файл" }, + { NULL, NULL } +}; + +static imv_lang_string_t reason_file_meas_pend[] = { + { "en", "Pending file measurement" }, + { "de", "Ausstehende Dateimessung" }, + { "mn", "Xүлээгдэж байгаа файл" }, + { NULL, NULL } +}; + +static imv_lang_string_t reason_no_trusted_aik[] = { + { "en", "No trusted AIK available" }, + { "de", "Kein vetrauenswürdiger AIK verfügbar" }, + { NULL, NULL } +}; + +static imv_lang_string_t reason_comp_evid_fail[] = { + { "en", "Incorrect component evidence" }, + { "de", "Falsche Komponenten-Evidenz" }, + { "mn", "Буруу компонент хэмжилт" }, + { NULL, NULL } +}; + +static imv_lang_string_t reason_comp_evid_pend[] = { + { "en", "Pending component evidence" }, + { "de", "Ausstehende Komponenten-Evidenz" }, + { "mn", "Xүлээгдэж компонент хэмжилт" }, + { NULL, NULL } +}; + +static imv_lang_string_t reason_tpm_quote_fail[] = { + { "en", "Invalid TPM Quote signature received" }, + { "de", "Falsche TPM Quote Signature erhalten" }, + { "mn", "Буруу TPM Quote гарын үсэг" }, + { NULL, NULL } +}; + +METHOD(imv_state_t, get_connection_id, TNC_ConnectionID, + private_imv_attestation_state_t *this) +{ + return this->connection_id; +} + +METHOD(imv_state_t, has_long, bool, + private_imv_attestation_state_t *this) +{ + return this->has_long; +} + +METHOD(imv_state_t, has_excl, bool, + private_imv_attestation_state_t *this) +{ + return this->has_excl; +} + +METHOD(imv_state_t, set_flags, void, + private_imv_attestation_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + +METHOD(imv_state_t, set_max_msg_len, void, + private_imv_attestation_state_t *this, uint32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imv_state_t, get_max_msg_len, uint32_t, + private_imv_attestation_state_t *this) +{ + return this->max_msg_len; +} + +METHOD(imv_state_t, set_action_flags, void, + private_imv_attestation_state_t *this, uint32_t flags) +{ + this->action_flags |= flags; +} + +METHOD(imv_state_t, get_action_flags, uint32_t, + private_imv_attestation_state_t *this) +{ + return this->action_flags; +} + +METHOD(imv_state_t, set_session, void, + private_imv_attestation_state_t *this, imv_session_t *session) +{ + this->session = session; +} + +METHOD(imv_state_t, get_session, imv_session_t*, + private_imv_attestation_state_t *this) +{ + return this->session; +} + +METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, + private_imv_attestation_state_t *this) +{ + return this->contracts; +} + +METHOD(imv_state_t, change_state, void, + private_imv_attestation_state_t *this, TNC_ConnectionState new_state) +{ + this->state = new_state; +} + +METHOD(imv_state_t, get_recommendation, void, + private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation *rec, + TNC_IMV_Evaluation_Result *eval) +{ + *rec = this->rec; + *eval = this->eval; +} + +METHOD(imv_state_t, set_recommendation, void, + private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval) +{ + this->rec = rec; + this->eval = eval; +} + +METHOD(imv_state_t, update_recommendation, void, + private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval) +{ + this->rec = tncif_policy_update_recommendation(this->rec, rec); + this->eval = tncif_policy_update_evaluation(this->eval, eval); +} + +METHOD(imv_attestation_state_t, add_file_meas_reasons, void, + private_imv_attestation_state_t *this, imv_reason_string_t *reason_string) +{ + if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL) + { + reason_string->add_reason(reason_string, reason_file_meas_fail); + } + if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_PEND) + { + reason_string->add_reason(reason_string, reason_file_meas_pend); + } +} + +METHOD(imv_attestation_state_t, add_comp_evid_reasons, void, + private_imv_attestation_state_t *this, imv_reason_string_t *reason_string) +{ + if (this->measurement_error & IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK) + { + reason_string->add_reason(reason_string, reason_no_trusted_aik); + } + if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_FAIL) + { + reason_string->add_reason(reason_string, reason_comp_evid_fail); + } + if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_PEND) + { + reason_string->add_reason(reason_string, reason_comp_evid_pend); + } + if (this->measurement_error & IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL) + { + reason_string->add_reason(reason_string, reason_tpm_quote_fail); + } +} + +METHOD(imv_state_t, get_reason_string, bool, + private_imv_attestation_state_t *this, enumerator_t *language_enumerator, + chunk_t *reason_string, char **reason_language) +{ + *reason_language = imv_lang_string_select_lang(language_enumerator, + languages, countof(languages)); + + /* Instantiate a TNC Reason String object */ + DESTROY_IF(this->reason_string); + this->reason_string = imv_reason_string_create(*reason_language, "\n"); + add_file_meas_reasons(this, this->reason_string); + add_comp_evid_reasons(this, this->reason_string); + *reason_string = this->reason_string->get_encoding(this->reason_string); + + return TRUE; +} + +METHOD(imv_state_t, get_remediation_instructions, bool, + private_imv_attestation_state_t *this, enumerator_t *language_enumerator, + chunk_t *string, char **lang_code, char **uri) +{ + return FALSE; +} + +METHOD(imv_state_t, destroy, void, + private_imv_attestation_state_t *this) +{ + DESTROY_IF(this->session); + DESTROY_IF(this->reason_string); + this->components->destroy_function(this->components, (void *)free_func_comp); + this->pts->destroy(this->pts); + this->contracts->destroy(this->contracts); + free(this); +} + +METHOD(imv_attestation_state_t, get_handshake_state, + imv_attestation_handshake_state_t, private_imv_attestation_state_t *this) +{ + return this->handshake_state; +} + +METHOD(imv_attestation_state_t, set_handshake_state, void, + private_imv_attestation_state_t *this, + imv_attestation_handshake_state_t new_state) +{ + this->handshake_state = new_state; +} + +METHOD(imv_attestation_state_t, get_pts, pts_t*, + private_imv_attestation_state_t *this) +{ + return this->pts; +} + +METHOD(imv_attestation_state_t, create_component, pts_component_t*, + private_imv_attestation_state_t *this, pts_comp_func_name_t *name, + uint32_t depth, pts_database_t *pts_db) +{ + enumerator_t *enumerator; + func_comp_t *entry, *new_entry; + pts_component_t *component; + bool found = FALSE; + + enumerator = this->components->create_enumerator(this->components); + while (enumerator->enumerate(enumerator, &entry)) + { + if (name->equals(name, entry->comp->get_comp_func_name(entry->comp))) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (found) + { + if (name->equals(name, entry->name)) + { + /* duplicate entry */ + return NULL; + } + new_entry = malloc_thing(func_comp_t); + new_entry->name = name->clone(name); + new_entry->comp = entry->comp->get_ref(entry->comp); + this->components->insert_last(this->components, new_entry); + return entry->comp; + } + else + { + component = imcv_pts_components->create(imcv_pts_components, + name, depth, pts_db); + if (!component) + { + /* unsupported component */ + return NULL; + } + new_entry = malloc_thing(func_comp_t); + new_entry->name = name->clone(name); + new_entry->comp = component; + this->components->insert_last(this->components, new_entry); + return component; + } +} + +/** + * Enumerate file measurement entries + */ +static bool entry_filter(void *null, func_comp_t **entry, uint8_t *flags, + void *i2, uint32_t *depth, + void *i3, pts_comp_func_name_t **comp_name) +{ + pts_component_t *comp; + pts_comp_func_name_t *name; + + comp = (*entry)->comp; + name = (*entry)->name; + + *flags = comp->get_evidence_flags(comp); + *depth = comp->get_depth(comp); + *comp_name = name; + + return TRUE; +} + +METHOD(imv_attestation_state_t, create_component_enumerator, enumerator_t*, + private_imv_attestation_state_t *this) +{ + return enumerator_create_filter( + this->components->create_enumerator(this->components), + (void*)entry_filter, NULL, NULL); +} + +METHOD(imv_attestation_state_t, get_component, pts_component_t*, + private_imv_attestation_state_t *this, pts_comp_func_name_t *name) +{ + enumerator_t *enumerator; + func_comp_t *entry; + pts_component_t *found = NULL; + + enumerator = this->components->create_enumerator(this->components); + while (enumerator->enumerate(enumerator, &entry)) + { + if (name->equals(name, entry->name)) + { + found = entry->comp; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +METHOD(imv_attestation_state_t, get_measurement_error, uint32_t, + private_imv_attestation_state_t *this) +{ + return this->measurement_error; +} + +METHOD(imv_attestation_state_t, set_measurement_error, void, + private_imv_attestation_state_t *this, uint32_t error) +{ + this->measurement_error |= error; +} + +METHOD(imv_attestation_state_t, finalize_components, void, + private_imv_attestation_state_t *this, bio_writer_t *result) +{ + func_comp_t *entry; + bool first = TRUE; + + while (this->components->remove_last(this->components, + (void**)&entry) == SUCCESS) + { + if (first) + { + first = FALSE; + } + else + { + result->write_data(result, chunk_from_str("; ")); + } + if (!entry->comp->finalize(entry->comp, + entry->name->get_qualifier(entry->name), + result)) + { + set_measurement_error(this, IMV_ATTESTATION_ERROR_COMP_EVID_PEND); + } + free_func_comp(entry); + } +} + +/** + * Described in header. + */ +imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) +{ + private_imv_attestation_state_t *this; + + INIT(this, + .public = { + .interface = { + .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, + .set_action_flags = _set_action_flags, + .get_action_flags = _get_action_flags, + .set_session = _set_session, + .get_session = _get_session, + .get_contracts = _get_contracts, + .change_state = _change_state, + .get_recommendation = _get_recommendation, + .set_recommendation = _set_recommendation, + .update_recommendation = _update_recommendation, + .get_reason_string = _get_reason_string, + .get_remediation_instructions = _get_remediation_instructions, + .destroy = _destroy, + }, + .get_handshake_state = _get_handshake_state, + .set_handshake_state = _set_handshake_state, + .get_pts = _get_pts, + .create_component = _create_component, + .create_component_enumerator = _create_component_enumerator, + .get_component = _get_component, + .finalize_components = _finalize_components, + .get_measurement_error = _get_measurement_error, + .set_measurement_error = _set_measurement_error, + .add_file_meas_reasons = _add_file_meas_reasons, + .add_comp_evid_reasons = _add_comp_evid_reasons, + }, + .connection_id = connection_id, + .state = TNC_CONNECTION_STATE_CREATE, + .handshake_state = IMV_ATTESTATION_STATE_INIT, + .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, + .contracts = seg_contract_manager_create(), + .components = linked_list_create(), + .pts = pts_create(FALSE), + ); + + return &this->public.interface; +} diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_state.h b/src/libimcv/plugins/imv_attestation/imv_attestation_state.h new file mode 100644 index 000000000..39a8eee9c --- /dev/null +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_state.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imv_attestation imv_attestation + * @ingroup libimcv_plugins + * + * @defgroup imv_attestation_state_t imv_attestation_state + * @{ @ingroup imv_attestation + */ + +#ifndef IMV_ATTESTATION_STATE_H_ +#define IMV_ATTESTATION_STATE_H_ + +#include <imv/imv_state.h> +#include <imv/imv_reason_string.h> +#include <pts/pts.h> +#include <pts/pts_database.h> +#include <pts/components/pts_component.h> + +#include <library.h> +#include <bio/bio_writer.h> + +typedef struct imv_attestation_state_t imv_attestation_state_t; +typedef enum imv_attestation_flag_t imv_attestation_flag_t; +typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t; +typedef enum imv_meas_error_t imv_meas_error_t; + +/** + * IMV Attestation Flags set for completed actions + */ +enum imv_attestation_flag_t { + IMV_ATTESTATION_ATTR_PRODUCT_INFO = (1<<0), + IMV_ATTESTATION_ATTR_STRING_VERSION = (1<<1), + IMV_ATTESTATION_ATTR_DEVICE_ID = (1<<2), + IMV_ATTESTATION_ATTR_MUST = (1<<3)-1, + IMV_ATTESTATION_ATTR_REQ = (1<<3), + IMV_ATTESTATION_ALGO = (1<<4), + IMV_ATTESTATION_DH_NONCE = (1<<5), + IMV_ATTESTATION_AIK = (1<<6), + IMV_ATTESTATION_FILE_MEAS = (1<<7), + IMV_ATTESTATION_REC = (1<<8) +}; + +/** + * IMV Attestation Handshake States (state machine) + */ +enum imv_attestation_handshake_state_t { + IMV_ATTESTATION_STATE_INIT, + IMV_ATTESTATION_STATE_DISCOVERY, + IMV_ATTESTATION_STATE_NONCE_REQ, + IMV_ATTESTATION_STATE_TPM_INIT, + IMV_ATTESTATION_STATE_COMP_EVID, + IMV_ATTESTATION_STATE_EVID_FINAL, + IMV_ATTESTATION_STATE_END, +}; + +/** + * IMV Measurement Error Types + */ +enum imv_meas_error_t { + IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL = 1, + IMV_ATTESTATION_ERROR_FILE_MEAS_PEND = 2, + IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK = 4, + IMV_ATTESTATION_ERROR_COMP_EVID_FAIL = 8, + IMV_ATTESTATION_ERROR_COMP_EVID_PEND = 16, + IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL = 32 +}; + +/** + * Internal state of an imv_attestation_t connection instance + */ +struct imv_attestation_state_t { + + /** + * imv_state_t interface + */ + imv_state_t interface; + + /** + * Get state of the handshake + * + * @return the handshake state of IMV + */ + imv_attestation_handshake_state_t (*get_handshake_state)( + imv_attestation_state_t *this); + + /** + * Set state of the handshake + * + * @param new_state the handshake state of IMV + */ + void (*set_handshake_state)(imv_attestation_state_t *this, + imv_attestation_handshake_state_t new_state); + + /** + * Get the PTS object + * + * @return PTS object + */ + pts_t* (*get_pts)(imv_attestation_state_t *this); + + /** + * Create and add an entry to the list of Functional Components + * + * @param name Component Functional Name + * @param depth Sub-component Depth + * @param pts_db PTS measurement database + * @return created functional component instance or NULL + */ + pts_component_t* (*create_component)(imv_attestation_state_t *this, + pts_comp_func_name_t *name, + uint32_t depth, + pts_database_t *pts_db); + + /** + * Enumerate over all Functional Components + * + * @return Functional Component enumerator + */ + enumerator_t* (*create_component_enumerator)(imv_attestation_state_t *this); + + /** + * Get a Functional Component with a given name + * + * @param name Name of the requested Functional Component + * @return Functional Component if found, NULL otherwise + */ + pts_component_t* (*get_component)(imv_attestation_state_t *this, + pts_comp_func_name_t *name); + + /** + * Tell the Functional Components to finalize any measurement registrations + * and to check if all expected measurements were received + * + * @param result Writer appending component measurement results + */ + void (*finalize_components)(imv_attestation_state_t *this, + bio_writer_t *result); + + /** + * Indicates the types of measurement errors that occurred + * + * @return Measurement error flags + */ + uint32_t (*get_measurement_error)(imv_attestation_state_t *this); + + /** + * Call if a measurement error is encountered + * + * @param error Measurement error type + */ + void (*set_measurement_error)(imv_attestation_state_t *this, + uint32_t error); + + /** + * Returns a concatenation of File Measurement reason strings + * + * @param reason_string Concatenated reason strings + */ + void (*add_file_meas_reasons)(imv_attestation_state_t *this, + imv_reason_string_t *reason_string); + + /** + * Returns a concatenation of Component Evidence reason strings + * + * @param reason_string Concatenated reason strings + */ + void (*add_comp_evid_reasons)(imv_attestation_state_t *this, + imv_reason_string_t *reason_string); +}; + +/** + * Create an imv_attestation_state_t instance + * + * @param id connection ID + */ +imv_state_t* imv_attestation_state_create(TNC_ConnectionID id); + +#endif /** IMV_ATTESTATION_STATE_H_ @}*/ diff --git a/src/libimcv/plugins/imv_os/Makefile.in b/src/libimcv/plugins/imv_os/Makefile.in index cae6dbe84..36e708fc9 100644 --- a/src/libimcv/plugins/imv_os/Makefile.in +++ b/src/libimcv/plugins/imv_os/Makefile.in @@ -238,6 +238,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ GPRBUILD = @GPRBUILD@ @@ -298,6 +299,7 @@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ RUBYINCLUDE = @RUBYINCLUDE@ RUBYLIB = @RUBYLIB@ SED = @SED@ @@ -363,6 +365,8 @@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -410,6 +414,10 @@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ target_alias = @target_alias@ diff --git a/src/libimcv/plugins/imv_os/imv_os_agent.c b/src/libimcv/plugins/imv_os/imv_os_agent.c index ca8bac6ca..f0b1936ab 100644 --- a/src/libimcv/plugins/imv_os/imv_os_agent.c +++ b/src/libimcv/plugins/imv_os/imv_os_agent.c @@ -37,8 +37,9 @@ #include <ita/ita_attr.h> #include <ita/ita_attr_get_settings.h> #include <ita/ita_attr_settings.h> -#include <ita/ita_attr_angel.h> #include <ita/ita_attr_device_id.h> +#include "tcg/seg/tcg_seg_attr_max_size.h" +#include "tcg/seg/tcg_seg_attr_seg_env.h" #include <tncif_names.h> #include <tncif_pa_subtypes.h> @@ -46,6 +47,8 @@ #include <pen/pen.h> #include <utils/debug.h> +#define INSTALLED_PACKAGES_MAX_ATTR_SIZE 100000000 + typedef struct private_imv_os_agent_t private_imv_os_agent_t; typedef enum imv_os_attr_t imv_os_attr_t; @@ -166,20 +169,23 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, chunk_t os_name = chunk_empty; chunk_t os_version = chunk_empty; bool fatal_error = FALSE, assessment = FALSE; + uint16_t missing; os_state = (imv_os_state_t*)state; session = state->get_session(state); os_info = session->get_os_info(session); + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imv_msg_create_as_reply(in_msg); + /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); + result = in_msg->receive(in_msg,out_msg, &fatal_error); if (result != TNC_RESULT_SUCCESS) { + out_msg->destroy(out_msg); return result; } - out_msg = imv_msg_create_as_reply(in_msg); - /* analyze PA-TNC attributes */ enumerator = in_msg->create_attribute_enumerator(in_msg); while (enumerator->enumerate(enumerator, &attr)) @@ -323,6 +329,9 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, TNC_IMV_EVALUATION_RESULT_ERROR); assessment = TRUE; } + missing = attr_cast->get_count(attr_cast); + os_state->set_missing(os_state, missing); + attr_cast->clear_packages(attr_cast); break; } default: @@ -369,12 +378,6 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, session->set_device_id(session, value); break; } - case ITA_ATTR_START_ANGEL: - os_state->set_angel_count(os_state, TRUE); - break; - case ITA_ATTR_STOP_ANGEL: - os_state->set_angel_count(os_state, FALSE); - break; default: break; } @@ -394,20 +397,20 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, { os_state->set_handshake_state(os_state, IMV_OS_STATE_END); result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) + if (result == TNC_RESULT_SUCCESS) { - return result; + result = this->agent->provide_recommendation(this->agent, state); } - return this->agent->provide_recommendation(this->agent, state); } - - /* send PA-TNC message with excl flag set */ - result = out_msg->send(out_msg, TRUE); + else + { + /* send PA-TNC message with the EXCL flag set */ + result = out_msg->send(out_msg, TRUE); + } out_msg->destroy(out_msg); return result; - } +} METHOD(imv_agent_if_t, receive_message, TNC_Result, private_imv_os_agent_t *this, TNC_ConnectionID id, @@ -529,6 +532,30 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, if (handshake_state == IMV_OS_STATE_INIT) { + size_t max_attr_size = INSTALLED_PACKAGES_MAX_ATTR_SIZE; + size_t max_seg_size; + seg_contract_t *contract; + seg_contract_manager_t *contracts; + char buf[BUF_LEN]; + + /* Determine maximum PA-TNC attribute segment size */ + max_seg_size = state->get_max_msg_len(state) + - PA_TNC_HEADER_SIZE + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_SEG_ENV_HEADER + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_MAX_SIZE_SIZE; + + /* Announce support of PA-TNC segmentation to IMC */ + contract = seg_contract_create(msg_types[0], max_attr_size, + max_seg_size, TRUE, imv_id, FALSE); + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMV, "%s", buf); + contracts = state->get_contracts(state); + contracts->add_contract(contracts, contract); + attr = tcg_seg_attr_max_size_create(max_attr_size, max_seg_size, TRUE); + out_msg->add_attribute(out_msg, attr); + if ((received & IMV_OS_ATTR_MUST) != IMV_OS_ATTR_MUST) { /* create attribute request for missing mandatory attributes */ @@ -671,7 +698,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, int count, count_update, count_blacklist, count_ok; if (!(received & IMV_OS_ATTR_INSTALLED_PACKAGES) || - os_state->get_angel_count(os_state) > 0) + os_state->get_missing(os_state) > 0) { continue; } diff --git a/src/libimcv/plugins/imv_os/imv_os_state.c b/src/libimcv/plugins/imv_os/imv_os_state.c index dc8474ac9..ac826a77c 100644 --- a/src/libimcv/plugins/imv_os/imv_os_state.c +++ b/src/libimcv/plugins/imv_os/imv_os_state.c @@ -76,6 +76,11 @@ struct private_imv_os_state_t { imv_session_t *session; /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** * IMV action recommendation */ TNC_IMV_Action_Recommendation rec; @@ -136,9 +141,9 @@ struct private_imv_os_state_t { u_int os_settings; /** - * Angel count + * Number of installed packages still missing */ - int angel_count; + uint16_t missing; }; @@ -327,6 +332,12 @@ METHOD(imv_state_t, get_session, imv_session_t*, return this->session; } +METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, + private_imv_os_state_t *this) +{ + return this->contracts; +} + METHOD(imv_state_t, get_recommendation, void, private_imv_os_state_t *this, TNC_IMV_Action_Recommendation *rec, TNC_IMV_Evaluation_Result *eval) @@ -461,6 +472,7 @@ METHOD(imv_state_t, destroy, void, DESTROY_IF(this->session); DESTROY_IF(this->reason_string); DESTROY_IF(this->remediation_string); + this->contracts->destroy(this->contracts); this->update_packages->destroy_function(this->update_packages, free); this->remove_packages->destroy_function(this->remove_packages, free); free(this); @@ -523,16 +535,16 @@ METHOD(imv_os_state_t, get_os_settings, u_int, return this->os_settings; } -METHOD(imv_os_state_t, set_angel_count, void, - private_imv_os_state_t *this, bool start) +METHOD(imv_os_state_t, set_missing, void, + private_imv_os_state_t *this, uint16_t missing) { - this->angel_count += start ? 1 : -1; + this->missing = missing; } -METHOD(imv_os_state_t, get_angel_count, int, +METHOD(imv_os_state_t, get_missing, uint16_t, private_imv_os_state_t *this) { - return this->angel_count; + return this->missing; } METHOD(imv_os_state_t, add_bad_package, void, @@ -571,6 +583,7 @@ imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id) .get_action_flags = _get_action_flags, .set_session = _set_session, .get_session = _get_session, + .get_contracts = _get_contracts, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, @@ -585,14 +598,15 @@ imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id) .get_count = _get_count, .set_os_settings = _set_os_settings, .get_os_settings = _get_os_settings, - .set_angel_count = _set_angel_count, - .get_angel_count = _get_angel_count, + .set_missing = _set_missing, + .get_missing = _get_missing, .add_bad_package = _add_bad_package, }, .state = TNC_CONNECTION_STATE_CREATE, .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, + .contracts = seg_contract_manager_create(), .update_packages = linked_list_create(), .remove_packages = linked_list_create(), ); diff --git a/src/libimcv/plugins/imv_os/imv_os_state.h b/src/libimcv/plugins/imv_os/imv_os_state.h index 82ebb6cc9..aa9b64076 100644 --- a/src/libimcv/plugins/imv_os/imv_os_state.h +++ b/src/libimcv/plugins/imv_os/imv_os_state.h @@ -114,18 +114,18 @@ struct imv_os_state_t { u_int (*get_os_settings)(imv_os_state_t *this); /** - * Increase/Decrease the ITA Angel count + * Set number of installed packages still missing * - * @param start TRUE increases and FALSE decreases count by one + * @param missing Number of missing installed packages */ - void (*set_angel_count)(imv_os_state_t *this, bool start); + void (*set_missing)(imv_os_state_t *this, uint16_t missing); /** - * Get the ITA Angel count + * Get number of installed packages still missing * - * @return ITA Angel count + * @return Number of missing installed packages */ - int (*get_angel_count)(imv_os_state_t *this); + uint16_t (*get_missing)(imv_os_state_t *this); /** * Store a bad package that has to be updated or removed diff --git a/src/libimcv/plugins/imv_scanner/Makefile.in b/src/libimcv/plugins/imv_scanner/Makefile.in index 18446e73a..2677b339a 100644 --- a/src/libimcv/plugins/imv_scanner/Makefile.in +++ b/src/libimcv/plugins/imv_scanner/Makefile.in @@ -232,6 +232,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ GPRBUILD = @GPRBUILD@ @@ -292,6 +293,7 @@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ RUBYINCLUDE = @RUBYINCLUDE@ RUBYLIB = @RUBYLIB@ SED = @SED@ @@ -357,6 +359,8 @@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -404,6 +408,10 @@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ target_alias = @target_alias@ diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c b/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c index 85ef23b80..cbabc80bf 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner_agent.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_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 @@ -94,10 +94,14 @@ static TNC_Result receive_msg(private_imv_scanner_agent_t *this, ietf_attr_port_filter_t *port_filter_attr; bool fatal_error = FALSE; + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imv_msg_create_as_reply(in_msg); + /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); + result = in_msg->receive(in_msg, out_msg, &fatal_error); if (result != TNC_RESULT_SUCCESS) { + out_msg->destroy(out_msg); return result; } @@ -121,17 +125,20 @@ static TNC_Result receive_msg(private_imv_scanner_agent_t *this, state->set_recommendation(state, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, TNC_IMV_EVALUATION_RESULT_ERROR); - out_msg = imv_msg_create_as_reply(in_msg); result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) + if (result == TNC_RESULT_SUCCESS) { - return result; + result = this->agent->provide_recommendation(this->agent, state); } - return this->agent->provide_recommendation(this->agent, state); } + else + { + /* send PA-TNC message with the EXCL flag set */ + result = out_msg->send(out_msg, TRUE); + } + out_msg->destroy(out_msg); - return TNC_RESULT_SUCCESS; + return result; } METHOD(imv_agent_if_t, receive_message, TNC_Result, diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c index 24a49a76c..8f9593f17 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c @@ -71,6 +71,11 @@ struct private_imv_scanner_state_t { imv_session_t *session; /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** * IMV action recommendation */ TNC_IMV_Action_Recommendation rec; @@ -211,6 +216,12 @@ METHOD(imv_state_t, get_session, imv_session_t*, return this->session; } +METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, + private_imv_scanner_state_t *this) +{ + return this->contracts; +} + METHOD(imv_state_t, change_state, void, private_imv_scanner_state_t *this, TNC_ConnectionState new_state) { @@ -299,6 +310,7 @@ METHOD(imv_state_t, destroy, void, DESTROY_IF(this->reason_string); DESTROY_IF(this->remediation_string); DESTROY_IF(&this->port_filter_attr->pa_tnc_attribute); + this->contracts->destroy(this->contracts); this->violating_ports->destroy_function(this->violating_ports, free); free(this); } @@ -354,6 +366,7 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id) .get_action_flags = _get_action_flags, .set_session = _set_session, .get_session= _get_session, + .get_contracts = _get_contracts, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, @@ -372,6 +385,7 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id) .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, + .contracts = seg_contract_manager_create(), .violating_ports = linked_list_create(), ); diff --git a/src/libimcv/plugins/imv_swid/Makefile.am b/src/libimcv/plugins/imv_swid/Makefile.am new file mode 100644 index 000000000..3a63b67d2 --- /dev/null +++ b/src/libimcv/plugins/imv_swid/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) $(json_CFLAGS) + +imcv_LTLIBRARIES = imv-swid.la + +imv_swid_la_LIBADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(json_LIBS) + +imv_swid_la_SOURCES = \ + imv_swid.c imv_swid_state.h imv_swid_state.c \ + imv_swid_agent.h imv_swid_agent.c \ + imv_swid_rest.h imv_swid_rest.c + +imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined diff --git a/src/libimcv/plugins/imv_swid/Makefile.in b/src/libimcv/plugins/imv_swid/Makefile.in new file mode 100644 index 000000000..815722f9c --- /dev/null +++ b/src/libimcv/plugins/imv_swid/Makefile.in @@ -0,0 +1,769 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libimcv/plugins/imv_swid +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/split-package-version.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(imcvdir)" +LTLIBRARIES = $(imcv_LTLIBRARIES) +am__DEPENDENCIES_1 = +imv_swid_la_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(am__DEPENDENCIES_1) +am_imv_swid_la_OBJECTS = imv_swid.lo imv_swid_state.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@) +am__v_lt_0 = --silent +am__v_lt_1 = +imv_swid_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(imv_swid_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(imv_swid_la_SOURCES) +DIST_SOURCES = $(imv_swid_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +COVERAGE_CFLAGS = @COVERAGE_CFLAGS@ +COVERAGE_LDFLAGS = @COVERAGE_LDFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GEM = @GEM@ +GENHTML = @GENHTML@ +GPERF = @GPERF@ +GPRBUILD = @GPRBUILD@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_LIB = @OPENSSL_LIB@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_BUILD = @PACKAGE_VERSION_BUILD@ +PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@ +PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@ +PACKAGE_VERSION_REVIEW = @PACKAGE_VERSION_REVIEW@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +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@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ +RUBYINCLUDE = @RUBYINCLUDE@ +RUBYLIB = @RUBYLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +UNWINDLIB = @UNWINDLIB@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +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@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +cmd_plugins = @cmd_plugins@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +fips_mode = @fips_mode@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +strongswan_options = @strongswan_options@ +swanctldir = @swanctldir@ +sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ +systemdsystemunitdir = @systemdsystemunitdir@ +t_plugins = @t_plugins@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) $(json_CFLAGS) + +imcv_LTLIBRARIES = imv-swid.la +imv_swid_la_LIBADD = \ + $(top_builddir)/src/libimcv/libimcv.la \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(json_LIBS) + +imv_swid_la_SOURCES = \ + imv_swid.c imv_swid_state.h imv_swid_state.c \ + imv_swid_agent.h imv_swid_agent.c \ + imv_swid_rest.h imv_swid_rest.c + +imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libimcv/plugins/imv_swid/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libimcv/plugins/imv_swid/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-imcvLTLIBRARIES: $(imcv_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(imcvdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(imcvdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imcvdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imcvdir)"; \ + } + +uninstall-imcvLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(imcv_LTLIBRARIES)'; test -n "$(imcvdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imcvdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imcvdir)/$$f"; \ + done + +clean-imcvLTLIBRARIES: + -test -z "$(imcv_LTLIBRARIES)" || rm -f $(imcv_LTLIBRARIES) + @list='$(imcv_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +imv-swid.la: $(imv_swid_la_OBJECTS) $(imv_swid_la_DEPENDENCIES) $(EXTRA_imv_swid_la_DEPENDENCIES) + $(AM_V_CCLD)$(imv_swid_la_LINK) -rpath $(imcvdir) $(imv_swid_la_OBJECTS) $(imv_swid_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@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: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(imcvdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-imcvLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-imcvLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-imcvLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-imcvLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-imcvLTLIBRARIES install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-imcvLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libimcv/plugins/imv_swid/imv_swid.c b/src/libimcv/plugins/imv_swid/imv_swid.c new file mode 100644 index 000000000..cab011580 --- /dev/null +++ b/src/libimcv/plugins/imv_swid/imv_swid.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imv_swid_agent.h" + +static const char imv_name[] = "SWID"; +static const imv_agent_create_t imv_agent_create = imv_swid_agent_create; + +/* include generic TGC TNC IF-IMV API code below */ + +#include <imv/imv_if.h> + diff --git a/src/libimcv/plugins/imv_swid/imv_swid_agent.c b/src/libimcv/plugins/imv_swid/imv_swid_agent.c new file mode 100644 index 000000000..5bebf32c0 --- /dev/null +++ b/src/libimcv/plugins/imv_swid/imv_swid_agent.c @@ -0,0 +1,726 @@ +/* + * Copyright (C) 2013-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE +#include <stdio.h> + +#include "imv_swid_agent.h" +#include "imv_swid_state.h" +#include "imv_swid_rest.h" + +#include <imcv.h> +#include <imv/imv_agent.h> +#include <imv/imv_msg.h> +#include <ietf/ietf_attr_pa_tnc_error.h> +#include "tcg/seg/tcg_seg_attr_max_size.h" +#include "tcg/seg/tcg_seg_attr_seg_env.h" +#include "tcg/swid/tcg_swid_attr_req.h" +#include "tcg/swid/tcg_swid_attr_tag_inv.h" +#include "tcg/swid/tcg_swid_attr_tag_id_inv.h" +#include "swid/swid_error.h" +#include "swid/swid_inventory.h" + +#include <tncif_names.h> +#include <tncif_pa_subtypes.h> + +#include <pen/pen.h> +#include <utils/debug.h> +#include <bio/bio_reader.h> + +typedef struct private_imv_swid_agent_t private_imv_swid_agent_t; + +/* Subscribed PA-TNC message subtypes */ +static pen_type_t msg_types[] = { + { PEN_TCG, PA_SUBTYPE_TCG_SWID } +}; + +/** + * Flag set when corresponding attribute has been received + */ +enum imv_swid_attr_t { + IMV_SWID_ATTR_TAG_INV = (1<<0), + IMV_SWID_ATTR_TAG_ID_INV = (1<<1) +}; + +/** + * Private data of an imv_swid_agent_t object. + */ +struct private_imv_swid_agent_t { + + /** + * Public members of imv_swid_agent_t + */ + imv_agent_if_t public; + + /** + * IMV agent responsible for generic functions + */ + imv_agent_t *agent; + + /** + * REST API to strongTNC manager + */ + imv_swid_rest_t *rest_api; + +}; + +METHOD(imv_agent_if_t, bind_functions, TNC_Result, + private_imv_swid_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function) +{ + return this->agent->bind_functions(this->agent, bind_function); +} + +METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, + private_imv_swid_agent_t *this, TNC_ConnectionID id, + TNC_ConnectionState new_state) +{ + imv_state_t *state; + + switch (new_state) + { + case TNC_CONNECTION_STATE_CREATE: + state = imv_swid_state_create(id); + return this->agent->create_state(this->agent, state); + case TNC_CONNECTION_STATE_DELETE: + return this->agent->delete_state(this->agent, id); + default: + return this->agent->change_state(this->agent, id, new_state, NULL); + } +} + +/** + * Process a received message + */ +static TNC_Result receive_msg(private_imv_swid_agent_t *this, + imv_state_t *state, imv_msg_t *in_msg) +{ + imv_swid_state_t *swid_state; + imv_msg_t *out_msg; + enumerator_t *enumerator; + pa_tnc_attr_t *attr; + TNC_Result result; + bool fatal_error = FALSE; + + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imv_msg_create_as_reply(in_msg); + + /* parse received PA-TNC message and handle local and remote errors */ + result = in_msg->receive(in_msg, out_msg, &fatal_error); + if (result != TNC_RESULT_SUCCESS) + { + out_msg->destroy(out_msg); + return result; + } + + swid_state = (imv_swid_state_t*)state; + + /* analyze PA-TNC attributes */ + enumerator = in_msg->create_attribute_enumerator(in_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + uint32_t request_id = 0, last_eid, eid_epoch; + swid_inventory_t *inventory; + pen_type_t type; + + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR) + { + ietf_attr_pa_tnc_error_t *error_attr; + pen_type_t error_code; + chunk_t msg_info, description; + bio_reader_t *reader; + uint32_t max_attr_size; + bool success; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; + error_code = error_attr->get_error_code(error_attr); + + if (error_code.vendor_id == PEN_TCG) + { + fatal_error = TRUE; + msg_info = error_attr->get_msg_info(error_attr); + reader = bio_reader_create(msg_info); + success = reader->read_uint32(reader, &request_id); + + DBG1(DBG_IMV, "received TCG error '%N' for request %d", + swid_error_code_names, error_code.type, request_id); + if (!success) + { + reader->destroy(reader); + continue; + } + if (error_code.type == TCG_SWID_RESPONSE_TOO_LARGE) + { + if (!reader->read_uint32(reader, &max_attr_size)) + { + reader->destroy(reader); + continue; + } + DBG1(DBG_IMV, " maximum PA-TNC attribute size is %u bytes", + max_attr_size); + } + description = reader->peek(reader); + if (description.len) + { + DBG1(DBG_IMV, " description: %.*s", description.len, + description.ptr); + } + reader->destroy(reader); + } + } + else if (type.vendor_id != PEN_TCG) + { + continue; + } + + switch (type.type) + { + case TCG_SWID_TAG_ID_INVENTORY: + { + tcg_swid_attr_tag_id_inv_t *attr_cast; + uint32_t missing; + int tag_id_count; + + state->set_action_flags(state, IMV_SWID_ATTR_TAG_ID_INV); + + attr_cast = (tcg_swid_attr_tag_id_inv_t*)attr; + request_id = attr_cast->get_request_id(attr_cast); + last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch); + inventory = attr_cast->get_inventory(attr_cast); + tag_id_count = inventory->get_count(inventory); + missing = attr_cast->get_tag_id_count(attr_cast); + swid_state->set_missing(swid_state, missing); + + DBG2(DBG_IMV, "received SWID tag ID inventory with %d item%s " + "for request %d at eid %d of epoch 0x%08x, %d item%s to " + "follow", tag_id_count, (tag_id_count == 1) ? "" : "s", + request_id, last_eid, eid_epoch, missing, + (missing == 1) ? "" : "s"); + + if (request_id == swid_state->get_request_id(swid_state)) + { + swid_state->set_swid_inventory(swid_state, inventory); + swid_state->set_count(swid_state, tag_id_count, 0); + } + else + { + DBG1(DBG_IMV, "no workitem found for SWID tag ID inventory " + "with request ID %d", request_id); + } + attr_cast->clear_inventory(attr_cast); + break; + } + case TCG_SWID_TAG_INVENTORY: + { + tcg_swid_attr_tag_inv_t *attr_cast; + swid_tag_t *tag; + chunk_t tag_encoding; + json_object *jobj, *jarray, *jstring; + char *tag_str; + uint32_t missing; + int tag_count; + enumerator_t *e; + + state->set_action_flags(state, IMV_SWID_ATTR_TAG_INV); + + attr_cast = (tcg_swid_attr_tag_inv_t*)attr; + request_id = attr_cast->get_request_id(attr_cast); + last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch); + inventory = attr_cast->get_inventory(attr_cast); + tag_count = inventory->get_count(inventory); + missing = attr_cast->get_tag_count(attr_cast); + swid_state->set_missing(swid_state, missing); + + DBG2(DBG_IMV, "received SWID tag inventory with %d item%s for " + "request %d at eid %d of epoch 0x%08x, %d item%s to follow", + tag_count, (tag_count == 1) ? "" : "s", request_id, + last_eid, eid_epoch, missing, (missing == 1) ? "" : "s"); + + if (request_id == swid_state->get_request_id(swid_state)) + { + swid_state->set_count(swid_state, 0, tag_count); + + if (this->rest_api) + { + jobj = json_object_new_object(); + jarray = json_object_new_array(); + json_object_object_add(jobj, "data", jarray); + + e = inventory->create_enumerator(inventory); + while (e->enumerate(e, &tag)) + { + tag_encoding = tag->get_encoding(tag); + tag_str = strndup(tag_encoding.ptr, tag_encoding.len); + DBG3(DBG_IMV, "%s", tag_str); + jstring = json_object_new_string(tag_str); + json_object_array_add(jarray, jstring); + free(tag_str); + } + e->destroy(e); + + if (this->rest_api->post(this->rest_api, + "swid/add-tags/", jobj, NULL) != SUCCESS) + { + DBG1(DBG_IMV, "error in REST API add-tags request"); + } + json_object_put(jobj); + } + } + else + { + DBG1(DBG_IMV, "no workitem found for SWID tag inventory " + "with request ID %d", request_id); + } + attr_cast->clear_inventory(attr_cast); + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); + + if (fatal_error) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + result = out_msg->send_assessment(out_msg); + if (result == TNC_RESULT_SUCCESS) + { + result = this->agent->provide_recommendation(this->agent, state); + } + } + else + { + /* send PA-TNC message with the EXCL flag set */ + result = out_msg->send(out_msg, TRUE); + } + out_msg->destroy(out_msg); + + return result; +} + +METHOD(imv_agent_if_t, receive_message, TNC_Result, + private_imv_swid_agent_t *this, TNC_ConnectionID id, + TNC_MessageType msg_type, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; +} + +METHOD(imv_agent_if_t, receive_message_long, TNC_Result, + private_imv_swid_agent_t *this, TNC_ConnectionID id, + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, + TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg) +{ + imv_state_t *state; + imv_msg_t *in_msg; + TNC_Result result; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + in_msg = imv_msg_create_from_long_data(this->agent, state, id, + src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg); + result = receive_msg(this, state, in_msg); + in_msg->destroy(in_msg); + + return result; + +} + +METHOD(imv_agent_if_t, batch_ending, TNC_Result, + private_imv_swid_agent_t *this, TNC_ConnectionID id) +{ + imv_msg_t *out_msg; + imv_state_t *state; + imv_session_t *session; + imv_workitem_t *workitem; + imv_swid_state_t *swid_state; + imv_swid_handshake_state_t handshake_state; + pa_tnc_attr_t *attr; + TNC_IMVID imv_id; + TNC_Result result = TNC_RESULT_SUCCESS; + bool no_workitems = TRUE; + uint32_t request_id, received; + uint8_t flags; + enumerator_t *enumerator; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + swid_state = (imv_swid_state_t*)state; + handshake_state = swid_state->get_handshake_state(swid_state); + session = state->get_session(state); + imv_id = this->agent->get_id(this->agent); + + if (handshake_state == IMV_SWID_STATE_END) + { + return TNC_RESULT_SUCCESS; + } + + /* Create an empty out message - we might need it */ + out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY, + msg_types[0]); + + if (!imcv_db) + { + DBG2(DBG_IMV, "no workitems available - no evaluation possible"); + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + swid_state->set_handshake_state(swid_state, IMV_SWID_STATE_END); + + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + /* Look for SWID tag workitem and create SWID tag request */ + if (handshake_state == IMV_SWID_STATE_INIT && + session->get_policy_started(session)) + { + size_t max_attr_size = SWID_MAX_ATTR_SIZE; + size_t max_seg_size; + seg_contract_t *contract; + seg_contract_manager_t *contracts; + char buf[BUF_LEN]; + + enumerator = session->create_workitem_enumerator(session); + if (enumerator) + { + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY || + workitem->get_type(workitem) != IMV_WORKITEM_SWID_TAGS) + { + continue; + } + + flags = TCG_SWID_ATTR_REQ_FLAG_NONE; + if (strchr(workitem->get_arg_str(workitem), 'R')) + { + flags |= TCG_SWID_ATTR_REQ_FLAG_R; + } + if (strchr(workitem->get_arg_str(workitem), 'S')) + { + flags |= TCG_SWID_ATTR_REQ_FLAG_S; + } + if (strchr(workitem->get_arg_str(workitem), 'C')) + { + flags |= TCG_SWID_ATTR_REQ_FLAG_C; + } + + /* Determine maximum PA-TNC attribute segment size */ + max_seg_size = state->get_max_msg_len(state) + - PA_TNC_HEADER_SIZE + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_SEG_ENV_HEADER + - PA_TNC_ATTR_HEADER_SIZE + - TCG_SEG_ATTR_MAX_SIZE_SIZE; + + /* Announce support of PA-TNC segmentation to IMC */ + contract = seg_contract_create(msg_types[0], max_attr_size, + max_seg_size, TRUE, imv_id, FALSE); + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMV, "%s", buf); + contracts = state->get_contracts(state); + contracts->add_contract(contracts, contract); + attr = tcg_seg_attr_max_size_create(max_attr_size, + max_seg_size, TRUE); + out_msg->add_attribute(out_msg, attr); + + /* Issue a SWID request */ + request_id = workitem->get_id(workitem); + swid_state->set_request_id(swid_state, request_id); + attr = tcg_swid_attr_req_create(flags, request_id, 0); + out_msg->add_attribute(out_msg, attr); + workitem->set_imv_id(workitem, imv_id); + no_workitems = FALSE; + DBG2(DBG_IMV, "IMV %d issues SWID request %d", + imv_id, request_id); + break; + } + enumerator->destroy(enumerator); + + if (no_workitems) + { + DBG2(DBG_IMV, "IMV %d has no workitems - " + "no evaluation requested", imv_id); + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + } + handshake_state = IMV_SWID_STATE_WORKITEMS; + swid_state->set_handshake_state(swid_state, handshake_state); + } + } + + received = state->get_action_flags(state); + + if (handshake_state == IMV_SWID_STATE_WORKITEMS && + (received & (IMV_SWID_ATTR_TAG_INV|IMV_SWID_ATTR_TAG_ID_INV)) && + swid_state->get_missing(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; + 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; + } + + /* Create a TCG SWID Request attribute */ + 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"); + swid_state->set_missing(swid_state, tag_id_count); + + 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); + cast_attr = (tcg_swid_attr_req_t*)attr; + cast_attr->add_target(cast_attr, tag_id); + } + json_object_put(jresponse); + + out_msg->add_attribute(out_msg, attr); + break; + case FAILED: + default: + break; + } + + if (status == FAILED) + { + enumerator = session->create_workitem_enumerator(session); + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS) + { + session->remove_workitem(session, enumerator); + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + rec = workitem->set_result(workitem, error_str, eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, workitem); + workitem->destroy(workitem); + break; + } + } + enumerator->destroy(enumerator); + } + } + + /* finalized all workitems ? */ + if (handshake_state == IMV_SWID_STATE_WORKITEMS && + session->get_workitem_count(session, imv_id) == 0) + { + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + swid_state->set_handshake_state(swid_state, IMV_SWID_STATE_END); + + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + /* send non-empty PA-TNC message with excl flag not set */ + if (out_msg->get_attribute_count(out_msg)) + { + result = out_msg->send(out_msg, FALSE); + } + out_msg->destroy(out_msg); + + return result; +} + +METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, + private_imv_swid_agent_t *this, TNC_ConnectionID id) +{ + imv_state_t *state; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + return this->agent->provide_recommendation(this->agent, state); +} + +METHOD(imv_agent_if_t, destroy, void, + private_imv_swid_agent_t *this) +{ + DESTROY_IF(this->rest_api); + this->agent->destroy(this->agent); + free(this); +} + +/** + * Described in header. + */ +imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id, + TNC_Version *actual_version) +{ + private_imv_swid_agent_t *this; + imv_agent_t *agent; + char *rest_api_uri; + u_int rest_api_timeout; + + agent = imv_agent_create(name, msg_types, countof(msg_types), id, + actual_version); + if (!agent) + { + return NULL; + } + agent->add_non_fatal_attr_type(agent, + pen_type_create(PEN_TCG, TCG_SEG_MAX_ATTR_SIZE_REQ)); + + INIT(this, + .public = { + .bind_functions = _bind_functions, + .notify_connection_change = _notify_connection_change, + .receive_message = _receive_message, + .receive_message_long = _receive_message_long, + .batch_ending = _batch_ending, + .solicit_recommendation = _solicit_recommendation, + .destroy = _destroy, + }, + .agent = agent, + ); + + rest_api_uri = lib->settings->get_str(lib->settings, + "%s.plugins.imv-swid.rest_api_uri", NULL, lib->ns); + rest_api_timeout = lib->settings->get_int(lib->settings, + "%s.plugins.imv-swid.rest_api_timeout", 120, lib->ns); + if (rest_api_uri) + { + this->rest_api = imv_swid_rest_create(rest_api_uri, rest_api_timeout); + } + + return &this->public; +} + diff --git a/src/libimcv/plugins/imv_swid/imv_swid_agent.h b/src/libimcv/plugins/imv_swid/imv_swid_agent.h new file mode 100644 index 000000000..4218040bc --- /dev/null +++ b/src/libimcv/plugins/imv_swid/imv_swid_agent.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imv_swid_agent_t imv_swid_agent + * @{ @ingroup imv_swid + */ + +#ifndef IMV_SWID_AGENT_H_ +#define IMV_SWID_AGENT_H_ + +#include <imv/imv_agent_if.h> + +/** + * Creates an SWID IMV agent + * + * @param name Name of the IMV + * @param id ID of the IMV + * @param actual_version TNC IF-IMV version + */ +imv_agent_if_t* imv_swid_agent_create(const char* name, TNC_IMVID id, + TNC_Version *actual_version); + +#endif /** IMV_SWID_AGENT_H_ @}*/ diff --git a/src/libimcv/plugins/imv_swid/imv_swid_rest.c b/src/libimcv/plugins/imv_swid/imv_swid_rest.c new file mode 100644 index 000000000..143b0b239 --- /dev/null +++ b/src/libimcv/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/libimcv/plugins/imv_swid/imv_swid_rest.h b/src/libimcv/plugins/imv_swid/imv_swid_rest.h new file mode 100644 index 000000000..32392cbe6 --- /dev/null +++ b/src/libimcv/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.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/libimcv/plugins/imv_swid/imv_swid_state.c b/src/libimcv/plugins/imv_swid/imv_swid_state.c new file mode 100644 index 000000000..04364b030 --- /dev/null +++ b/src/libimcv/plugins/imv_swid/imv_swid_state.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2013-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imv_swid_state.h" + +#include <imv/imv_lang_string.h> +#include <imv/imv_reason_string.h> +#include <imv/imv_remediation_string.h> +#include <swid/swid_tag_id.h> + +#include <tncif_policy.h> + +#include <utils/lexparser.h> +#include <utils/debug.h> + +typedef struct private_imv_swid_state_t private_imv_swid_state_t; + +/** + * Private data of an imv_swid_state_t object. + */ +struct private_imv_swid_state_t { + + /** + * Public members of imv_swid_state_t + */ + imv_swid_state_t public; + + /** + * TNCCS connection ID + */ + TNC_ConnectionID connection_id; + + /** + * TNCCS connection state + */ + TNC_ConnectionState state; + + /** + * Does the TNCCS connection support long message types? + */ + bool has_long; + + /** + * Does the TNCCS connection support exclusive delivery? + */ + bool has_excl; + + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + uint32_t max_msg_len; + + /** + * Flags set for completed actions + */ + uint32_t action_flags; + + /** + * IMV database session associated with TNCCS connection + */ + imv_session_t *session; + + /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** + * IMV action recommendation + */ + TNC_IMV_Action_Recommendation rec; + + /** + * IMV evaluation result + */ + TNC_IMV_Evaluation_Result eval; + + /** + * IMV Scanner handshake state + */ + imv_swid_handshake_state_t handshake_state; + + /** + * TNC Reason String + */ + imv_reason_string_t *reason_string; + + /** + * IETF Remediation Instructions String + */ + imv_remediation_string_t *remediation_string; + + /** + * SWID Tag Request ID + */ + uint32_t request_id; + + /** + * Number of processed SWID Tag IDs + */ + int tag_id_count; + + /** + * Number of processed SWID Tags + */ + int tag_count; + + /** + * Number of missing SWID Tags or Tag IDs + */ + uint32_t missing; + + /** + * Top level JSON object + */ + json_object *jobj; + + /** + * JSON array containing an inventory of SWID Tag IDs + */ + json_object *jarray; + +}; + +METHOD(imv_state_t, get_connection_id, TNC_ConnectionID, + private_imv_swid_state_t *this) +{ + return this->connection_id; +} + +METHOD(imv_state_t, has_long, bool, + private_imv_swid_state_t *this) +{ + return this->has_long; +} + +METHOD(imv_state_t, has_excl, bool, + private_imv_swid_state_t *this) +{ + return this->has_excl; +} + +METHOD(imv_state_t, set_flags, void, + private_imv_swid_state_t *this, bool has_long, bool has_excl) +{ + this->has_long = has_long; + this->has_excl = has_excl; +} + +METHOD(imv_state_t, set_max_msg_len, void, + private_imv_swid_state_t *this, uint32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imv_state_t, get_max_msg_len, uint32_t, + private_imv_swid_state_t *this) +{ + return this->max_msg_len; +} + +METHOD(imv_state_t, set_action_flags, void, + private_imv_swid_state_t *this, uint32_t flags) +{ + this->action_flags |= flags; +} + +METHOD(imv_state_t, get_action_flags, uint32_t, + private_imv_swid_state_t *this) +{ + return this->action_flags; +} + +METHOD(imv_state_t, set_session, void, + private_imv_swid_state_t *this, imv_session_t *session) +{ + this->session = session; +} + +METHOD(imv_state_t, get_session, imv_session_t*, + private_imv_swid_state_t *this) +{ + return this->session; +} + +METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, + private_imv_swid_state_t *this) +{ + return this->contracts; +} + +METHOD(imv_state_t, change_state, void, + private_imv_swid_state_t *this, TNC_ConnectionState new_state) +{ + this->state = new_state; +} + +METHOD(imv_state_t, get_recommendation, void, + private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation *rec, + TNC_IMV_Evaluation_Result *eval) +{ + *rec = this->rec; + *eval = this->eval; +} + +METHOD(imv_state_t, set_recommendation, void, + private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval) +{ + this->rec = rec; + this->eval = eval; +} + +METHOD(imv_state_t, update_recommendation, void, + private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation rec, + TNC_IMV_Evaluation_Result eval) +{ + this->rec = tncif_policy_update_recommendation(this->rec, rec); + this->eval = tncif_policy_update_evaluation(this->eval, eval); +} + +METHOD(imv_state_t, get_reason_string, bool, + private_imv_swid_state_t *this, enumerator_t *language_enumerator, + chunk_t *reason_string, char **reason_language) +{ + return FALSE; +} + +METHOD(imv_state_t, get_remediation_instructions, bool, + private_imv_swid_state_t *this, enumerator_t *language_enumerator, + chunk_t *string, char **lang_code, char **uri) +{ + return FALSE; +} + +METHOD(imv_state_t, destroy, void, + private_imv_swid_state_t *this) +{ + json_object_put(this->jobj); + DESTROY_IF(this->session); + DESTROY_IF(this->reason_string); + DESTROY_IF(this->remediation_string); + this->contracts->destroy(this->contracts); + free(this); +} + +METHOD(imv_swid_state_t, set_handshake_state, void, + private_imv_swid_state_t *this, imv_swid_handshake_state_t new_state) +{ + this->handshake_state = new_state; +} + +METHOD(imv_swid_state_t, get_handshake_state, imv_swid_handshake_state_t, + private_imv_swid_state_t *this) +{ + return this->handshake_state; +} + +METHOD(imv_swid_state_t, set_request_id, void, + private_imv_swid_state_t *this, uint32_t request_id) +{ + this->request_id = request_id; +} + +METHOD(imv_swid_state_t, get_request_id, uint32_t, + private_imv_swid_state_t *this) +{ + return this->request_id; +} + +METHOD(imv_swid_state_t, set_swid_inventory, void, + private_imv_swid_state_t *this, swid_inventory_t *inventory) +{ + chunk_t tag_creator, unique_sw_id; + char software_id[256]; + json_object *jstring; + swid_tag_id_t *tag_id; + enumerator_t *enumerator; + + enumerator = inventory->create_enumerator(inventory); + while (enumerator->enumerate(enumerator, &tag_id)) + { + /* Construct software ID from tag creator and unique software ID */ + tag_creator = tag_id->get_tag_creator(tag_id); + unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL); + snprintf(software_id, 256, "%.*s_%.*s", + tag_creator.len, tag_creator.ptr, + unique_sw_id.len, unique_sw_id.ptr); + DBG3(DBG_IMV, " %s", software_id); + + /* Add software ID to JSON array */ + jstring = json_object_new_string(software_id); + json_object_array_add(this->jarray, jstring); + } + enumerator->destroy(enumerator); +} + +METHOD(imv_swid_state_t, get_swid_inventory, json_object*, + private_imv_swid_state_t *this) +{ + return this->jobj; +} + +METHOD(imv_swid_state_t, set_missing, void, + private_imv_swid_state_t *this, uint32_t count) +{ + this->missing = count; +} + +METHOD(imv_swid_state_t, get_missing, uint32_t, + private_imv_swid_state_t *this) +{ + return this->missing; +} + +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; + } +} + +/** + * Described in header. + */ +imv_state_t *imv_swid_state_create(TNC_ConnectionID connection_id) +{ + private_imv_swid_state_t *this; + + INIT(this, + .public = { + .interface = { + .get_connection_id = _get_connection_id, + .has_long = _has_long, + .has_excl = _has_excl, + .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, + .set_action_flags = _set_action_flags, + .get_action_flags = _get_action_flags, + .set_session = _set_session, + .get_session= _get_session, + .get_contracts = _get_contracts, + .change_state = _change_state, + .get_recommendation = _get_recommendation, + .set_recommendation = _set_recommendation, + .update_recommendation = _update_recommendation, + .get_reason_string = _get_reason_string, + .get_remediation_instructions = _get_remediation_instructions, + .destroy = _destroy, + }, + .set_handshake_state = _set_handshake_state, + .get_handshake_state = _get_handshake_state, + .set_request_id = _set_request_id, + .get_request_id = _get_request_id, + .set_swid_inventory = _set_swid_inventory, + .get_swid_inventory = _get_swid_inventory, + .set_missing = _set_missing, + .get_missing = _get_missing, + .set_count = _set_count, + .get_count = _get_count, + }, + .state = TNC_CONNECTION_STATE_CREATE, + .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, + .connection_id = connection_id, + .contracts = seg_contract_manager_create(), + .jobj = json_object_new_object(), + .jarray = json_object_new_array(), + ); + + json_object_object_add(this->jobj, "data", this->jarray); + + return &this->public.interface; +} + + diff --git a/src/libimcv/plugins/imv_swid/imv_swid_state.h b/src/libimcv/plugins/imv_swid/imv_swid_state.h new file mode 100644 index 000000000..af5d95c9d --- /dev/null +++ b/src/libimcv/plugins/imv_swid/imv_swid_state.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2013-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup imv_swid imv_swid + * @ingroup libimcv_plugins + * + * @defgroup imv_swid_state_t imv_swid_state + * @{ @ingroup imv_swid + */ + +#ifndef IMV_SWID_STATE_H_ +#define IMV_SWID_STATE_H_ + +#include <imv/imv_state.h> +#include <swid/swid_inventory.h> +#include <library.h> + +#include <json.h> + +typedef struct imv_swid_state_t imv_swid_state_t; +typedef enum imv_swid_handshake_state_t imv_swid_handshake_state_t; + +/** + * IMV OS Handshake States (state machine) + */ +enum imv_swid_handshake_state_t { + IMV_SWID_STATE_INIT, + IMV_SWID_STATE_WORKITEMS, + IMV_SWID_STATE_END +}; + +/** + * Internal state of an imv_swid_t connection instance + */ +struct imv_swid_state_t { + + /** + * imv_state_t interface + */ + imv_state_t interface; + + /** + * Set state of the handshake + * + * @param new_state the handshake state of IMV + */ + void (*set_handshake_state)(imv_swid_state_t *this, + imv_swid_handshake_state_t new_state); + + /** + * Get state of the handshake + * + * @return the handshake state of IMV + */ + imv_swid_handshake_state_t (*get_handshake_state)(imv_swid_state_t *this); + + /** + * Set the SWID request ID + * + * @param request_id SWID request ID to be set + */ + void (*set_request_id)(imv_swid_state_t *this, uint32_t request_id); + + /** + * Get the SWID request ID + * + * @return SWID request ID + */ + uint32_t (*get_request_id)(imv_swid_state_t *this); + + /** + * Set or extend the SWID Tag ID inventory in the state + * + * @param inventory SWID Tags ID inventory to be added + */ + void (*set_swid_inventory)(imv_swid_state_t *this, swid_inventory_t *inventory); + + /** + * Get the encoding of the complete SWID Tag ID inventory + * + * @return SWID Tags ID inventory as a JSON array + */ + json_object* (*get_swid_inventory)(imv_swid_state_t *this); + + /** + * Set the number of still missing SWID Tags or Tag IDs + * + * @param count Number of missing SWID Tags or Tag IDs + */ + void (*set_missing)(imv_swid_state_t *this, uint32_t count); + + /** + * Get the number of still missing SWID Tags or Tag IDs + * + * @result Number of missing SWID Tags or Tag IDs + */ + uint32_t (*get_missing)(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); +}; + +/** + * Create an imv_swid_state_t instance + * + * @param id connection ID + */ +imv_state_t* imv_swid_state_create(TNC_ConnectionID id); + +#endif /** IMV_SWID_STATE_H_ @}*/ diff --git a/src/libimcv/plugins/imv_test/Makefile.in b/src/libimcv/plugins/imv_test/Makefile.in index 5ac6a8f7b..66da75a1e 100644 --- a/src/libimcv/plugins/imv_test/Makefile.in +++ b/src/libimcv/plugins/imv_test/Makefile.in @@ -231,6 +231,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ GPRBUILD = @GPRBUILD@ @@ -291,6 +292,7 @@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ +RUBYGEMDIR = @RUBYGEMDIR@ RUBYINCLUDE = @RUBYINCLUDE@ RUBYLIB = @RUBYLIB@ SED = @SED@ @@ -356,6 +358,8 @@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ +json_CFLAGS = @json_CFLAGS@ +json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -403,6 +407,10 @@ strongswan_conf = @strongswan_conf@ strongswan_options = @strongswan_options@ swanctldir = @swanctldir@ sysconfdir = @sysconfdir@ +systemd_daemon_CFLAGS = @systemd_daemon_CFLAGS@ +systemd_daemon_LIBS = @systemd_daemon_LIBS@ +systemd_journal_CFLAGS = @systemd_journal_CFLAGS@ +systemd_journal_LIBS = @systemd_journal_LIBS@ systemdsystemunitdir = @systemdsystemunitdir@ t_plugins = @t_plugins@ target_alias = @target_alias@ diff --git a/src/libimcv/plugins/imv_test/imv_test_agent.c b/src/libimcv/plugins/imv_test/imv_test_agent.c index 42630003b..5e4b4866a 100644 --- a/src/libimcv/plugins/imv_test/imv_test_agent.c +++ b/src/libimcv/plugins/imv_test/imv_test_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 @@ -94,10 +94,14 @@ static TNC_Result receive_msg(private_imv_test_agent_t *this, imv_state_t *state int rounds; bool fatal_error = FALSE, received_command = FALSE, retry = FALSE; + /* generate an outgoing PA-TNC message - we might need it */ + out_msg = imv_msg_create_as_reply(in_msg); + /* parse received PA-TNC message and handle local and remote errors */ - result = in_msg->receive(in_msg, &fatal_error); + result = in_msg->receive(in_msg, out_msg, &fatal_error); if (result != TNC_RESULT_SUCCESS) { + out_msg->destroy(out_msg); return result; } @@ -172,14 +176,12 @@ static TNC_Result receive_msg(private_imv_test_agent_t *this, imv_state_t *state state->set_recommendation(state, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, TNC_IMV_EVALUATION_RESULT_ERROR); - out_msg = imv_msg_create_as_reply(in_msg); result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) + if (result == TNC_RESULT_SUCCESS) { - return result; + result = this->agent->provide_recommendation(this->agent, state); } - return this->agent->provide_recommendation(this->agent, state); + return result; } /* request a handshake retry ? */ @@ -195,7 +197,6 @@ static TNC_Result receive_msg(private_imv_test_agent_t *this, imv_state_t *state /* repeat the measurement ? */ if (test_state->another_round(test_state, in_msg->get_src_id(in_msg))) { - out_msg = imv_msg_create_as_reply(in_msg); attr = ita_attr_command_create("repeat"); out_msg->add_attribute(out_msg, attr); @@ -208,19 +209,20 @@ static TNC_Result receive_msg(private_imv_test_agent_t *this, imv_state_t *state if (received_command) { - out_msg = imv_msg_create_as_reply(in_msg); result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) + if (result == TNC_RESULT_SUCCESS) { - return result; + result = this->agent->provide_recommendation(this->agent, state); } - return this->agent->provide_recommendation(this->agent, state); } else { - return TNC_RESULT_SUCCESS; + /* send PA-TNC message with the EXCL flag set */ + result = out_msg->send(out_msg, TRUE); } + out_msg->destroy(out_msg); + + return result; } METHOD(imv_agent_if_t, receive_message, TNC_Result, diff --git a/src/libimcv/plugins/imv_test/imv_test_state.c b/src/libimcv/plugins/imv_test/imv_test_state.c index 3564456a8..c20d00bd1 100644 --- a/src/libimcv/plugins/imv_test/imv_test_state.c +++ b/src/libimcv/plugins/imv_test/imv_test_state.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 @@ -66,6 +66,11 @@ struct private_imv_test_state_t { imv_session_t *session; /** + * PA-TNC attribute segmentation contracts associated with TNCCS connection + */ + seg_contract_manager_t *contracts; + + /** * IMV action recommendation */ TNC_IMV_Action_Recommendation rec; @@ -162,6 +167,12 @@ METHOD(imv_state_t, get_session, imv_session_t*, return this->session; } +METHOD(imv_state_t, get_contracts, seg_contract_manager_t*, + private_imv_test_state_t *this) +{ + return this->contracts; +} + METHOD(imv_state_t, change_state, void, private_imv_test_state_t *this, TNC_ConnectionState new_state) { @@ -220,6 +231,7 @@ METHOD(imv_state_t, destroy, void, { DESTROY_IF(this->session); DESTROY_IF(this->reason_string); + this->contracts->destroy(this->contracts); this->imcs->destroy_function(this->imcs, free); free(this); } @@ -307,6 +319,7 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id) .get_max_msg_len = _get_max_msg_len, .set_session = _set_session, .get_session = _get_session, + .get_contracts = _get_contracts, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, @@ -323,6 +336,7 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id) .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, + .contracts = seg_contract_manager_create(), .imcs = linked_list_create(), ); |