Merged libpts into libimcv

This commit is contained in:
Andreas Steffen
2014-10-05 12:55:37 +02:00
parent c4d0987609
commit d6fb2cc6e3
159 changed files with 232 additions and 439 deletions
@@ -0,0 +1,18 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
imcv_LTLIBRARIES = imc-attestation.la
imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imc_attestation_la_SOURCES = imc_attestation.c \
imc_attestation_state.h imc_attestation_state.c \
imc_attestation_process.h imc_attestation_process.c
imc_attestation_la_LDFLAGS = -module -avoid-version -no-undefined
@@ -0,0 +1,335 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_attestation_state.h"
#include "imc_attestation_process.h"
#include <imc/imc_agent.h>
#include <imc/imc_msg.h>
#include <ietf/ietf_attr.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <ietf/ietf_attr_product_info.h>
#include <ietf/ietf_attr_string_version.h>
#include <ietf/ietf_attr_assess_result.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <os_info/os_info.h>
#include <pts/pts_error.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <collections/linked_list.h>
/* IMC definitions */
static const char imc_name[] = "Attestation";
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_PTS }
};
static imc_agent_t *imc_attestation;
/**
* Supported PTS measurement algorithms
*/
static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE;
/**
* Supported PTS Diffie Hellman Groups
*/
static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
/**
* see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_Initialize(TNC_IMCID imc_id,
TNC_Version min_version,
TNC_Version max_version,
TNC_Version *actual_version)
{
bool mandatory_dh_groups;
if (imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
return TNC_RESULT_ALREADY_INITIALIZED;
}
imc_attestation = imc_agent_create(imc_name, msg_types, countof(msg_types),
imc_id, actual_version);
if (!imc_attestation)
{
return TNC_RESULT_FATAL;
}
mandatory_dh_groups = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-attestation.mandatory_dh_groups", TRUE, lib->ns);
if (!pts_meas_algo_probe(&supported_algorithms) ||
!pts_dh_group_probe(&supported_dh_groups, mandatory_dh_groups))
{
imc_attestation->destroy(imc_attestation);
imc_attestation = NULL;
return TNC_RESULT_FATAL;
}
if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
{
DBG1(DBG_IMC, "no common IF-IMC version");
return TNC_RESULT_NO_COMMON_VERSION;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imc_state_t *state;
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imc_attestation_state_create(connection_id);
return imc_attestation->create_state(imc_attestation, state);
case TNC_CONNECTION_STATE_HANDSHAKE:
if (imc_attestation->change_state(imc_attestation, connection_id,
new_state, &state) != TNC_RESULT_SUCCESS)
{
return TNC_RESULT_FATAL;
}
state->set_result(state, imc_id,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_attestation->delete_state(imc_attestation, connection_id);
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
default:
return imc_attestation->change_state(imc_attestation, connection_id,
new_state, NULL);
}
}
/**
* see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
{
imc_msg_t *out_msg;
imc_attestation_state_t *attestation_state;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
pen_type_t type;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imc_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
type = attr->get_type(attr);
if (type.vendor_id == PEN_IETF)
{
if (type.type == IETF_ATTR_PA_TNC_ERROR)
{
ietf_attr_pa_tnc_error_t *error_attr;
pen_type_t error_code;
chunk_t msg_info;
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
error_code = error_attr->get_error_code(error_attr);
if (error_code.vendor_id == PEN_TCG)
{
msg_info = error_attr->get_msg_info(error_attr);
DBG1(DBG_IMC, "received TCG-PTS error '%N'",
pts_error_code_names, error_code.type);
DBG1(DBG_IMC, "error information: %B", &msg_info);
result = TNC_RESULT_FATAL;
}
}
}
else if (type.vendor_id == PEN_TCG)
{
attestation_state = (imc_attestation_state_t*)state;
if (!imc_attestation_process(attr, out_msg, attestation_state,
supported_algorithms, supported_dh_groups))
{
result = TNC_RESULT_FATAL;
break;
}
}
}
enumerator->destroy(enumerator);
if (result == TNC_RESULT_SUCCESS)
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
/**
* see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_data(imc_attestation, state, connection_id,
msg_type, chunk_create(msg, msg_len));
result = receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_VendorID msg_vid,
TNC_MessageSubtype msg_subtype,
TNC_UInt32 src_imv_id,
TNC_UInt32 dst_imc_id)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_long_data(imc_attestation, state, connection_id,
src_imv_id, dst_imc_id, msg_vid, msg_subtype,
chunk_create(msg, msg_len));
result =receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_BatchEnding(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_Terminate(TNC_IMCID imc_id)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
imc_attestation->destroy(imc_attestation);
imc_attestation = NULL;
return TNC_RESULT_SUCCESS;
}
/**
* see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_API TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
{
if (!imc_attestation)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return imc_attestation->bind_functions(imc_attestation, bind_function);
}
@@ -0,0 +1,476 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#define _GNU_SOURCE
#include <stdio.h>
/* for isdigit */
#include <ctype.h>
#include "imc_attestation_process.h"
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <pts/pts.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h>
#include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_get_aik.h>
#include <tcg/pts/tcg_pts_attr_aik.h>
#include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
#include <tcg/pts/tcg_pts_attr_simple_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_simple_evid_final.h>
#include <tcg/pts/tcg_pts_attr_req_file_meas.h>
#include <tcg/pts/tcg_pts_attr_file_meas.h>
#include <tcg/pts/tcg_pts_attr_req_file_meta.h>
#include <tcg/pts/tcg_pts_attr_unix_file_meta.h>
#include <utils/debug.h>
#include <utils/lexparser.h>
#define DEFAULT_NONCE_LEN 20
bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
imc_attestation_state_t *attestation_state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups)
{
chunk_t attr_info;
pts_t *pts;
pts_error_code_t pts_error;
pen_type_t attr_type;
bool valid_path;
pts = attestation_state->get_pts(attestation_state);
attr_type = attr->get_type(attr);
switch (attr_type.type)
{
case TCG_PTS_REQ_PROTO_CAPS:
{
tcg_pts_attr_proto_caps_t *attr_cast;
pts_proto_caps_flag_t imc_caps, imv_caps;
attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
imv_caps = attr_cast->get_flags(attr_cast);
imc_caps = pts->get_proto_caps(pts);
pts->set_proto_caps(pts, imc_caps & imv_caps);
/* Send PTS Protocol Capabilities attribute */
attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps, FALSE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_MEAS_ALGO:
{
tcg_pts_attr_meas_algo_t *attr_cast;
pts_meas_algorithms_t offered_algorithms, selected_algorithm;
attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
offered_algorithms = attr_cast->get_algorithms(attr_cast);
selected_algorithm = pts_meas_algo_select(supported_algorithms,
offered_algorithms);
if (selected_algorithm == PTS_MEAS_ALGO_NONE)
{
attr = pts_hash_alg_error_create(supported_algorithms);
msg->add_attribute(msg, attr);
break;
}
/* Send Measurement Algorithm Selection attribute */
pts->set_meas_algorithm(pts, selected_algorithm);
attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_DH_NONCE_PARAMS_REQ:
{
tcg_pts_attr_dh_nonce_params_req_t *attr_cast;
pts_dh_group_t offered_dh_groups, selected_dh_group;
chunk_t responder_value, responder_nonce;
int nonce_len, min_nonce_len;
nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imc-attestation.nonce_len",
DEFAULT_NONCE_LEN, lib->ns);
attr_cast = (tcg_pts_attr_dh_nonce_params_req_t*)attr;
min_nonce_len = attr_cast->get_min_nonce_len(attr_cast);
if (nonce_len < PTS_MIN_NONCE_LEN ||
(min_nonce_len > 0 && nonce_len < min_nonce_len))
{
attr = pts_dh_nonce_error_create(nonce_len, PTS_MAX_NONCE_LEN);
msg->add_attribute(msg, attr);
break;
}
offered_dh_groups = attr_cast->get_dh_groups(attr_cast);
selected_dh_group = pts_dh_group_select(supported_dh_groups,
offered_dh_groups);
if (selected_dh_group == PTS_DH_GROUP_NONE)
{
attr = pts_dh_group_error_create(supported_dh_groups);
msg->add_attribute(msg, attr);
break;
}
/* Create own DH factor and nonce */
if (!pts->create_dh_nonce(pts, selected_dh_group, nonce_len))
{
return FALSE;
}
pts->get_my_public_value(pts, &responder_value, &responder_nonce);
/* Send DH Nonce Parameters Response attribute */
attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group,
supported_algorithms, responder_nonce, responder_value);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_DH_NONCE_FINISH:
{
tcg_pts_attr_dh_nonce_finish_t *attr_cast;
pts_meas_algorithms_t selected_algorithm;
chunk_t initiator_nonce, initiator_value;
int nonce_len;
attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr;
selected_algorithm = attr_cast->get_hash_algo(attr_cast);
if (!(selected_algorithm & supported_algorithms))
{
DBG1(DBG_IMC, "PTS-IMV selected unsupported DH hash algorithm");
return FALSE;
}
pts->set_dh_hash_algorithm(pts, selected_algorithm);
initiator_value = attr_cast->get_initiator_value(attr_cast);
initiator_nonce = attr_cast->get_initiator_nonce(attr_cast);
nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imc-attestation.nonce_len",
DEFAULT_NONCE_LEN, lib->ns);
if (nonce_len != initiator_nonce.len)
{
DBG1(DBG_IMC, "initiator and responder DH nonces "
"have differing lengths");
return FALSE;
}
pts->set_peer_public_value(pts, initiator_value, initiator_nonce);
if (!pts->calculate_secret(pts))
{
return FALSE;
}
break;
}
case TCG_PTS_GET_TPM_VERSION_INFO:
{
chunk_t tpm_version_info, attr_info;
pen_type_t error_code = { PEN_TCG, TCG_PTS_TPM_VERS_NOT_SUPPORTED };
if (!pts->get_tpm_version_info(pts, &tpm_version_info))
{
attr_info = attr->get_value(attr);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
/* Send TPM Version Info attribute */
attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_GET_AIK:
{
certificate_t *aik;
aik = pts->get_aik(pts);
if (!aik)
{
DBG1(DBG_IMC, "no AIK certificate or public key available");
break;
}
/* Send AIK attribute */
attr = tcg_pts_attr_aik_create(aik);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_REQ_FILE_MEAS:
{
tcg_pts_attr_req_file_meas_t *attr_cast;
char *pathname;
u_int16_t request_id;
bool is_directory;
u_int32_t delimiter;
pts_file_meas_t *measurements;
pen_type_t error_code;
attr_info = attr->get_value(attr);
attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
is_directory = attr_cast->get_directory_flag(attr_cast);
request_id = attr_cast->get_request_id(attr_cast);
delimiter = attr_cast->get_delimiter(attr_cast);
pathname = attr_cast->get_pathname(attr_cast);
valid_path = pts->is_path_valid(pts, pathname, &pts_error);
if (valid_path && pts_error)
{
error_code = pen_type_create(PEN_TCG, pts_error);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
else if (!valid_path)
{
break;
}
if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_INVALID_DELIMITER);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
/* Do PTS File Measurements and send them to PTS-IMV */
DBG2(DBG_IMC, "measurement request %d for %s '%s'",
request_id, is_directory ? "directory" : "file",
pathname);
measurements = pts_file_meas_create_from_path(request_id,
pathname, is_directory, TRUE,
pts->get_meas_algorithm(pts));
if (!measurements)
{
/* TODO handle error codes from measurements */
return FALSE;
}
attr = tcg_pts_attr_file_meas_create(measurements);
attr->set_noskip_flag(attr, TRUE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_REQ_FILE_META:
{
tcg_pts_attr_req_file_meta_t *attr_cast;
char *pathname;
bool is_directory;
u_int8_t delimiter;
pts_file_meta_t *metadata;
pen_type_t error_code;
attr_info = attr->get_value(attr);
attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
is_directory = attr_cast->get_directory_flag(attr_cast);
delimiter = attr_cast->get_delimiter(attr_cast);
pathname = attr_cast->get_pathname(attr_cast);
valid_path = pts->is_path_valid(pts, pathname, &pts_error);
if (valid_path && pts_error)
{
error_code = pen_type_create(PEN_TCG, pts_error);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
else if (!valid_path)
{
break;
}
if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_INVALID_DELIMITER);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
/* Get File Metadata and send them to PTS-IMV */
DBG2(DBG_IMC, "metadata request for %s '%s'",
is_directory ? "directory" : "file",
pathname);
metadata = pts->get_metadata(pts, pathname, is_directory);
if (!metadata)
{
/* TODO handle error codes from measurements */
return FALSE;
}
attr = tcg_pts_attr_unix_file_meta_create(metadata);
attr->set_noskip_flag(attr, TRUE);
msg->add_attribute(msg, attr);
break;
}
case TCG_PTS_REQ_FUNC_COMP_EVID:
{
tcg_pts_attr_req_func_comp_evid_t *attr_cast;
pts_proto_caps_flag_t negotiated_caps;
pts_comp_func_name_t *name;
pts_comp_evidence_t *evid;
pts_component_t *comp;
pen_type_t error_code;
u_int32_t depth;
u_int8_t flags;
status_t status;
enumerator_t *e;
attr_info = attr->get_value(attr);
attr_cast = (tcg_pts_attr_req_func_comp_evid_t*)attr;
DBG1(DBG_IMC, "evidence requested for %d functional components",
attr_cast->get_count(attr_cast));
e = attr_cast->create_enumerator(attr_cast);
while (e->enumerate(e, &flags, &depth, &name))
{
name->log(name, "* ");
negotiated_caps = pts->get_proto_caps(pts);
if (flags & PTS_REQ_FUNC_COMP_EVID_TTC)
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_DET_TTC);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (flags & PTS_REQ_FUNC_COMP_EVID_VER &&
!(negotiated_caps & PTS_PROTO_CAPS_V))
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_LOCAL_VAL);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (flags & PTS_REQ_FUNC_COMP_EVID_CURR &&
!(negotiated_caps & PTS_PROTO_CAPS_C))
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_CUR_EVID);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (flags & PTS_REQ_FUNC_COMP_EVID_PCR &&
!(negotiated_caps & PTS_PROTO_CAPS_T))
{
error_code = pen_type_create(PEN_TCG,
TCG_PTS_UNABLE_DET_PCR);
attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
msg->add_attribute(msg, attr);
break;
}
if (depth > 0)
{
DBG1(DBG_IMC, "the Attestation IMC currently does not "
"support sub component measurements");
return FALSE;
}
comp = attestation_state->create_component(attestation_state,
name, depth);
if (!comp)
{
DBG2(DBG_IMC, " not registered: no evidence provided");
continue;
}
/* do the component evidence measurement[s] and cache them */
do
{
status = comp->measure(comp, name->get_qualifier(name),
pts, &evid);
if (status == FAILED)
{
break;
}
attestation_state->add_evidence(attestation_state, evid);
}
while (status == NEED_MORE);
}
e->destroy(e);
break;
}
case TCG_PTS_GEN_ATTEST_EVID:
{
pts_simple_evid_final_flag_t flags;
pts_meas_algorithms_t comp_hash_algorithm;
pts_comp_evidence_t *evid;
chunk_t pcr_composite, quote_sig;
bool use_quote2;
/* Send cached Component Evidence entries */
while (attestation_state->next_evidence(attestation_state, &evid))
{
attr = tcg_pts_attr_simple_comp_evid_create(evid);
msg->add_attribute(msg, attr);
}
use_quote2 = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-attestation.use_quote2", TRUE,
lib->ns);
if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, &quote_sig))
{
DBG1(DBG_IMC, "error occurred during TPM quote operation");
return FALSE;
}
/* Send Simple Evidence Final attribute */
flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
attr = tcg_pts_attr_simple_evid_final_create(flags,
comp_hash_algorithm, pcr_composite, quote_sig);
msg->add_attribute(msg, attr);
break;
}
/* TODO: Not implemented yet */
case TCG_PTS_REQ_INTEG_MEAS_LOG:
/* Attributes using XML */
case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
case TCG_PTS_UPDATE_TEMPL_REF_MANI:
/* On Windows only*/
case TCG_PTS_REQ_REGISTRY_VALUE:
/* Received on IMV side only*/
case TCG_PTS_PROTO_CAPS:
case TCG_PTS_DH_NONCE_PARAMS_RESP:
case TCG_PTS_MEAS_ALGO_SELECTION:
case TCG_PTS_TPM_VERSION_INFO:
case TCG_PTS_TEMPL_REF_MANI_SET_META:
case TCG_PTS_AIK:
case TCG_PTS_SIMPLE_COMP_EVID:
case TCG_PTS_SIMPLE_EVID_FINAL:
case TCG_PTS_VERIFICATION_RESULT:
case TCG_PTS_INTEG_REPORT:
case TCG_PTS_UNIX_FILE_META:
case TCG_PTS_FILE_MEAS:
case TCG_PTS_INTEG_MEAS_LOG:
default:
DBG1(DBG_IMC, "received unsupported attribute '%N'",
tcg_attr_names, attr->get_type(attr));
break;
}
return TRUE;
}
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imc_attestation_process_t imc_attestation_process
* @{ @ingroup imc_attestation
*/
#ifndef IMC_ATTESTATION_PROCESS_H_
#define IMC_ATTESTATION_PROCESS_H_
#include "imc_attestation_state.h"
#include <library.h>
#include <imc/imc_msg.h>
#include <pa_tnc/pa_tnc_attr.h>
#include <pts/pts_dh_group.h>
#include <pts/pts_meas_algo.h>
/**
* Process a TCG PTS attribute
*
* @param attr PA-TNC attribute to be processed
* @param msg outbound PA-TNC message to be assembled
* @param attestation_state attestation state of a given connection
* @param supported_algorithms supported PTS measurement algorithms
* @param supported_dh_groups supported DH groups
* @return TRUE if successful
*/
bool imc_attestation_process(pa_tnc_attr_t *attr, imc_msg_t *msg,
imc_attestation_state_t *attestation_state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups);
#endif /** IMC_ATTESTATION_PROCESS_H_ @}*/
@@ -0,0 +1,260 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_attestation_state.h"
#include <imcv.h>
#include <tncif_names.h>
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_imc_attestation_state_t private_imc_attestation_state_t;
typedef struct func_comp_t func_comp_t;
/**
* Private data of an imc_attestation_state_t object.
*/
struct private_imc_attestation_state_t {
/**
* Public members of imc_attestation_state_t
*/
imc_attestation_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Assessment/Evaluation Result
*/
TNC_IMV_Evaluation_Result result;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
u_int32_t max_msg_len;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* PTS object
*/
pts_t *pts;
/**
* List of Functional Components
*/
linked_list_t *components;
/**
* Functional Component Evidence cache list
*/
linked_list_t *list;
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
private_imc_attestation_state_t *this)
{
return this->connection_id;
}
METHOD(imc_state_t, has_long, bool,
private_imc_attestation_state_t *this)
{
return this->has_long;
}
METHOD(imc_state_t, has_excl, bool,
private_imc_attestation_state_t *this)
{
return this->has_excl;
}
METHOD(imc_state_t, set_flags, void,
private_imc_attestation_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imc_state_t, set_max_msg_len, void,
private_imc_attestation_state_t *this, u_int32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imc_state_t, get_max_msg_len, u_int32_t,
private_imc_attestation_state_t *this)
{
return this->max_msg_len;
}
METHOD(imc_state_t, get_contracts, seg_contract_manager_t*,
private_imc_attestation_state_t *this)
{
return this->contracts;
}
METHOD(imc_state_t, change_state, void,
private_imc_attestation_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imc_state_t, set_result, void,
private_imc_attestation_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result result)
{
this->result = result;
}
METHOD(imc_state_t, get_result, bool,
private_imc_attestation_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result *result)
{
if (result)
{
*result = this->result;
}
return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
}
METHOD(imc_state_t, destroy, void,
private_imc_attestation_state_t *this)
{
this->pts->destroy(this->pts);
this->components->destroy_offset(this->components,
offsetof(pts_component_t, destroy));
this->list->destroy_offset(this->list,
offsetof(pts_comp_evidence_t, destroy));
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imc_attestation_state_t, get_pts, pts_t*,
private_imc_attestation_state_t *this)
{
return this->pts;
}
METHOD(imc_attestation_state_t, create_component, pts_component_t*,
private_imc_attestation_state_t *this, pts_comp_func_name_t *name,
u_int32_t depth)
{
enumerator_t *enumerator;
pts_component_t *component;
bool found = FALSE;
enumerator = this->components->create_enumerator(this->components);
while (enumerator->enumerate(enumerator, &component))
{
if (name->equals(name, component->get_comp_func_name(component)))
{
found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
if (!found)
{
component = imcv_pts_components->create(imcv_pts_components,
name, depth, NULL);
if (!component)
{
return NULL;
}
this->components->insert_last(this->components, component);
}
return component;
}
METHOD(imc_attestation_state_t, add_evidence, void,
private_imc_attestation_state_t *this, pts_comp_evidence_t *evid)
{
this->list->insert_last(this->list, evid);
}
METHOD(imc_attestation_state_t, next_evidence, bool,
private_imc_attestation_state_t *this, pts_comp_evidence_t **evid)
{
return this->list->remove_first(this->list, (void**)evid) == SUCCESS;
}
/**
* Described in header.
*/
imc_state_t *imc_attestation_state_create(TNC_ConnectionID connection_id)
{
private_imc_attestation_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.get_contracts = _get_contracts,
.change_state = _change_state,
.set_result = _set_result,
.get_result = _get_result,
.destroy = _destroy,
},
.get_pts = _get_pts,
.create_component = _create_component,
.add_evidence = _add_evidence,
.next_evidence = _next_evidence,
},
.connection_id = connection_id,
.state = TNC_CONNECTION_STATE_CREATE,
.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.contracts = seg_contract_manager_create(),
.pts = pts_create(TRUE),
.components = linked_list_create(),
.list = linked_list_create(),
);
return &this->public.interface;
}
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imc_attestation imc_attestation
* @ingroup libimcv_plugins
*
* @defgroup imc_attestation_state_t imc_attestation_state
* @{ @ingroup imc_attestation
*/
#ifndef IMC_ATTESTATION_STATE_H_
#define IMC_ATTESTATION_STATE_H_
#include <imc/imc_state.h>
#include <pts/pts.h>
#include <pts/components/pts_component.h>
#include <pts/components/pts_comp_evidence.h>
#include <library.h>
typedef struct imc_attestation_state_t imc_attestation_state_t;
/**
* Internal state of an imc_attestation_t connection instance
*/
struct imc_attestation_state_t {
/**
* imc_state_t interface
*/
imc_state_t interface;
/**
* Get the PTS object
*
* @return PTS object
*/
pts_t* (*get_pts)(imc_attestation_state_t *this);
/**
* Create and add an entry to the list of Functional Components
*
* @param name Component Functional Name
* @param depth Sub-component Depth
* @return created functional component instance or NULL
*/
pts_component_t* (*create_component)(imc_attestation_state_t *this,
pts_comp_func_name_t *name, u_int32_t depth);
/**
* Add an entry to the Component Evidence cache list
*
* @param evid Component Evidence entry
*/
void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *evid);
/**
* Removes next entry from the Component Evidence cache list and returns it
*
* @param evid Next Component Evidence entry
* @return TRUE if next entry is available
*/
bool (*next_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t** evid);
};
/**
* Create an imc_attestation_state_t instance
*
* @param id connection ID
*/
imc_state_t* imc_attestation_state_create(TNC_ConnectionID id);
#endif /** IMC_ATTESTATION_STATE_H_ @}*/
+1
View File
@@ -0,0 +1 @@
regid.2004-03.org.strongswan*.swidtag
+37
View File
@@ -0,0 +1,37 @@
regid = regid.2004-03.org.strongswan
unique_sw_id = strongSwan-$(PACKAGE_VERSION_MAJOR)-$(PACKAGE_VERSION_MINOR)-$(PACKAGE_VERSION_BUILD)$(PACKAGE_VERSION_REVIEW)
swid_tag = $(regid)_$(unique_sw_id).swidtag
swiddir = $(prefix)/share/$(regid)
swid_DATA = $(swid_tag)
ipsec_DATA = $(swid_tag)
EXTRA_DIST = $(regid)_strongSwan.swidtag.in
CLEANFILES = $(regid)_strongSwan*.swidtag
$(swid_tag) : regid.2004-03.org.strongswan_strongSwan.swidtag.in
$(AM_V_GEN) \
sed \
-e "s:@VERSION_MAJOR@:$(PACKAGE_VERSION_MAJOR):" \
-e "s:@VERSION_MINOR@:$(PACKAGE_VERSION_MINOR):" \
-e "s:@VERSION_BUILD@:$(PACKAGE_VERSION_BUILD):" \
-e "s:@VERSION_REVIEW@:$(PACKAGE_VERSION_REVIEW):" \
$(srcdir)/$(regid)_strongSwan.swidtag.in > $@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv \
-DSWID_DIRECTORY=\"${prefix}/share\"
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
imcv_LTLIBRARIES = imc-swid.la
imc_swid_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imc_swid_la_SOURCES = imc_swid.c imc_swid_state.h imc_swid_state.c
imc_swid_la_LDFLAGS = -module -avoid-version -no-undefined
+447
View File
@@ -0,0 +1,447 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_swid_state.h"
#include <imc/imc_agent.h>
#include <imc/imc_msg.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_angel.h>
#include "tcg/swid/tcg_swid_attr_req.h"
#include "tcg/swid/tcg_swid_attr_tag_inv.h"
#include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
#include "swid/swid_inventory.h"
#include "swid/swid_error.h"
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#define SWID_GENERATOR "/usr/local/bin/swid_generator"
/* IMC definitions */
static const char imc_name[] = "SWID";
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_SWID }
};
static imc_agent_t *imc_swid;
/**
* see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
TNC_Version min_version,
TNC_Version max_version,
TNC_Version *actual_version)
{
if (imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
return TNC_RESULT_ALREADY_INITIALIZED;
}
imc_swid = imc_agent_create(imc_name, msg_types, countof(msg_types),
imc_id, actual_version);
if (!imc_swid)
{
return TNC_RESULT_FATAL;
}
if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
{
DBG1(DBG_IMC, "no common IF-IMC version");
return TNC_RESULT_NO_COMMON_VERSION;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imc_state_t *state;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imc_swid_state_create(connection_id);
return imc_swid->create_state(imc_swid, state);
case TNC_CONNECTION_STATE_HANDSHAKE:
if (imc_swid->change_state(imc_swid, connection_id, new_state,
&state) != TNC_RESULT_SUCCESS)
{
return TNC_RESULT_FATAL;
}
state->set_result(state, imc_id,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_swid->delete_state(imc_swid, connection_id);
default:
return imc_swid->change_state(imc_swid, connection_id,
new_state, NULL);
}
}
/**
* see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
imc_state_t *state;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swid->get_state(imc_swid, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
return TNC_RESULT_SUCCESS;
}
/**
* Add one or multiple SWID Inventory attributes to the send queue
*/
static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg,
uint32_t request_id, bool full_tags,
swid_inventory_t *targets)
{
pa_tnc_attr_t *attr, *attr_angel, *attr_error;
imc_swid_state_t *swid_state;
swid_inventory_t *swid_inventory;
char *swid_directory, *swid_generator;
uint32_t eid_epoch;
size_t max_attr_size, attr_size, entry_size;
bool first = TRUE, swid_pretty, swid_full;
enumerator_t *enumerator;
swid_directory = lib->settings->get_str(lib->settings,
"%s.plugins.imc-swid.swid_directory",
SWID_DIRECTORY, lib->ns);
swid_generator = lib->settings->get_str(lib->settings,
"%s.plugins.imc-swid.swid_generator",
SWID_GENERATOR, lib->ns);
swid_pretty = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-swid.swid_pretty",
FALSE, lib->ns);
swid_full = lib->settings->get_bool(lib->settings,
"%s.plugins.imc-swid.swid_full",
FALSE, lib->ns);
swid_inventory = swid_inventory_create(full_tags);
if (!swid_inventory->collect(swid_inventory, swid_directory, swid_generator,
targets, swid_pretty, swid_full))
{
swid_inventory->destroy(swid_inventory);
attr_error = swid_error_create(TCG_SWID_ERROR, request_id,
0, "error in SWID tag collection");
msg->add_attribute(msg, attr_error);
return FALSE;
}
DBG1(DBG_IMC, "collected %d SWID tag%s%s",
swid_inventory->get_count(swid_inventory), full_tags ? "" : " ID",
swid_inventory->get_count(swid_inventory) == 1 ? "" : "s");
swid_state = (imc_swid_state_t*)state;
eid_epoch = swid_state->get_eid_epoch(swid_state);
/**
* Compute the maximum TCG SWID Tag [ID] Inventory attribute size
* leaving space for an additional ITA Angel attribute
*/
max_attr_size = state->get_max_msg_len(state) -
PA_TNC_HEADER_SIZE - PA_TNC_ATTR_HEADER_SIZE;
if (full_tags)
{
tcg_swid_attr_tag_inv_t *swid_attr;
swid_tag_t *tag;
chunk_t encoding, instance_id;
/* At least one TCG Tag Inventory attribute is sent */
attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_INV_MIN_SIZE;
attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
enumerator = swid_inventory->create_enumerator(swid_inventory);
while (enumerator->enumerate(enumerator, &tag))
{
instance_id = tag->get_instance_id(tag);
encoding = tag->get_encoding(tag);
entry_size = 2 + instance_id.len + 4 + encoding.len;
/* Check for oversize tags that cannot be transported */
if (PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_INV_MIN_SIZE +
entry_size > max_attr_size)
{
attr_error = swid_error_create(TCG_SWID_RESPONSE_TOO_LARGE,
request_id, max_attr_size,
"oversize SWID tag omitted");
msg->add_attribute(msg, attr_error);
continue;
}
if (attr_size + entry_size > max_attr_size)
{
if (first)
{
/**
* Send an ITA Start Angel attribute to the IMV signalling
* that multiple TGC SWID Tag Inventory attributes follow
*/
attr_angel = ita_attr_angel_create(TRUE);
msg->add_attribute(msg, attr_angel);
first = FALSE;
}
msg->add_attribute(msg, attr);
/* create the next TCG SWID Tag Inventory attribute */
attr_size = PA_TNC_ATTR_HEADER_SIZE +
TCG_SWID_TAG_INV_MIN_SIZE;
attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
}
swid_attr = (tcg_swid_attr_tag_inv_t*)attr;
swid_attr->add(swid_attr, tag->get_ref(tag));
attr_size += entry_size;
}
enumerator->destroy(enumerator);
}
else
{
tcg_swid_attr_tag_id_inv_t *swid_id_attr;
swid_tag_id_t *tag_id;
/* Send a TCG Tag ID Inventory attribute */
attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1);
swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr;
enumerator = swid_inventory->create_enumerator(swid_inventory);
while (enumerator->enumerate(enumerator, &tag_id))
{
swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id));
}
enumerator->destroy(enumerator);
}
msg->add_attribute(msg, attr);
swid_inventory->destroy(swid_inventory);
if (!first)
{
/**
* If we sent an ITA Start Angel attribute in the first place,
* terminate by appending a matching ITA Stop Angel attribute.
*/
attr_angel = ita_attr_angel_create(FALSE);
msg->add_attribute(msg, attr_angel);
}
return TRUE;
}
static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
{
imc_msg_t *out_msg;
pa_tnc_attr_t *attr;
enumerator_t *enumerator;
pen_type_t type;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imc_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
tcg_swid_attr_req_t *attr_req;
uint8_t flags;
uint32_t request_id;
bool full_tags;
swid_inventory_t *targets;
type = attr->get_type(attr);
if (type.vendor_id != PEN_TCG || type.type != TCG_SWID_REQUEST)
{
continue;
}
attr_req = (tcg_swid_attr_req_t*)attr;
flags = attr_req->get_flags(attr_req);
request_id = attr_req->get_request_id(attr_req);
targets = attr_req->get_targets(attr_req);
if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C))
{
attr = swid_error_create(TCG_SWID_SUBSCRIPTION_DENIED, request_id,
0, "no subscription available yet");
out_msg->add_attribute(out_msg, attr);
break;
}
full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0;
if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets))
{
break;
}
}
enumerator->destroy(enumerator);
if (fatal_error)
{
result = TNC_RESULT_FATAL;
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
/**
* see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swid->get_state(imc_swid, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_data(imc_swid, state, connection_id, msg_type,
chunk_create(msg, msg_len));
result = receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
*/
TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_VendorID msg_vid,
TNC_MessageSubtype msg_subtype,
TNC_UInt32 src_imv_id,
TNC_UInt32 dst_imc_id)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_swid->get_state(imc_swid, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_long_data(imc_swid, state, connection_id,
src_imv_id, dst_imc_id,msg_vid, msg_subtype,
chunk_create(msg, msg_len));
result =receive_message(state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
{
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
imc_swid->destroy(imc_swid);
imc_swid = NULL;
return TNC_RESULT_SUCCESS;
}
/**
* see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
{
if (!imc_swid)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return imc_swid->bind_functions(imc_swid, bind_function);
}
@@ -0,0 +1,203 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_swid_state.h"
#include <tncif_names.h>
#include <utils/debug.h>
typedef struct private_imc_swid_state_t private_imc_swid_state_t;
/**
* Private data of an imc_swid_state_t object.
*/
struct private_imc_swid_state_t {
/**
* Public members of imc_swid_state_t
*/
imc_swid_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Assessment/Evaluation Result
*/
TNC_IMV_Evaluation_Result result;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
u_int32_t max_msg_len;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* Event ID Epoch
*/
u_int32_t eid_epoch;
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
private_imc_swid_state_t *this)
{
return this->connection_id;
}
METHOD(imc_state_t, has_long, bool,
private_imc_swid_state_t *this)
{
return this->has_long;
}
METHOD(imc_state_t, has_excl, bool,
private_imc_swid_state_t *this)
{
return this->has_excl;
}
METHOD(imc_state_t, set_flags, void,
private_imc_swid_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imc_state_t, set_max_msg_len, void,
private_imc_swid_state_t *this, u_int32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imc_state_t, get_max_msg_len, u_int32_t,
private_imc_swid_state_t *this)
{
return this->max_msg_len;
}
METHOD(imc_state_t, get_contracts, seg_contract_manager_t*,
private_imc_swid_state_t *this)
{
return this->contracts;
}
METHOD(imc_state_t, change_state, void,
private_imc_swid_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imc_state_t, set_result, void,
private_imc_swid_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result result)
{
this->result = result;
}
METHOD(imc_state_t, get_result, bool,
private_imc_swid_state_t *this, TNC_IMCID id,
TNC_IMV_Evaluation_Result *result)
{
if (result)
{
*result = this->result;
}
return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
}
METHOD(imc_state_t, destroy, void,
private_imc_swid_state_t *this)
{
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imc_swid_state_t, get_eid_epoch, u_int32_t,
private_imc_swid_state_t *this)
{
return this->eid_epoch;
}
/**
* Described in header.
*/
imc_state_t *imc_swid_state_create(TNC_ConnectionID connection_id)
{
private_imc_swid_state_t *this;
u_int32_t eid_epoch;
nonce_gen_t *ng;
ng = lib->crypto->create_nonce_gen(lib->crypto);
if (!ng || !ng->get_nonce(ng, 4, (u_int8_t*)&eid_epoch))
{
DBG1(DBG_TNC, "failed to generate random EID epoch value");
DESTROY_IF(ng);
return NULL;
}
ng->destroy(ng);
DBG1(DBG_IMC, "creating random EID epoch 0x%08x", eid_epoch);
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.get_contracts = _get_contracts,
.change_state = _change_state,
.set_result = _set_result,
.get_result = _get_result,
.destroy = _destroy,
},
.get_eid_epoch = _get_eid_epoch,
},
.state = TNC_CONNECTION_STATE_CREATE,
.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.contracts = seg_contract_manager_create(),
.eid_epoch = eid_epoch,
);
return &this->public.interface;
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2013 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imc_swid imc_swid
* @ingroup libimcv_plugins
*
* @defgroup imc_swid_state_t imc_swid_state
* @{ @ingroup imc_swid
*/
#ifndef IMC_SWID_STATE_H_
#define IMC_SWID_STATE_H_
#include <imc/imc_state.h>
#include <library.h>
typedef struct imc_swid_state_t imc_swid_state_t;
/**
* Internal state of an imc_swid_t connection instance
*/
struct imc_swid_state_t {
/**
* imc_state_t interface
*/
imc_state_t interface;
/**
* Get Event ID Epoch
*
* @return Event ID Epoch
*/
u_int32_t (*get_eid_epoch)(imc_swid_state_t *this);
};
/**
* Create an imc_swid_state_t instance
*
* @param id connection ID
*/
imc_state_t* imc_swid_state_create(TNC_ConnectionID id);
#endif /** IMC_SWID_STATE_H_ @}*/
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>apache2</product_title>
<product_version>
<name>2.2-22-13</name>
<numeric>
<major>2</major>
<minor>2</minor>
<build>22</build>
<review>13</review>
</numeric>
</product_version>
<software_creator>
<name>Apache Software Foundation</name>
<regid>regid.1995-04.org.apache</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>apache-2-2-22-13</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>bind9</product_title>
<product_version>
<name>9-8-4-dfsg</name>
<numeric>
<major>9</major>
<minor>8</minor>
<build>4</build>
<review>dfsg</review>
</numeric>
</product_version>
<software_creator>
<name>Internet Systems Consortium</name>
<regid>regid.1994-04.org.isc</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>bind-9-8-4-dfsg</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libsqlite3</product_title>
<product_version>
<name>3.7.13-1</name>
<numeric>
<major>3</major>
<minor>7</minor>
<build>13</build>
<review>1</review>
</numeric>
</product_version>
<software_creator>
<name>SQLite Project</name>
<regid>regid.2002-08.org.sqlite</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libsqlite-3-7-13-1</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libssl1.0.0</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libssl-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>libssl-dev</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>libssl-dev-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>openssl</product_title>
<product_version>
<name>1.0.1e-2</name>
<numeric>
<major>1</major>
<minor>0</minor>
<build>1e</build>
<review>2</review>
</numeric>
</product_version>
<software_creator>
<name>OpenSSL Project</name>
<regid>regid.1998-12.org.openssl</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>openssl-1-0-1e-2</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<software_identification_tag xmlns="http://standards.iso.org/iso/19770/-2/2009/schema.xsd">
<entitlement_required_indicator>true</entitlement_required_indicator>
<product_title>sqlite3</product_title>
<product_version>
<name>3.7.13-1</name>
<numeric>
<major>3</major>
<minor>7</minor>
<build>13</build>
<review>1</review>
</numeric>
</product_version>
<software_creator>
<name>SQLite Project</name>
<regid>regid.2002-08.org.sqlite</regid>
</software_creator>
<software_licensor>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</software_licensor>
<software_id>
<unique_id>sqlite-3-7-13-1</unique_id>
<tag_creator_regid>regid.1999-03.org.debian</tag_creator_regid>
</software_id>
<tag_creator>
<name>Debian Project</name>
<regid>regid.1999-03.org.debian</regid>
</tag_creator>
</software_identification_tag>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<SoftwareIdentity
name="strongSwan"
uniqueId="strongSwan-@VERSION_MAJOR@-@VERSION_MINOR@-@VERSION_BUILD@@VERSION_REVIEW@"
version="@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_BUILD@@VERSION_REVIEW@" versionScheme="alphanumeric"
xmlns="http://standards.iso.org/iso/19770/-2/2014/schema.xsd">
<Entity
name="strongSwan Project"
regid="regid.2004-03.org.strongswan"
role="publisher licensor tagcreator"/>
</SoftwareIdentity>
@@ -0,0 +1 @@
attest
@@ -0,0 +1,33 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv \
-DPLUGINS=\""${attest_plugins}\""
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
imcv_LTLIBRARIES = imv-attestation.la
imv_attestation_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
imv_attestation_la_SOURCES = imv_attestation.c \
imv_attestation_state.h imv_attestation_state.c \
imv_attestation_agent.h imv_attestation_agent.c \
imv_attestation_process.h imv_attestation_process.c \
imv_attestation_build.h imv_attestation_build.c
imv_attestation_la_LDFLAGS = -module -avoid-version -no-undefined
ipsec_PROGRAMS = attest
attest_SOURCES = attest.c \
attest_usage.h attest_usage.c \
attest_db.h attest_db.c
attest_LDADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
attest.o : $(top_builddir)/config.status
EXTRA_DIST = build-database.sh
@@ -0,0 +1,484 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#define _GNU_SOURCE
#include <getopt.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <libgen.h>
#ifdef HAVE_SYSLOG
# include <syslog.h>
#endif
#include <library.h>
#include <utils/debug.h>
#include <imcv.h>
#include <pts/pts_meas_algo.h>
#include "attest_db.h"
#include "attest_usage.h"
/**
* global debug output variables
*/
static int debug_level = 1;
static bool stderr_quiet = TRUE;
/**
* attest dbg function
*/
static void attest_dbg(debug_t group, level_t level, char *fmt, ...)
{
va_list args;
if (level <= debug_level)
{
if (!stderr_quiet)
{
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
}
#ifdef HAVE_SYSLOG
{
int priority = LOG_INFO;
char buffer[8192];
char *current = buffer, *next;
/* write in memory buffer first */
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
/* do a syslog with every line */
while (current)
{
next = strchr(current, '\n');
if (next)
{
*(next++) = '\0';
}
syslog(priority, "%s\n", current);
current = next;
}
}
#endif /* HAVE_SYSLOG */
}
}
/**
* global attestation database object
*/
attest_db_t *attest;
/**
* atexit handler to close db on shutdown
*/
static void cleanup(void)
{
attest->destroy(attest);
libimcv_deinit();
#ifdef HAVE_SYSLOG
closelog();
#endif
}
static void do_args(int argc, char *argv[])
{
enum {
OP_UNDEF,
OP_USAGE,
OP_KEYS,
OP_COMPONENTS,
OP_DEVICES,
OP_DIRECTORIES,
OP_FILES,
OP_HASHES,
OP_MEASUREMENTS,
OP_PACKAGES,
OP_PRODUCTS,
OP_SESSIONS,
OP_ADD,
OP_DEL,
} op = OP_UNDEF;
/* reinit getopt state */
optind = 0;
while (TRUE)
{
int c;
struct option long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "components", no_argument, NULL, 'c' },
{ "devices", no_argument, NULL, 'e' },
{ "directories", no_argument, NULL, 'd' },
{ "dirs", no_argument, NULL, 'd' },
{ "files", no_argument, NULL, 'f' },
{ "keys", no_argument, NULL, 'k' },
{ "packages", no_argument, NULL, 'g' },
{ "products", no_argument, NULL, 'p' },
{ "hashes", no_argument, NULL, 'H' },
{ "measurements", no_argument, NULL, 'm' },
{ "sessions", no_argument, NULL, 's' },
{ "add", no_argument, NULL, 'a' },
{ "delete", no_argument, NULL, 'r' },
{ "del", no_argument, NULL, 'r' },
{ "remove", no_argument, NULL, 'r' },
{ "aik", required_argument, NULL, 'A' },
{ "blacklist", no_argument, NULL, 'B' },
{ "component", required_argument, NULL, 'C' },
{ "comp", required_argument, NULL, 'C' },
{ "directory", required_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'D' },
{ "file", required_argument, NULL, 'F' },
{ "package", required_argument, NULL, 'G' },
{ "key", required_argument, NULL, 'K' },
{ "measdir", required_argument, NULL, 'M' },
{ "owner", required_argument, NULL, 'O' },
{ "product", required_argument, NULL, 'P' },
{ "relative", no_argument, NULL, 'R' },
{ "rel", no_argument, NULL, 'R' },
{ "sequence", required_argument, NULL, 'S' },
{ "seq", required_argument, NULL, 'S' },
{ "utc", no_argument, NULL, 'U' },
{ "version", required_argument, NULL, 'V' },
{ "security", no_argument, NULL, 'Y' },
{ "sha1", no_argument, NULL, '1' },
{ "sha256", no_argument, NULL, '2' },
{ "sha384", no_argument, NULL, '3' },
{ "did", required_argument, NULL, '4' },
{ "fid", required_argument, NULL, '5' },
{ "pid", required_argument, NULL, '6' },
{ "cid", required_argument, NULL, '7' },
{ "kid", required_argument, NULL, '8' },
{ "gid", required_argument, NULL, '9' },
{ 0,0,0,0 }
};
c = getopt_long(argc, argv, "", long_opts, NULL);
switch (c)
{
case EOF:
break;
case 'h':
op = OP_USAGE;
break;
case 'c':
op = OP_COMPONENTS;
continue;
case 'd':
op = OP_DIRECTORIES;
continue;
case 'e':
op = OP_DEVICES;
continue;
case 'f':
op = OP_FILES;
continue;
case 'g':
op = OP_PACKAGES;
continue;
case 'k':
op = OP_KEYS;
continue;
case 'p':
op = OP_PRODUCTS;
continue;
case 'H':
op = OP_HASHES;
continue;
case 'm':
op = OP_MEASUREMENTS;
continue;
case 's':
op = OP_SESSIONS;
continue;
case 'a':
op = OP_ADD;
continue;
case 'r':
op = OP_DEL;
continue;
case 'A':
{
certificate_t *aik_cert;
public_key_t *aik_key;
chunk_t aik;
aik_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_X509, BUILD_FROM_FILE, optarg, BUILD_END);
if (!aik_cert)
{
printf("AIK certificate '%s' could not be loaded\n", optarg);
exit(EXIT_FAILURE);
}
aik_key = aik_cert->get_public_key(aik_cert);
aik_cert->destroy(aik_cert);
if (!aik_key)
{
printf("AIK public key could not be retrieved\n");
exit(EXIT_FAILURE);
}
if (!aik_key->get_fingerprint(aik_key, KEYID_PUBKEY_INFO_SHA1,
&aik))
{
printf("AIK fingerprint could not be computed\n");
aik_key->destroy(aik_key);
exit(EXIT_FAILURE);
}
aik = chunk_clone(aik);
aik_key->destroy(aik_key);
if (!attest->set_key(attest, aik, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
}
case 'B':
attest->set_package_state(attest, OS_PACKAGE_STATE_BLACKLIST);
continue;
case 'C':
if (!attest->set_component(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'D':
if (!attest->set_directory(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'F':
{
char *dir = path_dirname(optarg);
char *file = path_basename(optarg);
if (*dir != '.')
{
if (!attest->set_directory(attest, dir, op == OP_ADD))
{
free(file);
free(dir);
exit(EXIT_FAILURE);
}
}
free(dir);
if (!attest->set_file(attest, file, op == OP_ADD))
{
free(file);
exit(EXIT_FAILURE);
}
free(file);
continue;
}
case 'G':
if (!attest->set_package(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'K':
{
chunk_t aik;
aik = chunk_from_hex(chunk_create(optarg, strlen(optarg)), NULL);
if (!attest->set_key(attest, aik, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
}
case 'M':
if (!attest->set_meas_directory(attest, optarg))
{
exit(EXIT_FAILURE);
}
continue;
case 'O':
attest->set_owner(attest, optarg);
continue;
case 'P':
if (!attest->set_product(attest, optarg, op == OP_ADD))
{
exit(EXIT_FAILURE);
}
continue;
case 'R':
attest->set_relative(attest);
continue;
case 'S':
attest->set_sequence(attest, atoi(optarg));
continue;
case 'U':
attest->set_utc(attest);
continue;
case 'V':
if (!attest->set_version(attest, optarg))
{
exit(EXIT_FAILURE);
}
continue;
case 'Y':
attest->set_package_state(attest, OS_PACKAGE_STATE_SECURITY);
continue;
case '1':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA1);
continue;
case '2':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA256);
continue;
case '3':
attest->set_algo(attest, PTS_MEAS_ALGO_SHA384);
continue;
case '4':
if (!attest->set_did(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '5':
if (!attest->set_fid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '6':
if (!attest->set_pid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '7':
if (!attest->set_cid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '8':
if (!attest->set_kid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
case '9':
if (!attest->set_gid(attest, atoi(optarg)))
{
exit(EXIT_FAILURE);
}
continue;
}
break;
}
switch (op)
{
case OP_USAGE:
usage();
break;
case OP_PACKAGES:
attest->list_packages(attest);
break;
case OP_PRODUCTS:
attest->list_products(attest);
break;
case OP_KEYS:
attest->list_keys(attest);
break;
case OP_COMPONENTS:
attest->list_components(attest);
break;
case OP_DEVICES:
attest->list_devices(attest);
break;
case OP_DIRECTORIES:
attest->list_directories(attest);
break;
case OP_FILES:
attest->list_files(attest);
break;
case OP_HASHES:
attest->list_hashes(attest);
break;
case OP_MEASUREMENTS:
attest->list_measurements(attest);
break;
case OP_SESSIONS:
attest->list_sessions(attest);
break;
case OP_ADD:
attest->add(attest);
break;
case OP_DEL:
attest->delete(attest);
break;
default:
usage();
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
char *uri;
/* enable attest debugging hook */
dbg = attest_dbg;
#ifdef HAVE_SYSLOG
openlog("attest", 0, LOG_DEBUG);
#endif
atexit(library_deinit);
/* initialize library */
if (!library_init(NULL, "attest"))
{
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
}
if (!lib->plugins->load(lib->plugins,
lib->settings->get_str(lib->settings, "attest.load", PLUGINS)))
{
exit(SS_RC_INITIALIZATION_FAILED);
}
uri = lib->settings->get_str(lib->settings, "attest.database", NULL);
if (!uri)
{
fprintf(stderr, "database URI attest.database not set.\n");
exit(SS_RC_INITIALIZATION_FAILED);
}
attest = attest_db_create(uri);
if (!attest)
{
exit(SS_RC_INITIALIZATION_FAILED);
}
atexit(cleanup);
libimcv_init(FALSE);
do_args(argc, argv);
exit(EXIT_SUCCESS);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,267 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup attest_db_t attest_db
* @{ @ingroup libpts
*/
#ifndef ATTEST_DB_H_
#define ATTEST_DB_H_
#include <pts/pts_meas_algo.h>
#include <os_info/os_info.h>
#include <library.h>
typedef struct attest_db_t attest_db_t;
/**
* Attestation database object
*/
struct attest_db_t {
/**
* Set functional component to be queried
*
* @param comp functional component
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_component)(attest_db_t *this, char *comp, bool create);
/**
* Set primary key of the functional component to be queried
*
* @param fid primary key of functional component
* @return TRUE if successful
*/
bool (*set_cid)(attest_db_t *this, int fid);
/**
* Set directory to be queried
*
* @param dir directory
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_directory)(attest_db_t *this, char *dir, bool create);
/**
* Set primary key of the directory to be queried
*
* @param did primary key of directory
* @return TRUE if successful
*/
bool (*set_did)(attest_db_t *this, int did);
/**
* Set measurement file to be queried
*
* @param file measurement file
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_file)(attest_db_t *this, char *file, bool create);
/**
* Set primary key of the measurement file to be queried
*
* @param fid primary key of measurement file
* @return TRUE if successful
*/
bool (*set_fid)(attest_db_t *this, int fid);
/**
* Set path to directory where file[s] are to be measured
*
* @param meas_dir measurement directory
* @return TRUE if successful
*/
bool (*set_meas_directory)(attest_db_t *this, char *dir);
/**
* Set functional component to be queried
*
* @param key AIK
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_key)(attest_db_t *this, chunk_t key, bool create);
/**
* Set primary key of the AIK to be queried
*
* @param kid primary key of AIK
* @return TRUE if successful
*/
bool (*set_kid)(attest_db_t *this, int kid);
/**
* Set software package to be queried
*
* @param product software package
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_package)(attest_db_t *this, char *package, bool create);
/**
* Set primary key of the software package to be queried
*
* @param gid primary key of software package
* @return TRUE if successful
*/
bool (*set_gid)(attest_db_t *this, int gid);
/**
* Set software product to be queried
*
* @param product software product
* @param create if TRUE create database entry if it doesn't exist
* @return TRUE if successful
*/
bool (*set_product)(attest_db_t *this, char *product, bool create);
/**
* Set primary key of the software product to be queried
*
* @param pid primary key of software product
* @return TRUE if successful
*/
bool (*set_pid)(attest_db_t *this, int pid);
/**
* Set software package version to be queried
*
* @param version software package version
* @return TRUE if successful
*/
bool (*set_version)(attest_db_t *this, char *version);
/**
* Set measurement hash algorithm
*
* @param algo hash algorithm
*/
void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo);
/**
* Set that the IMA-specific SHA-1 template hash be computed
*/
void (*set_ima)(attest_db_t *this);
/**
* Set that relative filenames are to be used
*/
void (*set_relative)(attest_db_t *this);
/**
* Set the package security or blacklist state
*/
void (*set_package_state)(attest_db_t *this, os_package_state_t package_state);
/**
* Set the sequence number
*/
void (*set_sequence)(attest_db_t *this, int seq_no);
/**
* Set owner [user/host] of an AIK
*
* @param owner user/host name
* @return TRUE if successful
*/
void (*set_owner)(attest_db_t *this, char *owner);
/**
* Display all dates in UTC
*/
void (*set_utc)(attest_db_t *this);
/**
* List all packages stored in the database
*/
void (*list_packages)(attest_db_t *this);
/**
* List all products stored in the database
*/
void (*list_products)(attest_db_t *this);
/**
* List all directories stored in the database
*/
void (*list_directories)(attest_db_t *this);
/**
* List selected files stored in the database
*/
void (*list_files)(attest_db_t *this);
/**
* List all components stored in the database
*/
void (*list_components)(attest_db_t *this);
/**
* List all devices stored in the database
*/
void (*list_devices)(attest_db_t *this);
/**
* List all AIKs stored in the database
*/
void (*list_keys)(attest_db_t *this);
/**
* List selected measurement hashes stored in the database
*/
void (*list_hashes)(attest_db_t *this);
/**
* List selected component measurement stored in the database
*/
void (*list_measurements)(attest_db_t *this);
/**
* List sessions stored in the database
*/
void (*list_sessions)(attest_db_t *this);
/**
* Add an entry to the database
*/
bool (*add)(attest_db_t *this);
/**
* Delete an entry from the database
*/
bool (*delete)(attest_db_t *this);
/**
* Destroy attest_db_t object
*/
void (*destroy)(attest_db_t *this);
};
/**
* Create an attest_db_t instance
*
* @param uri database URI
*/
attest_db_t* attest_db_create(char *uri);
#endif /** ATTEST_DB_H_ @}*/
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <stdio.h>
#include "attest_usage.h"
/**
* print attest usage info
*/
void usage(void)
{
printf("\
Usage:\n\
ipsec attest --components|--devices|--sessions|--files|--hashes|--keys [options]\n\
\n\
ipsec attest --measurements|--packages|--products|--add|--del [options]\n\
\n\
ipsec attest --components [--key <digest>|--kid <id>]\n\
Show a list of components with an AIK digest or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --devices [--utc]\n\
Show a list of registered devices and associated collected information\n\
\n\
ipsec attest --sessions [--utc]\n\
Show a chronologically sorted list of all TNC sessions\n\
\n\
ipsec attest --files [--product <name>|--pid <id>]\n\
Show a list of files with a software product name or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --hashes [--sha1|--sha256|--sha384] [--product <name>|--pid <id>]\n\
Show a list of measurement hashes for a given software product or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --hashes [--sha1|--sha1-ima|--sha256|--sha384] [--file <path>|--fid <id>]\n\
Show a list of measurement hashes for a given file or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --keys [--components <cfn>|--cid <id>]\n\
Show a list of AIK key digests with a component or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --measurements --sha1|--sha256|--sha384 [--component <cfn>|--cid <id>]\n\
Show a list of component measurements for a given component or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --measurements --sha1|--sha256|--sha384 [--key <digest>|--kid <id>|--aik <path>]\n\
Show a list of component measurements for a given AIK or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --packages [--product <name>|--pid <id>] [--utc]\n\
Show a list of software packages for a given product or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --products [--file <path>|--fid <id>]\n\
Show a list of supported software products with a file path or\n\
its primary key as an optional selector.\n\
\n\
ipsec attest --add --file <path>|--dir <path>|--product <name>|--component <cfn>\n\
Add a file, directory, product or component entry\n\
Component <cfn> entries must be of the form <vendor_id>/<name>-<qualifier>\n\
\n\
ipsec attest --add [--owner <name>] --key <digest>|--aik <path>\n\
Add an AIK public key digest entry preceded by an optional owner name\n\
\n\
ipsec attest --add --product <name>|--pid <id> --sha1|--sha1-ima|--sha256|--sha384\n\
[--relative|--rel] --dir <path>|--file <path>\n\
Add hashes of a single file or all files in a directory under absolute or relative filenames\n\
\n\
ipsec attest --add --key <digest|--kid <id> --component <cfn>|--cid <id> --sequence <no>|--seq <no>\n\
Add an ordered key/component entry\n\
\n\
ipsec attest --add --package <name> --version <string> [--security|--blacklist]\n\
[--product <name>|--pid <id>]\n\
Add a package version for a given product optionally with security or blacklist flag\n\
\n\
ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>\n\
Delete a file or directory entry referenced either by value or primary key\n\
\n\
ipsec attest --del --product <name>|--pid <id>|--component <cfn>|--cid <id>\n\
Delete a product or component entry referenced either by value or primary key\n\
\n\
ipsec attest --del --product <name>|--pid <id> --file <path>|--fid <id>|--dir <path>|--did <id>\n\
Delete a product/file entry referenced either by value or primary key\n\
\n\
ipsec attest --del --key <digest>|--kid <id>|--aik <path>\n\
Delete an AIK entry referenced either by value or primary key\n\
\n\
ipsec attest --del --key <digest|--kid <id> --component <cfn>|--cid <id>\n\
Delete a key/component entry\n\
\n\
ipsec attest --del --product <name>|--pid <id> --sha1|--sha1-ima|--sha256|--sha384\n\
[--dir <path>|--did <id>] --file <path>|--fid <id>\n\
Delete a file hash given an absolute or relative filename\n\
\n");
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2011 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef ATTEST_USAGE_H_
#define ATTEST_USAGE_H_
/**
* print attest usage info
*/
void usage(void);
#endif /* ATTEST_USAGE_H_ */
+84
View File
@@ -0,0 +1,84 @@
#!/bin/sh
p="Ubuntu 14.04 x86_64"
a="x86_64-linux-gnu"
k="3.13.0-34-generic"
for hash in sha1 sha256
do
ipsec attest --add --product "$p" --$hash --dir /sbin
ipsec attest --add --product "$p" --$hash --dir /usr/sbin
ipsec attest --add --product "$p" --$hash --dir /bin
ipsec attest --add --product "$p" --$hash --dir /usr/bin
ipsec attest --add --product "$p" --$hash --file /etc/init.d/rc
ipsec attest --add --product "$p" --$hash --file /etc/init.d/rcS
ipsec attest --add --product "$p" --$hash --dir /etc/network/if-pre-up.d
ipsec attest --add --product "$p" --$hash --dir /etc/network/if-up.d
ipsec attest --add --product "$p" --$hash --dir /etc/ppp/ip-down.d
ipsec attest --add --product "$p" --$hash --dir /etc/rcS.d
ipsec attest --add --product "$p" --$hash --dir /etc/rc2.d
ipsec attest --add --product "$p" --$hash --file /etc/rc.local
ipsec attest --add --product "$p" --$hash --dir /etc/resolvconf/update.d
ipsec attest --add --product "$p" --$hash --file /etc/resolvconf/update-libc.d/avahi-daemon
ipsec attest --add --product "$p" --$hash --dir /etc/update-motd.d
ipsec attest --add --product "$p" --$hash --dir /lib
ipsec attest --add --product "$p" --$hash --file /lib/crda/setregdomain
ipsec attest --add --product "$p" --$hash --dir /lib/ebtables
ipsec attest --add --product "$p" --$hash --file /lib/init/apparmor-profile-load
ipsec attest --add --product "$p" --$hash --file /lib/resolvconf/list-records
ipsec attest --add --product "$p" --$hash --dir /lib/ufw
ipsec attest --add --product "$p" --$hash --dir /lib/udev
ipsec attest --add --product "$p" --$hash --dir /lib/systemd
ipsec attest --add --product "$p" --$hash --dir /lib/xtables
ipsec attest --add --product "$p" --$hash --dir /lib/$a
ipsec attest --add --product "$p" --$hash --dir /lib/$a/plymouth
ipsec attest --add --product "$p" --$hash --dir /lib/$a/plymouth/renderers
ipsec attest --add --product "$p" --$hash --dir /lib/$a/security
ipsec attest --add --product "$p" --$hash --file /lib64/ld-linux-x86-64.so.2
for file in `find /usr/lib -name *.so`
do
ipsec attest --add --product "$p" --$hash --file $file
done
for file in `find /usr/lib -name *service`
do
ipsec attest --add --product "$p" --$hash --file $file
done
ipsec attest --add --product "$p" --$hash --dir /usr/lib
ipsec attest --add --product "$p" --$hash --dir /usr/lib/accountsservice
ipsec attest --add --product "$p" --$hash --dir /usr/lib/at-spi2-core
ipsec attest --add --product "$p" --$hash --file /usr/lib/avahi/avahi-daemon-check-dns.sh
ipsec attest --add --product "$p" --$hash --file /usr/lib/dbus-1.0/dbus-daemon-launch-helper
ipsec attest --add --product "$p" --$hash --dir /usr/lib/gvfs
ipsec attest --add --product "$p" --$hash --file /usr/lib/firefox/firefox
ipsec attest --add --product "$p" --$hash --dir /usr/lib/NetworkManager
ipsec attest --add --product "$p" --$hash --dir /usr/lib/pm-utils/power.d
ipsec attest --add --product "$p" --$hash --file /usr/lib/policykit-1/polkitd
ipsec attest --add --product "$p" --$hash --file /usr/lib/thunderbird/thunderbird
ipsec attest --add --product "$p" --$hash --dir /usr/lib/ubuntu-release-upgrader
ipsec attest --add --product "$p" --$hash --dir /usr/lib/update-notifier
ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a
ipsec attest --add --product "$p" --$hash --file /usr/lib/$a/mesa/libGL.so.1.2.0
ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a/samba
ipsec attest --add --product "$p" --$hash --dir /usr/lib/$a/sasl2
ipsec attest --add --product "$p" --$hash --dir /usr/share/language-tools
ipsec attest --add --product "$p" --$hash --file /init \
--measdir /usr/share/initramfs-tools
ipsec attest --add --product "$p" --$hash --file /scripts/functions \
--measdir /usr/share/initramfs-tools/scripts
for file in `find /lib/modules/$k -name *.ko`
do
ipsec attest --add --product "$p" --$hash --file $file
done
done
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_attestation_agent.h"
static const char imv_name[] = "Attestation";
static const imv_agent_create_t imv_agent_create = imv_attestation_agent_create;
/* include generic TGC TNC IF-IMV API code below */
#include <imv/imv_if.h>
@@ -0,0 +1,904 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#define _GNU_SOURCE /* for stdndup() */
#include <string.h>
#include "imv_attestation_agent.h"
#include "imv_attestation_state.h"
#include "imv_attestation_process.h"
#include "imv_attestation_build.h"
#include <imcv.h>
#include <imv/imv_agent.h>
#include <imv/imv_msg.h>
#include <imv/imv_session.h>
#include <imv/imv_os_info.h>
#include <ietf/ietf_attr.h>
#include <ietf/ietf_attr_attr_request.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <ietf/ietf_attr_product_info.h>
#include <ietf/ietf_attr_string_version.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_device_id.h>
#include <tcg/tcg_attr.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_req_file_meas.h>
#include <tcg/pts/tcg_pts_attr_req_file_meta.h>
#include <pts/pts.h>
#include <pts/pts_database.h>
#include <pts/pts_creds.h>
#include <pts/components/ita/ita_comp_func_name.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <credentials/credential_manager.h>
#include <collections/linked_list.h>
typedef struct private_imv_attestation_agent_t private_imv_attestation_agent_t;
/* Subscribed PA-TNC message subtypes */
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_PTS },
{ PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM }
};
/**
* Private data of an imv_attestation_agent_t object.
*/
struct private_imv_attestation_agent_t {
/**
* Public members of imv_attestation_agent_t
*/
imv_agent_if_t public;
/**
* IMV agent responsible for generic functions
*/
imv_agent_t *agent;
/**
* Supported PTS measurement algorithms
*/
pts_meas_algorithms_t supported_algorithms;
/**
* Supported PTS Diffie Hellman Groups
*/
pts_dh_group_t supported_dh_groups;
/**
* PTS file measurement database
*/
pts_database_t *pts_db;
/**
* PTS credentials
*/
pts_creds_t *pts_creds;
/**
* PTS credential manager
*/
credential_manager_t *pts_credmgr;
};
METHOD(imv_agent_if_t, bind_functions, TNC_Result,
private_imv_attestation_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
{
return this->agent->bind_functions(this->agent, bind_function);
}
METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id,
TNC_ConnectionState new_state)
{
TNC_IMV_Action_Recommendation rec;
imv_state_t *state;
imv_session_t *session;
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imv_attestation_state_create(id);
return this->agent->create_state(this->agent, state);
case TNC_CONNECTION_STATE_DELETE:
return this->agent->delete_state(this->agent, id);
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
if (this->agent->get_state(this->agent, id, &state) && imcv_db)
{
session = state->get_session(state);
if (session->get_policy_started(session))
{
switch (new_state)
{
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
break;
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
break;
case TNC_CONNECTION_STATE_ACCESS_NONE:
default:
rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
}
imcv_db->add_recommendation(imcv_db, session, rec);
if (!imcv_db->policy_script(imcv_db, session, FALSE))
{
DBG1(DBG_IMV, "error in policy script stop");
}
}
}
/* fall through to default state */
default:
return this->agent->change_state(this->agent, id, new_state, NULL);
}
}
/**
* Process a received message
*/
static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
imv_state_t *state, imv_msg_t *in_msg)
{
imv_msg_t *out_msg;
imv_session_t *session;
imv_os_info_t *os_info;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
pen_type_t type;
TNC_Result result;
chunk_t os_name, os_version;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imv_msg_create_as_reply(in_msg);
out_msg->set_msg_type(out_msg, msg_types[0]);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
session = state->get_session(state);
os_info = session->get_os_info(session);
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
type = attr->get_type(attr);
if (type.vendor_id == PEN_IETF)
{
switch (type.type)
{
case IETF_ATTR_PA_TNC_ERROR:
{
ietf_attr_pa_tnc_error_t *error_attr;
pen_type_t error_code;
chunk_t msg_info;
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
error_code = error_attr->get_error_code(error_attr);
if (error_code.vendor_id == PEN_TCG)
{
msg_info = error_attr->get_msg_info(error_attr);
DBG1(DBG_IMV, "received TCG-PTS error '%N'",
pts_error_code_names, error_code.type);
DBG1(DBG_IMV, "error information: %B", &msg_info);
fatal_error = TRUE;
}
break;
}
case IETF_ATTR_PRODUCT_INFORMATION:
{
ietf_attr_product_info_t *attr_cast;
pen_t vendor_id;
state->set_action_flags(state,
IMV_ATTESTATION_ATTR_PRODUCT_INFO);
attr_cast = (ietf_attr_product_info_t*)attr;
os_name = attr_cast->get_info(attr_cast, &vendor_id, NULL);
os_info->set_name(os_info, os_name);
if (vendor_id != PEN_IETF)
{
DBG1(DBG_IMV, "operating system name is '%.*s' "
"from vendor %N", os_name.len, os_name.ptr,
pen_names, vendor_id);
}
else
{
DBG1(DBG_IMV, "operating system name is '%.*s'",
os_name.len, os_name.ptr);
}
break;
break;
}
case IETF_ATTR_STRING_VERSION:
{
ietf_attr_string_version_t *attr_cast;
state->set_action_flags(state,
IMV_ATTESTATION_ATTR_STRING_VERSION);
attr_cast = (ietf_attr_string_version_t*)attr;
os_version = attr_cast->get_version(attr_cast, NULL, NULL);
os_info->set_version(os_info, os_version);
if (os_version.len)
{
DBG1(DBG_IMV, "operating system version is '%.*s'",
os_version.len, os_version.ptr);
}
break;
}
default:
break;
}
}
else if (type.vendor_id == PEN_ITA)
{
switch (type.type)
{
case ITA_ATTR_DEVICE_ID:
{
chunk_t value;
state->set_action_flags(state,
IMV_ATTESTATION_ATTR_DEVICE_ID);
value = attr->get_value(attr);
DBG1(DBG_IMV, "device ID is %.*s", value.len, value.ptr);
session->set_device_id(session, value);
break;
}
default:
break;
}
}
else if (type.vendor_id == PEN_TCG)
{
if (!imv_attestation_process(attr, out_msg, state,
this->supported_algorithms, this->supported_dh_groups,
this->pts_db, this->pts_credmgr))
{
result = TNC_RESULT_FATAL;
break;
}
}
}
enumerator->destroy(enumerator);
if (fatal_error || result != TNC_RESULT_SUCCESS)
{
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
result = out_msg->send_assessment(out_msg);
if (result == TNC_RESULT_SUCCESS)
{
result = this->agent->provide_recommendation(this->agent, state);
}
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id,
TNC_MessageType msg_type, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id,
TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_long_data(this->agent, state, id,
src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* Build an IETF Attribute Request attribute for missing attributes
*/
static pa_tnc_attr_t* build_attr_request(uint32_t received)
{
pa_tnc_attr_t *attr;
ietf_attr_attr_request_t *attr_cast;
attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
attr_cast = (ietf_attr_attr_request_t*)attr;
if (!(received & IMV_ATTESTATION_ATTR_PRODUCT_INFO) ||
!(received & IMV_ATTESTATION_ATTR_STRING_VERSION))
{
attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION);
attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
}
if (!(received & IMV_ATTESTATION_ATTR_DEVICE_ID))
{
attr_cast->add(attr_cast, PEN_ITA, ITA_ATTR_DEVICE_ID);
}
return attr;
}
METHOD(imv_agent_if_t, batch_ending, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id)
{
imv_msg_t *out_msg;
imv_state_t *state;
imv_session_t *session;
imv_attestation_state_t *attestation_state;
imv_attestation_handshake_state_t handshake_state;
imv_workitem_t *workitem;
TNC_IMV_Action_Recommendation rec;
TNC_IMV_Evaluation_Result eval;
TNC_IMVID imv_id;
TNC_Result result = TNC_RESULT_SUCCESS;
pts_t *pts;
int pid;
uint32_t actions;
enumerator_t *enumerator;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
attestation_state = (imv_attestation_state_t*)state;
pts = attestation_state->get_pts(attestation_state);
handshake_state = attestation_state->get_handshake_state(attestation_state);
actions = state->get_action_flags(state);
session = state->get_session(state);
imv_id = this->agent->get_id(this->agent);
/* exit if a recommendation has already been provided */
if (actions & IMV_ATTESTATION_REC)
{
return TNC_RESULT_SUCCESS;
}
/* send an IETF attribute request if no platform info was received */
if (!(actions & IMV_ATTESTATION_ATTR_REQ))
{
if ((actions & IMV_ATTESTATION_ATTR_MUST) != IMV_ATTESTATION_ATTR_MUST)
{
imv_msg_t *os_msg;
/* create attribute request for missing mandatory attributes */
os_msg = imv_msg_create(this->agent, state, id, imv_id,
TNC_IMCID_ANY, msg_types[1]);
os_msg->add_attribute(os_msg, build_attr_request(actions));
result = os_msg->send(os_msg, FALSE);
os_msg->destroy(os_msg);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
}
state->set_action_flags(state, IMV_ATTESTATION_ATTR_REQ);
}
if (!session->get_policy_started(session) &&
(actions & IMV_ATTESTATION_ATTR_PRODUCT_INFO) &&
(actions & IMV_ATTESTATION_ATTR_STRING_VERSION) &&
(actions & IMV_ATTESTATION_ATTR_DEVICE_ID))
{
if (imcv_db)
{
/* start the policy script */
if (!imcv_db->policy_script(imcv_db, session, TRUE))
{
DBG1(DBG_IMV, "error in policy script start");
}
}
else
{
DBG2(DBG_IMV, "no workitems available - no evaluation possible");
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
session->set_policy_started(session, TRUE);
}
}
if (handshake_state == IMV_ATTESTATION_STATE_INIT)
{
pa_tnc_attr_t *attr;
pts_proto_caps_flag_t flags;
out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
msg_types[0]);
/* Send Request Protocol Capabilities attribute */
flags = pts->get_proto_caps(pts);
attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Send Measurement Algorithms attribute */
attr = tcg_pts_attr_meas_algo_create(this->supported_algorithms, FALSE);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_DISCOVERY);
/* send these initial PTS attributes and exit */
result = out_msg->send(out_msg, FALSE);
out_msg->destroy(out_msg);
return result;
}
/* exit if we are not ready yet for PTS measurements */
if (!(actions & IMV_ATTESTATION_ALGO))
{
return TNC_RESULT_SUCCESS;
}
session->get_session_id(session, &pid, NULL);
pts->set_platform_id(pts, pid);
/* create an empty out message - we might need it */
out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
msg_types[0]);
/* establish the PTS measurements to be taken */
if (!(actions & IMV_ATTESTATION_FILE_MEAS))
{
bool is_dir, no_workitems = TRUE;
uint32_t delimiter = SOLIDUS_UTF;
uint16_t request_id;
pa_tnc_attr_t *attr;
char *pathname;
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_END);
enumerator = session->create_workitem_enumerator(session);
if (enumerator)
{
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY)
{
continue;
}
switch (workitem->get_type(workitem))
{
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_FILE_MEAS:
case IMV_WORKITEM_FILE_META:
is_dir = FALSE;
break;
case IMV_WORKITEM_DIR_REF_MEAS:
case IMV_WORKITEM_DIR_MEAS:
case IMV_WORKITEM_DIR_META:
is_dir = TRUE;
break;
case IMV_WORKITEM_TPM_ATTEST:
{
pts_component_t *comp;
pts_comp_func_name_t *comp_name;
bool no_d_flag, no_t_flag;
char result_str[BUF_LEN];
workitem->set_imv_id(workitem, imv_id);
no_workitems = FALSE;
no_d_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D);
no_t_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T);
if (no_d_flag || no_t_flag)
{
snprintf(result_str, BUF_LEN, "%s%s%s",
(no_t_flag) ? "no TPM available" : "",
(no_t_flag && no_d_flag) ? ", " : "",
(no_d_flag) ? "no DH nonce negotiation" : "");
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
session->remove_workitem(session, enumerator);
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
continue;
}
/* do TPM BIOS measurements */
if (strchr(workitem->get_arg_str(workitem), 'B'))
{
comp_name = pts_comp_func_name_create(PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_IMA,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED);
comp = attestation_state->create_component(
attestation_state, comp_name,
0, this->pts_db);
if (!comp)
{
comp_name->log(comp_name, "unregistered ");
comp_name->destroy(comp_name);
}
}
/* do TPM IMA measurements */
if (strchr(workitem->get_arg_str(workitem), 'I'))
{
comp_name = pts_comp_func_name_create(PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_IMA,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_OS);
comp = attestation_state->create_component(
attestation_state, comp_name,
0, this->pts_db);
if (!comp)
{
comp_name->log(comp_name, "unregistered ");
comp_name->destroy(comp_name);
}
}
/* do TPM TRUSTED BOOT measurements */
if (strchr(workitem->get_arg_str(workitem), 'T'))
{
comp_name = pts_comp_func_name_create(PEN_ITA,
PTS_ITA_COMP_FUNC_NAME_TBOOT,
PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED);
comp = attestation_state->create_component(
attestation_state, comp_name,
0, this->pts_db);
if (!comp)
{
comp_name->log(comp_name, "unregistered ");
comp_name->destroy(comp_name);
}
}
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_NONCE_REQ);
continue;
}
default:
continue;
}
/* initiate file and directory measurements */
pathname = this->pts_db->get_pathname(this->pts_db, is_dir,
workitem->get_arg_int(workitem));
if (!pathname)
{
continue;
}
workitem->set_imv_id(workitem, imv_id);
no_workitems = FALSE;
if (workitem->get_type(workitem) == IMV_WORKITEM_FILE_META)
{
TNC_IMV_Action_Recommendation rec;
TNC_IMV_Evaluation_Result eval;
char result_str[BUF_LEN];
DBG2(DBG_IMV, "IMV %d requests metadata for %s '%s'",
imv_id, is_dir ? "directory" : "file", pathname);
/* currently just fire and forget metadata requests */
attr = tcg_pts_attr_req_file_meta_create(is_dir,
delimiter, pathname);
snprintf(result_str, BUF_LEN, "%s metadata requested",
is_dir ? "directory" : "file");
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
session->remove_workitem(session, enumerator);
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
}
else
{
/* use lower 16 bits of the workitem ID as request ID */
request_id = workitem->get_id(workitem) & 0xffff;
DBG2(DBG_IMV, "IMV %d requests measurement %d for %s '%s'",
imv_id, request_id, is_dir ? "directory" : "file",
pathname);
attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
delimiter, pathname);
}
free(pathname);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
}
enumerator->destroy(enumerator);
/* sent all file and directory measurement and metadata requests */
state->set_action_flags(state, IMV_ATTESTATION_FILE_MEAS);
if (no_workitems)
{
DBG2(DBG_IMV, "IMV %d has no workitems - "
"no evaluation requested", imv_id);
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
}
}
}
/* check the IMV state for the next PA-TNC attributes to send */
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST)
{
if (!imv_attestation_build(out_msg, state,
this->supported_dh_groups, this->pts_db))
{
imv_reason_string_t *reason_string;
chunk_t result;
char *result_str;
reason_string = imv_reason_string_create("en", ", ");
attestation_state->add_comp_evid_reasons(attestation_state,
reason_string);
result = reason_string->get_encoding(reason_string);
result_str = strndup(result.ptr, result.len);
reason_string->destroy(reason_string);
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
session->remove_workitem(session, enumerator);
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
}
break;
}
}
enumerator->destroy(enumerator);
/* finalized all workitems? */
if (session->get_policy_started(session) &&
session->get_workitem_count(session, imv_id) == 0 &&
attestation_state->get_handshake_state(attestation_state) ==
IMV_ATTESTATION_STATE_END)
{
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
state->set_action_flags(state, IMV_ATTESTATION_REC);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* send non-empty PA-TNC message with excl flag not set */
if (out_msg->get_attribute_count(out_msg))
{
result = out_msg->send(out_msg, FALSE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
private_imv_attestation_agent_t *this, TNC_ConnectionID id)
{
TNC_IMVID imv_id;
imv_state_t *state;
imv_attestation_state_t *attestation_state;
imv_session_t *session;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
attestation_state = (imv_attestation_state_t*)state;
session = state->get_session(state);
imv_id = this->agent->get_id(this->agent);
if (imcv_db)
{
TNC_IMV_Evaluation_Result eval;
TNC_IMV_Action_Recommendation rec;
imv_workitem_t *workitem;
enumerator_t *enumerator;
int pending_file_meas = 0;
char *result_str;
chunk_t result_buf;
bio_writer_t *result;
enumerator = session->create_workitem_enumerator(session);
if (enumerator)
{
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_imv_id(workitem) != imv_id)
{
continue;
}
result = bio_writer_create(128);
switch (workitem->get_type(workitem))
{
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_FILE_MEAS:
case IMV_WORKITEM_DIR_REF_MEAS:
case IMV_WORKITEM_DIR_MEAS:
result_str = "pending file measurements";
pending_file_meas++;
break;
case IMV_WORKITEM_TPM_ATTEST:
attestation_state->finalize_components(attestation_state,
result);
result->write_data(result,
chunk_from_str("; pending component evidence"));
result->write_uint8(result, '\0');
result_buf = result->get_buf(result);
result_str = result_buf.ptr;
break;
default:
result->destroy(result);
continue;
}
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
result->destroy(result);
}
enumerator->destroy(enumerator);
if (pending_file_meas)
{
DBG1(DBG_IMV, "failure due to %d pending file measurements",
pending_file_meas);
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_FILE_MEAS_PEND);
}
}
}
return this->agent->provide_recommendation(this->agent, state);
}
METHOD(imv_agent_if_t, destroy, void,
private_imv_attestation_agent_t *this)
{
if (this->pts_creds)
{
this->pts_credmgr->remove_set(this->pts_credmgr,
this->pts_creds->get_set(this->pts_creds));
this->pts_creds->destroy(this->pts_creds);
}
DESTROY_IF(this->pts_db);
DESTROY_IF(this->pts_credmgr);
DESTROY_IF(this->agent);
free(this);
}
/**
* Described in header.
*/
imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id,
TNC_Version *actual_version)
{
private_imv_attestation_agent_t *this;
imv_agent_t *agent;
char *hash_alg, *dh_group, *cadir;
bool mandatory_dh_groups;
agent = imv_agent_create(name, msg_types, countof(msg_types), id,
actual_version);
if (!agent)
{
return NULL;
}
hash_alg = lib->settings->get_str(lib->settings,
"%s.plugins.imv-attestation.hash_algorithm", "sha256", lib->ns);
dh_group = lib->settings->get_str(lib->settings,
"%s.plugins.imv-attestation.dh_group", "ecp256", lib->ns);
mandatory_dh_groups = lib->settings->get_bool(lib->settings,
"%s.plugins.imv-attestation.mandatory_dh_groups", TRUE, lib->ns);
cadir = lib->settings->get_str(lib->settings,
"%s.plugins.imv-attestation.cadir", NULL, lib->ns);
INIT(this,
.public = {
.bind_functions = _bind_functions,
.notify_connection_change = _notify_connection_change,
.receive_message = _receive_message,
.receive_message_long = _receive_message_long,
.batch_ending = _batch_ending,
.solicit_recommendation = _solicit_recommendation,
.destroy = _destroy,
},
.agent = agent,
.supported_algorithms = PTS_MEAS_ALGO_NONE,
.supported_dh_groups = PTS_DH_GROUP_NONE,
.pts_credmgr = credential_manager_create(),
.pts_creds = pts_creds_create(cadir),
.pts_db = pts_database_create(imcv_db),
);
if (!pts_meas_algo_probe(&this->supported_algorithms) ||
!pts_dh_group_probe(&this->supported_dh_groups, mandatory_dh_groups) ||
!pts_meas_algo_update(hash_alg, &this->supported_algorithms) ||
!pts_dh_group_update(dh_group, &this->supported_dh_groups))
{
destroy(this);
return NULL;
}
if (this->pts_creds)
{
this->pts_credmgr->add_set(this->pts_credmgr,
this->pts_creds->get_set(this->pts_creds));
}
return &this->public;
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation_agent_t imv_attestation_agent
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_AGENT_H_
#define IMV_ATTESTATION_AGENT_H_
#include <imv/imv_agent_if.h>
/**
* Creates a Attestation IMV agent
*
* @param name Name of the IMV
* @param id ID of the IMV
* @param actual_version TNC IF-IMV version
*/
imv_agent_if_t* imv_attestation_agent_create(const char* name, TNC_IMVID id,
TNC_Version *actual_version);
#endif /** IMV_ATTESTATION_AGENT_H_ @}*/
@@ -0,0 +1,150 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_attestation_build.h"
#include "imv_attestation_state.h"
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h>
#include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_get_aik.h>
#include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
#include <utils/debug.h>
bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db)
{
imv_attestation_state_t *attestation_state;
imv_attestation_handshake_state_t handshake_state;
pts_t *pts;
pa_tnc_attr_t *attr = NULL;
attestation_state = (imv_attestation_state_t*)state;
handshake_state = attestation_state->get_handshake_state(attestation_state);
pts = attestation_state->get_pts(attestation_state);
switch (handshake_state)
{
case IMV_ATTESTATION_STATE_NONCE_REQ:
{
int min_nonce_len;
/* Send DH nonce parameters request attribute */
min_nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imv-attestation.min_nonce_len", 0, lib->ns);
attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
supported_dh_groups);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_TPM_INIT);
break;
}
case IMV_ATTESTATION_STATE_TPM_INIT:
{
pts_meas_algorithms_t selected_algorithm;
chunk_t initiator_value, initiator_nonce;
if (!(state->get_action_flags(state) & IMV_ATTESTATION_DH_NONCE))
{
break;
}
/* Send DH nonce finish attribute */
selected_algorithm = pts->get_meas_algorithm(pts);
pts->get_my_public_value(pts, &initiator_value, &initiator_nonce);
attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm,
initiator_value, initiator_nonce);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Send Get TPM Version attribute */
attr = tcg_pts_attr_get_tpm_version_info_create();
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Send Get AIK attribute */
attr = tcg_pts_attr_get_aik_create();
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_COMP_EVID);
break;
}
case IMV_ATTESTATION_STATE_COMP_EVID:
{
tcg_pts_attr_req_func_comp_evid_t *attr_cast;
enumerator_t *enumerator;
pts_comp_func_name_t *name;
uint8_t flags;
uint32_t depth;
bool first_component = TRUE;
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_END);
if (!pts->get_aik_id(pts))
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK);
return FALSE;
}
enumerator = attestation_state->create_component_enumerator(
attestation_state);
while (enumerator->enumerate(enumerator, &flags, &depth, &name))
{
if (first_component)
{
attr = tcg_pts_attr_req_func_comp_evid_create();
attr->set_noskip_flag(attr, TRUE);
first_component = FALSE;
DBG2(DBG_IMV, "evidence request by");
}
name->log(name, " ");
/* TODO check flags against negotiated_caps */
attr_cast = (tcg_pts_attr_req_func_comp_evid_t *)attr;
attr_cast->add_component(attr_cast, flags, depth, name);
}
enumerator->destroy(enumerator);
if (attr)
{
/* Send Request Functional Component Evidence attribute */
out_msg->add_attribute(out_msg, attr);
/* Send Generate Attestation Evidence attribute */
attr = tcg_pts_attr_gen_attest_evid_create();
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_EVID_FINAL);
}
break;
}
default:
break;
}
return TRUE;
}
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation_build_t imv_attestation_build
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_BUILD_H_
#define IMV_ATTESTATION_BUILD_H_
#include "imv_attestation_state.h"
#include <imv/imv_msg.h>
#include <library.h>
#include <pts/pts_database.h>
#include <pts/pts_dh_group.h>
#include <pts/pts_meas_algo.h>
/**
* Process a TCG PTS attribute
*
* @param out_msg outbound PA-TNC message to be built
* @param state state of a given connection
* @param supported_dh_groups supported DH groups
* @param pts_db PTS configuration database
* @return TRUE if successful
*/
bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db);
#endif /** IMV_ATTESTATION_BUILD_H_ @}*/
@@ -0,0 +1,563 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#define _GNU_SOURCE /* for stdndup() */
#include <string.h>
#include "imv_attestation_process.h"
#include <imcv.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <pts/pts.h>
#include <tcg/pts/tcg_pts_attr_aik.h>
#include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h>
#include <tcg/pts/tcg_pts_attr_file_meas.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_simple_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_simple_evid_final.h>
#include <tcg/pts/tcg_pts_attr_tpm_version_info.h>
#include <tcg/pts/tcg_pts_attr_unix_file_meta.h>
#include <utils/debug.h>
#include <crypto/hashers/hasher.h>
#include <inttypes.h>
bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg,
imv_state_t *state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db,
credential_manager_t *pts_credmgr)
{
imv_session_t *session;
imv_attestation_state_t *attestation_state;
pen_type_t attr_type;
pts_t *pts;
session = state->get_session(state);
attestation_state = (imv_attestation_state_t*)state;
pts = attestation_state->get_pts(attestation_state);
attr_type = attr->get_type(attr);
switch (attr_type.type)
{
case TCG_PTS_PROTO_CAPS:
{
tcg_pts_attr_proto_caps_t *attr_cast;
pts_proto_caps_flag_t flags;
attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
flags = attr_cast->get_flags(attr_cast);
pts->set_proto_caps(pts, flags);
break;
}
case TCG_PTS_MEAS_ALGO_SELECTION:
{
tcg_pts_attr_meas_algo_t *attr_cast;
pts_meas_algorithms_t selected_algorithm;
attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
selected_algorithm = attr_cast->get_algorithms(attr_cast);
if (!(selected_algorithm & supported_algorithms))
{
DBG1(DBG_IMV, "PTS-IMC selected unsupported"
" measurement algorithm");
return FALSE;
}
pts->set_meas_algorithm(pts, selected_algorithm);
state->set_action_flags(state, IMV_ATTESTATION_ALGO);
break;
}
case TCG_PTS_DH_NONCE_PARAMS_RESP:
{
tcg_pts_attr_dh_nonce_params_resp_t *attr_cast;
int nonce_len, min_nonce_len;
pts_dh_group_t dh_group;
pts_meas_algorithms_t offered_algorithms, selected_algorithm;
chunk_t responder_value, responder_nonce;
attr_cast = (tcg_pts_attr_dh_nonce_params_resp_t*)attr;
responder_nonce = attr_cast->get_responder_nonce(attr_cast);
/* check compliance of responder nonce length */
min_nonce_len = lib->settings->get_int(lib->settings,
"%s.plugins.imv-attestation.min_nonce_len", 0, lib->ns);
nonce_len = responder_nonce.len;
if (nonce_len < PTS_MIN_NONCE_LEN ||
(min_nonce_len > 0 && nonce_len < min_nonce_len))
{
attr = pts_dh_nonce_error_create(
max(PTS_MIN_NONCE_LEN, min_nonce_len),
PTS_MAX_NONCE_LEN);
out_msg->add_attribute(out_msg, attr);
break;
}
dh_group = attr_cast->get_dh_group(attr_cast);
if (!(dh_group & supported_dh_groups))
{
DBG1(DBG_IMV, "PTS-IMC selected unsupported DH group");
return FALSE;
}
offered_algorithms = attr_cast->get_hash_algo_set(attr_cast);
selected_algorithm = pts_meas_algo_select(supported_algorithms,
offered_algorithms);
if (selected_algorithm == PTS_MEAS_ALGO_NONE)
{
attr = pts_hash_alg_error_create(supported_algorithms);
out_msg->add_attribute(out_msg, attr);
break;
}
pts->set_dh_hash_algorithm(pts, selected_algorithm);
if (!pts->create_dh_nonce(pts, dh_group, nonce_len))
{
return FALSE;
}
responder_value = attr_cast->get_responder_value(attr_cast);
pts->set_peer_public_value(pts, responder_value,
responder_nonce);
/* Calculate secret assessment value */
if (!pts->calculate_secret(pts))
{
return FALSE;
}
state->set_action_flags(state, IMV_ATTESTATION_DH_NONCE);
break;
}
case TCG_PTS_TPM_VERSION_INFO:
{
tcg_pts_attr_tpm_version_info_t *attr_cast;
chunk_t tpm_version_info;
attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr;
tpm_version_info = attr_cast->get_tpm_version_info(attr_cast);
pts->set_tpm_version_info(pts, tpm_version_info);
break;
}
case TCG_PTS_AIK:
{
tcg_pts_attr_aik_t *attr_cast;
certificate_t *aik, *issuer;
public_key_t *public;
chunk_t keyid, keyid_hex, device_id;
int aik_id;
enumerator_t *e;
bool trusted = FALSE, trusted_chain = FALSE;
attr_cast = (tcg_pts_attr_aik_t*)attr;
aik = attr_cast->get_aik(attr_cast);
if (!aik)
{
DBG1(DBG_IMV, "AIK unavailable");
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK);
break;
}
/* check trust into public key as stored in the database */
public = aik->get_public_key(aik);
public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid);
DBG1(DBG_IMV, "verifying AIK with keyid %#B", &keyid);
keyid_hex = chunk_to_hex(keyid, NULL, FALSE);
if (session->get_device_id(session, &device_id) &&
chunk_equals(keyid_hex, device_id))
{
trusted = session->get_device_trust(session);
}
else
{
DBG1(DBG_IMV, "device ID unknown or different from AIK keyid");
}
DBG1(DBG_IMV, "AIK public key is %strusted", trusted ? "" : "not ");
public->destroy(public);
chunk_free(&keyid_hex);
if (aik->get_type(aik) == CERT_X509)
{
e = pts_credmgr->create_trusted_enumerator(pts_credmgr,
KEY_ANY, aik->get_issuer(aik), FALSE);
while (e->enumerate(e, &issuer))
{
if (aik->issued_by(aik, issuer, NULL))
{
trusted_chain = TRUE;
break;
}
}
e->destroy(e);
DBG1(DBG_IMV, "AIK certificate is %strusted",
trusted_chain ? "" : "not ");
if (!trusted || !trusted_chain)
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK);
break;
}
}
session->get_session_id(session, NULL, &aik_id);
pts->set_aik(pts, aik, aik_id);
break;
}
case TCG_PTS_FILE_MEAS:
{
TNC_IMV_Evaluation_Result eval;
TNC_IMV_Action_Recommendation rec;
tcg_pts_attr_file_meas_t *attr_cast;
uint16_t request_id;
int arg_int, file_count;
pts_meas_algorithms_t algo;
pts_file_meas_t *measurements;
imv_workitem_t *workitem, *found = NULL;
imv_workitem_type_t type;
char result_str[BUF_LEN];
bool is_dir, correct;
enumerator_t *enumerator;
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
algo = pts->get_meas_algorithm(pts);
attr_cast = (tcg_pts_attr_file_meas_t*)attr;
measurements = attr_cast->get_measurements(attr_cast);
request_id = measurements->get_request_id(measurements);
file_count = measurements->get_file_count(measurements);
DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
request_id, file_count, (file_count == 1) ? "":"s");
if (request_id)
{
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
/* request ID consist of lower 16 bits of workitem ID */
if ((workitem->get_id(workitem) & 0xffff) == request_id)
{
found = workitem;
break;
}
}
if (!found)
{
DBG1(DBG_IMV, " no entry found for file measurement "
"request %d", request_id);
enumerator->destroy(enumerator);
break;
}
type = found->get_type(found);
arg_int = found->get_arg_int(found);
switch (type)
{
default:
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_FILE_MEAS:
is_dir = FALSE;
break;
case IMV_WORKITEM_DIR_REF_MEAS:
case IMV_WORKITEM_DIR_MEAS:
is_dir = TRUE;
}
switch (type)
{
case IMV_WORKITEM_FILE_MEAS:
case IMV_WORKITEM_DIR_MEAS:
{
enumerator_t *e;
/* check hashes from database against measurements */
e = pts_db->create_file_hash_enumerator(pts_db,
pts->get_platform_id(pts),
algo, is_dir, arg_int);
if (!e)
{
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
break;
}
correct = measurements->verify(measurements, e, is_dir);
if (!correct)
{
attestation_state->set_measurement_error(
attestation_state,
IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL);
eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR;
}
e->destroy(e);
snprintf(result_str, BUF_LEN, "%s measurement%s correct",
is_dir ? "directory" : "file",
correct ? "" : " not");
break;
}
case IMV_WORKITEM_FILE_REF_MEAS:
case IMV_WORKITEM_DIR_REF_MEAS:
{
enumerator_t *e;
char *filename;
chunk_t measurement;
e = measurements->create_enumerator(measurements);
while (e->enumerate(e, &filename, &measurement))
{
if (pts_db->add_file_measurement(pts_db,
pts->get_platform_id(pts), algo, measurement,
filename, is_dir, arg_int) != SUCCESS)
{
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
}
}
e->destroy(e);
snprintf(result_str, BUF_LEN, "%s reference measurement "
"successful", is_dir ? "directory" : "file");
break;
}
default:
break;
}
session->remove_workitem(session, enumerator);
enumerator->destroy(enumerator);
rec = found->set_result(found, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, found);
found->destroy(found);
}
else
{
measurements->check(measurements, pts_db,
pts->get_platform_id(pts), algo);
}
break;
}
case TCG_PTS_UNIX_FILE_META:
{
tcg_pts_attr_file_meta_t *attr_cast;
int file_count;
pts_file_meta_t *metadata;
pts_file_metadata_t *entry;
time_t created, modified, accessed;
bool utc = FALSE;
enumerator_t *e;
attr_cast = (tcg_pts_attr_file_meta_t*)attr;
metadata = attr_cast->get_metadata(attr_cast);
file_count = metadata->get_file_count(metadata);
DBG1(DBG_IMV, "metadata request returned %d file%s:",
file_count, (file_count == 1) ? "":"s");
e = metadata->create_enumerator(metadata);
while (e->enumerate(e, &entry))
{
DBG1(DBG_IMV, " '%s' (%"PRIu64" bytes)"
" owner %"PRIu64", group %"PRIu64", type %N",
entry->filename, entry->filesize, entry->owner,
entry->group, pts_file_type_names, entry->type);
created = entry->created;
modified = entry->modified;
accessed = entry->accessed;
DBG1(DBG_IMV, " created %T, modified %T, accessed %T",
&created, utc, &modified, utc, &accessed, utc);
}
e->destroy(e);
break;
}
case TCG_PTS_SIMPLE_COMP_EVID:
{
tcg_pts_attr_simple_comp_evid_t *attr_cast;
pts_comp_func_name_t *name;
pts_comp_evidence_t *evidence;
pts_component_t *comp;
uint32_t depth;
status_t status;
attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr;
evidence = attr_cast->get_comp_evidence(attr_cast);
name = evidence->get_comp_func_name(evidence, &depth);
comp = attestation_state->get_component(attestation_state, name);
if (!comp)
{
DBG1(DBG_IMV, " no entry found for component evidence request");
break;
}
status = comp->verify(comp, name->get_qualifier(name), pts, evidence);
if (status == VERIFY_ERROR || status == FAILED)
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_COMP_EVID_FAIL);
name->log(name, " measurement mismatch for ");
}
break;
}
case TCG_PTS_SIMPLE_EVID_FINAL:
{
tcg_pts_attr_simple_evid_final_t *attr_cast;
uint8_t flags;
pts_meas_algorithms_t comp_hash_algorithm;
chunk_t pcr_comp, tpm_quote_sig, evid_sig;
chunk_t pcr_composite, quote_info, result_buf;
imv_workitem_t *workitem;
imv_reason_string_t *reason_string;
enumerator_t *enumerator;
bool use_quote2, use_ver_info;
bio_writer_t *result;
attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr;
flags = attr_cast->get_quote_info(attr_cast, &comp_hash_algorithm,
&pcr_comp, &tpm_quote_sig);
if (flags != PTS_SIMPLE_EVID_FINAL_NO)
{
use_quote2 = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 ||
flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
use_ver_info = (flags == PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER);
/* Construct PCR Composite and TPM Quote Info structures */
if (!pts->get_quote_info(pts, use_quote2, use_ver_info,
comp_hash_algorithm, &pcr_composite, &quote_info))
{
DBG1(DBG_IMV, "unable to construct TPM Quote Info");
return FALSE;
}
if (!chunk_equals(pcr_comp, pcr_composite))
{
DBG1(DBG_IMV, "received PCR Composite does not match "
"constructed one");
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
goto quote_error;
}
DBG2(DBG_IMV, "received PCR Composite matches constructed one");
if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig))
{
attestation_state->set_measurement_error(attestation_state,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
goto quote_error;
}
DBG2(DBG_IMV, "TPM Quote Info signature verification successful");
quote_error:
free(pcr_composite.ptr);
free(quote_info.ptr);
/**
* Finalize any pending measurement registrations and check
* if all expected component measurements were received
*/
result = bio_writer_create(128);
attestation_state->finalize_components(attestation_state,
result);
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST)
{
TNC_IMV_Action_Recommendation rec;
TNC_IMV_Evaluation_Result eval;
uint32_t error;
error = attestation_state->get_measurement_error(
attestation_state);
if (error & (IMV_ATTESTATION_ERROR_COMP_EVID_FAIL |
IMV_ATTESTATION_ERROR_COMP_EVID_PEND |
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL))
{
reason_string = imv_reason_string_create("en", ", ");
attestation_state->add_comp_evid_reasons(
attestation_state, reason_string);
result->write_data(result, chunk_from_str("; "));
result->write_data(result,
reason_string->get_encoding(reason_string));
reason_string->destroy(reason_string);
eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR;
}
else
{
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
}
session->remove_workitem(session, enumerator);
result->write_uint8(result, '\0');
result_buf = result->get_buf(result);
rec = workitem->set_result(workitem, result_buf.ptr,
eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
attestation_state->set_handshake_state(attestation_state,
IMV_ATTESTATION_STATE_END);
break;
}
}
enumerator->destroy(enumerator);
result->destroy(result);
}
if (attr_cast->get_evid_sig(attr_cast, &evid_sig))
{
/** TODO: What to do with Evidence Signature */
DBG1(DBG_IMV, "this version of the Attestation IMV can not "
"handle Evidence Signatures");
}
break;
}
/* TODO: Not implemented yet */
case TCG_PTS_INTEG_MEAS_LOG:
/* Attributes using XML */
case TCG_PTS_TEMPL_REF_MANI_SET_META:
case TCG_PTS_VERIFICATION_RESULT:
case TCG_PTS_INTEG_REPORT:
/* On Windows only*/
case TCG_PTS_WIN_FILE_META:
case TCG_PTS_REGISTRY_VALUE:
/* Received on IMC side only*/
case TCG_PTS_REQ_PROTO_CAPS:
case TCG_PTS_DH_NONCE_PARAMS_REQ:
case TCG_PTS_DH_NONCE_FINISH:
case TCG_PTS_MEAS_ALGO:
case TCG_PTS_GET_TPM_VERSION_INFO:
case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
case TCG_PTS_UPDATE_TEMPL_REF_MANI:
case TCG_PTS_GET_AIK:
case TCG_PTS_REQ_FUNC_COMP_EVID:
case TCG_PTS_GEN_ATTEST_EVID:
case TCG_PTS_REQ_FILE_META:
case TCG_PTS_REQ_FILE_MEAS:
case TCG_PTS_REQ_INTEG_MEAS_LOG:
default:
DBG1(DBG_IMV, "received unsupported attribute '%N'",
tcg_attr_names, attr->get_type(attr));
break;
}
return TRUE;
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation_process_t imv_attestation_process
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_PROCESS_H_
#define IMV_ATTESTATION_PROCESS_H_
#include "imv_attestation_state.h"
#include <library.h>
#include <collections/linked_list.h>
#include <credentials/credential_manager.h>
#include <crypto/hashers/hasher.h>
#include <imv/imv_msg.h>
#include <pa_tnc/pa_tnc_attr.h>
#include <pts/pts_database.h>
#include <pts/pts_dh_group.h>
#include <pts/pts_meas_algo.h>
/**
* Process a TCG PTS attribute
*
* @param attr PA-TNC attribute to be processed
* @param out_msg PA-TNC message containing error messages
* @param state state of a given connection
* @param supported_algorithms supported PTS measurement algorithms
* @param supported_dh_groups supported DH groups
* @param pts_db PTS configuration database
* @param pts_credmgr PTS credential manager
* @return TRUE if successful
*/
bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg,
imv_state_t *state,
pts_meas_algorithms_t supported_algorithms,
pts_dh_group_t supported_dh_groups,
pts_database_t *pts_db,
credential_manager_t *pts_credmgr);
#endif /** IMV_ATTESTATION_PROCESS_H_ @}*/
@@ -0,0 +1,560 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_attestation_state.h"
#include <imcv.h>
#include <imv/imv_lang_string.h>
#include "imv/imv_reason_string.h"
#include <tncif_policy.h>
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_imv_attestation_state_t private_imv_attestation_state_t;
typedef struct file_meas_request_t file_meas_request_t;
typedef struct func_comp_t func_comp_t;
/**
* Private data of an imv_attestation_state_t object.
*/
struct private_imv_attestation_state_t {
/**
* Public members of imv_attestation_state_t
*/
imv_attestation_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
uint32_t max_msg_len;
/**
* Flags set for completed actions
*/
uint32_t action_flags;
/**
* IMV database session associated with TNCCS connection
*/
imv_session_t *session;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* IMV Attestation handshake state
*/
imv_attestation_handshake_state_t handshake_state;
/**
* IMV action recommendation
*/
TNC_IMV_Action_Recommendation rec;
/**
* IMV evaluation result
*/
TNC_IMV_Evaluation_Result eval;
/**
* List of Functional Components
*/
linked_list_t *components;
/**
* PTS object
*/
pts_t *pts;
/**
* Measurement error flags
*/
uint32_t measurement_error;
/**
* TNC Reason String
*/
imv_reason_string_t *reason_string;
};
/**
* PTS Functional Component entry
*/
struct func_comp_t {
pts_component_t *comp;
pts_comp_func_name_t* name;
};
/**
* Frees a func_comp_t object
*/
static void free_func_comp(func_comp_t *this)
{
this->comp->destroy(this->comp);
this->name->destroy(this->name);
free(this);
}
/**
* Supported languages
*/
static char* languages[] = { "en", "de", "mn" };
/**
* Table of reason strings
*/
static imv_lang_string_t reason_file_meas_fail[] = {
{ "en", "Incorrect file measurement" },
{ "de", "Falsche Dateimessung" },
{ "mn", "Буруу байгаа файл" },
{ NULL, NULL }
};
static imv_lang_string_t reason_file_meas_pend[] = {
{ "en", "Pending file measurement" },
{ "de", "Ausstehende Dateimessung" },
{ "mn", "Xүлээгдэж байгаа файл" },
{ NULL, NULL }
};
static imv_lang_string_t reason_no_trusted_aik[] = {
{ "en", "No trusted AIK available" },
{ "de", "Kein vetrauenswürdiger AIK verfügbar" },
{ NULL, NULL }
};
static imv_lang_string_t reason_comp_evid_fail[] = {
{ "en", "Incorrect component evidence" },
{ "de", "Falsche Komponenten-Evidenz" },
{ "mn", "Буруу компонент хэмжилт" },
{ NULL, NULL }
};
static imv_lang_string_t reason_comp_evid_pend[] = {
{ "en", "Pending component evidence" },
{ "de", "Ausstehende Komponenten-Evidenz" },
{ "mn", "Xүлээгдэж компонент хэмжилт" },
{ NULL, NULL }
};
static imv_lang_string_t reason_tpm_quote_fail[] = {
{ "en", "Invalid TPM Quote signature received" },
{ "de", "Falsche TPM Quote Signature erhalten" },
{ "mn", "Буруу TPM Quote гарын үсэг" },
{ NULL, NULL }
};
METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
private_imv_attestation_state_t *this)
{
return this->connection_id;
}
METHOD(imv_state_t, has_long, bool,
private_imv_attestation_state_t *this)
{
return this->has_long;
}
METHOD(imv_state_t, has_excl, bool,
private_imv_attestation_state_t *this)
{
return this->has_excl;
}
METHOD(imv_state_t, set_flags, void,
private_imv_attestation_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imv_state_t, set_max_msg_len, void,
private_imv_attestation_state_t *this, uint32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imv_state_t, get_max_msg_len, uint32_t,
private_imv_attestation_state_t *this)
{
return this->max_msg_len;
}
METHOD(imv_state_t, set_action_flags, void,
private_imv_attestation_state_t *this, uint32_t flags)
{
this->action_flags |= flags;
}
METHOD(imv_state_t, get_action_flags, uint32_t,
private_imv_attestation_state_t *this)
{
return this->action_flags;
}
METHOD(imv_state_t, set_session, void,
private_imv_attestation_state_t *this, imv_session_t *session)
{
this->session = session;
}
METHOD(imv_state_t, get_session, imv_session_t*,
private_imv_attestation_state_t *this)
{
return this->session;
}
METHOD(imv_state_t, get_contracts, seg_contract_manager_t*,
private_imv_attestation_state_t *this)
{
return this->contracts;
}
METHOD(imv_state_t, change_state, void,
private_imv_attestation_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imv_state_t, get_recommendation, void,
private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation *rec,
TNC_IMV_Evaluation_Result *eval)
{
*rec = this->rec;
*eval = this->eval;
}
METHOD(imv_state_t, set_recommendation, void,
private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = rec;
this->eval = eval;
}
METHOD(imv_state_t, update_recommendation, void,
private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = tncif_policy_update_recommendation(this->rec, rec);
this->eval = tncif_policy_update_evaluation(this->eval, eval);
}
METHOD(imv_attestation_state_t, add_file_meas_reasons, void,
private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
{
if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL)
{
reason_string->add_reason(reason_string, reason_file_meas_fail);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_PEND)
{
reason_string->add_reason(reason_string, reason_file_meas_pend);
}
}
METHOD(imv_attestation_state_t, add_comp_evid_reasons, void,
private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
{
if (this->measurement_error & IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK)
{
reason_string->add_reason(reason_string, reason_no_trusted_aik);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_FAIL)
{
reason_string->add_reason(reason_string, reason_comp_evid_fail);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_PEND)
{
reason_string->add_reason(reason_string, reason_comp_evid_pend);
}
if (this->measurement_error & IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL)
{
reason_string->add_reason(reason_string, reason_tpm_quote_fail);
}
}
METHOD(imv_state_t, get_reason_string, bool,
private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
chunk_t *reason_string, char **reason_language)
{
*reason_language = imv_lang_string_select_lang(language_enumerator,
languages, countof(languages));
/* Instantiate a TNC Reason String object */
DESTROY_IF(this->reason_string);
this->reason_string = imv_reason_string_create(*reason_language, "\n");
add_file_meas_reasons(this, this->reason_string);
add_comp_evid_reasons(this, this->reason_string);
*reason_string = this->reason_string->get_encoding(this->reason_string);
return TRUE;
}
METHOD(imv_state_t, get_remediation_instructions, bool,
private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
chunk_t *string, char **lang_code, char **uri)
{
return FALSE;
}
METHOD(imv_state_t, destroy, void,
private_imv_attestation_state_t *this)
{
DESTROY_IF(this->session);
DESTROY_IF(this->reason_string);
this->components->destroy_function(this->components, (void *)free_func_comp);
this->pts->destroy(this->pts);
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imv_attestation_state_t, get_handshake_state,
imv_attestation_handshake_state_t, private_imv_attestation_state_t *this)
{
return this->handshake_state;
}
METHOD(imv_attestation_state_t, set_handshake_state, void,
private_imv_attestation_state_t *this,
imv_attestation_handshake_state_t new_state)
{
this->handshake_state = new_state;
}
METHOD(imv_attestation_state_t, get_pts, pts_t*,
private_imv_attestation_state_t *this)
{
return this->pts;
}
METHOD(imv_attestation_state_t, create_component, pts_component_t*,
private_imv_attestation_state_t *this, pts_comp_func_name_t *name,
uint32_t depth, pts_database_t *pts_db)
{
enumerator_t *enumerator;
func_comp_t *entry, *new_entry;
pts_component_t *component;
bool found = FALSE;
enumerator = this->components->create_enumerator(this->components);
while (enumerator->enumerate(enumerator, &entry))
{
if (name->equals(name, entry->comp->get_comp_func_name(entry->comp)))
{
found = TRUE;
break;
}
}
enumerator->destroy(enumerator);
if (found)
{
if (name->equals(name, entry->name))
{
/* duplicate entry */
return NULL;
}
new_entry = malloc_thing(func_comp_t);
new_entry->name = name->clone(name);
new_entry->comp = entry->comp->get_ref(entry->comp);
this->components->insert_last(this->components, new_entry);
return entry->comp;
}
else
{
component = imcv_pts_components->create(imcv_pts_components,
name, depth, pts_db);
if (!component)
{
/* unsupported component */
return NULL;
}
new_entry = malloc_thing(func_comp_t);
new_entry->name = name->clone(name);
new_entry->comp = component;
this->components->insert_last(this->components, new_entry);
return component;
}
}
/**
* Enumerate file measurement entries
*/
static bool entry_filter(void *null, func_comp_t **entry, uint8_t *flags,
void *i2, uint32_t *depth,
void *i3, pts_comp_func_name_t **comp_name)
{
pts_component_t *comp;
pts_comp_func_name_t *name;
comp = (*entry)->comp;
name = (*entry)->name;
*flags = comp->get_evidence_flags(comp);
*depth = comp->get_depth(comp);
*comp_name = name;
return TRUE;
}
METHOD(imv_attestation_state_t, create_component_enumerator, enumerator_t*,
private_imv_attestation_state_t *this)
{
return enumerator_create_filter(
this->components->create_enumerator(this->components),
(void*)entry_filter, NULL, NULL);
}
METHOD(imv_attestation_state_t, get_component, pts_component_t*,
private_imv_attestation_state_t *this, pts_comp_func_name_t *name)
{
enumerator_t *enumerator;
func_comp_t *entry;
pts_component_t *found = NULL;
enumerator = this->components->create_enumerator(this->components);
while (enumerator->enumerate(enumerator, &entry))
{
if (name->equals(name, entry->name))
{
found = entry->comp;
break;
}
}
enumerator->destroy(enumerator);
return found;
}
METHOD(imv_attestation_state_t, get_measurement_error, uint32_t,
private_imv_attestation_state_t *this)
{
return this->measurement_error;
}
METHOD(imv_attestation_state_t, set_measurement_error, void,
private_imv_attestation_state_t *this, uint32_t error)
{
this->measurement_error |= error;
}
METHOD(imv_attestation_state_t, finalize_components, void,
private_imv_attestation_state_t *this, bio_writer_t *result)
{
func_comp_t *entry;
bool first = TRUE;
while (this->components->remove_last(this->components,
(void**)&entry) == SUCCESS)
{
if (first)
{
first = FALSE;
}
else
{
result->write_data(result, chunk_from_str("; "));
}
if (!entry->comp->finalize(entry->comp,
entry->name->get_qualifier(entry->name),
result))
{
set_measurement_error(this, IMV_ATTESTATION_ERROR_COMP_EVID_PEND);
}
free_func_comp(entry);
}
}
/**
* Described in header.
*/
imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
{
private_imv_attestation_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.set_action_flags = _set_action_flags,
.get_action_flags = _get_action_flags,
.set_session = _set_session,
.get_session = _get_session,
.get_contracts = _get_contracts,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
.update_recommendation = _update_recommendation,
.get_reason_string = _get_reason_string,
.get_remediation_instructions = _get_remediation_instructions,
.destroy = _destroy,
},
.get_handshake_state = _get_handshake_state,
.set_handshake_state = _set_handshake_state,
.get_pts = _get_pts,
.create_component = _create_component,
.create_component_enumerator = _create_component_enumerator,
.get_component = _get_component,
.finalize_components = _finalize_components,
.get_measurement_error = _get_measurement_error,
.set_measurement_error = _set_measurement_error,
.add_file_meas_reasons = _add_file_meas_reasons,
.add_comp_evid_reasons = _add_comp_evid_reasons,
},
.connection_id = connection_id,
.state = TNC_CONNECTION_STATE_CREATE,
.handshake_state = IMV_ATTESTATION_STATE_INIT,
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.contracts = seg_contract_manager_create(),
.components = linked_list_create(),
.pts = pts_create(FALSE),
);
return &this->public.interface;
}
@@ -0,0 +1,191 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_attestation imv_attestation
* @ingroup libimcv_plugins
*
* @defgroup imv_attestation_state_t imv_attestation_state
* @{ @ingroup imv_attestation
*/
#ifndef IMV_ATTESTATION_STATE_H_
#define IMV_ATTESTATION_STATE_H_
#include <imv/imv_state.h>
#include <imv/imv_reason_string.h>
#include <pts/pts.h>
#include <pts/pts_database.h>
#include <pts/components/pts_component.h>
#include <library.h>
#include <bio/bio_writer.h>
typedef struct imv_attestation_state_t imv_attestation_state_t;
typedef enum imv_attestation_flag_t imv_attestation_flag_t;
typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t;
typedef enum imv_meas_error_t imv_meas_error_t;
/**
* IMV Attestation Flags set for completed actions
*/
enum imv_attestation_flag_t {
IMV_ATTESTATION_ATTR_PRODUCT_INFO = (1<<0),
IMV_ATTESTATION_ATTR_STRING_VERSION = (1<<1),
IMV_ATTESTATION_ATTR_DEVICE_ID = (1<<2),
IMV_ATTESTATION_ATTR_MUST = (1<<3)-1,
IMV_ATTESTATION_ATTR_REQ = (1<<3),
IMV_ATTESTATION_ALGO = (1<<4),
IMV_ATTESTATION_DH_NONCE = (1<<5),
IMV_ATTESTATION_FILE_MEAS = (1<<6),
IMV_ATTESTATION_REC = (1<<7)
};
/**
* IMV Attestation Handshake States (state machine)
*/
enum imv_attestation_handshake_state_t {
IMV_ATTESTATION_STATE_INIT,
IMV_ATTESTATION_STATE_DISCOVERY,
IMV_ATTESTATION_STATE_NONCE_REQ,
IMV_ATTESTATION_STATE_TPM_INIT,
IMV_ATTESTATION_STATE_COMP_EVID,
IMV_ATTESTATION_STATE_EVID_FINAL,
IMV_ATTESTATION_STATE_END,
};
/**
* IMV Measurement Error Types
*/
enum imv_meas_error_t {
IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL = 1,
IMV_ATTESTATION_ERROR_FILE_MEAS_PEND = 2,
IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK = 4,
IMV_ATTESTATION_ERROR_COMP_EVID_FAIL = 8,
IMV_ATTESTATION_ERROR_COMP_EVID_PEND = 16,
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL = 32
};
/**
* Internal state of an imv_attestation_t connection instance
*/
struct imv_attestation_state_t {
/**
* imv_state_t interface
*/
imv_state_t interface;
/**
* Get state of the handshake
*
* @return the handshake state of IMV
*/
imv_attestation_handshake_state_t (*get_handshake_state)(
imv_attestation_state_t *this);
/**
* Set state of the handshake
*
* @param new_state the handshake state of IMV
*/
void (*set_handshake_state)(imv_attestation_state_t *this,
imv_attestation_handshake_state_t new_state);
/**
* Get the PTS object
*
* @return PTS object
*/
pts_t* (*get_pts)(imv_attestation_state_t *this);
/**
* Create and add an entry to the list of Functional Components
*
* @param name Component Functional Name
* @param depth Sub-component Depth
* @param pts_db PTS measurement database
* @return created functional component instance or NULL
*/
pts_component_t* (*create_component)(imv_attestation_state_t *this,
pts_comp_func_name_t *name,
uint32_t depth,
pts_database_t *pts_db);
/**
* Enumerate over all Functional Components
*
* @return Functional Component enumerator
*/
enumerator_t* (*create_component_enumerator)(imv_attestation_state_t *this);
/**
* Get a Functional Component with a given name
*
* @param name Name of the requested Functional Component
* @return Functional Component if found, NULL otherwise
*/
pts_component_t* (*get_component)(imv_attestation_state_t *this,
pts_comp_func_name_t *name);
/**
* Tell the Functional Components to finalize any measurement registrations
* and to check if all expected measurements were received
*
* @param result Writer appending component measurement results
*/
void (*finalize_components)(imv_attestation_state_t *this,
bio_writer_t *result);
/**
* Indicates the types of measurement errors that occurred
*
* @return Measurement error flags
*/
uint32_t (*get_measurement_error)(imv_attestation_state_t *this);
/**
* Call if a measurement error is encountered
*
* @param error Measurement error type
*/
void (*set_measurement_error)(imv_attestation_state_t *this,
uint32_t error);
/**
* Returns a concatenation of File Measurement reason strings
*
* @param reason_string Concatenated reason strings
*/
void (*add_file_meas_reasons)(imv_attestation_state_t *this,
imv_reason_string_t *reason_string);
/**
* Returns a concatenation of Component Evidence reason strings
*
* @param reason_string Concatenated reason strings
*/
void (*add_comp_evid_reasons)(imv_attestation_state_t *this,
imv_reason_string_t *reason_string);
};
/**
* Create an imv_attestation_state_t instance
*
* @param id connection ID
*/
imv_state_t* imv_attestation_state_create(TNC_ConnectionID id);
#endif /** IMV_ATTESTATION_STATE_H_ @}*/
+21
View File
@@ -0,0 +1,21 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libtncif \
-I$(top_srcdir)/src/libimcv
AM_CFLAGS = \
$(PLUGIN_CFLAGS) $(json_CFLAGS)
imcv_LTLIBRARIES = imv-swid.la
imv_swid_la_LIBADD = \
$(top_builddir)/src/libimcv/libimcv.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
$(json_LIBS)
imv_swid_la_SOURCES = \
imv_swid.c imv_swid_state.h imv_swid_state.c \
imv_swid_agent.h imv_swid_agent.c \
imv_swid_rest.h imv_swid_rest.c
imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_swid_agent.h"
static const char imv_name[] = "SWID";
static const imv_agent_create_t imv_agent_create = imv_swid_agent_create;
/* include generic TGC TNC IF-IMV API code below */
#include <imv/imv_if.h>
@@ -0,0 +1,751 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "imv_swid_agent.h"
#include "imv_swid_state.h"
#include "imv_swid_rest.h"
#include <imcv.h>
#include <imv/imv_agent.h>
#include <imv/imv_msg.h>
#include <ietf/ietf_attr_pa_tnc_error.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_angel.h>
#include "tcg/seg/tcg_seg_attr_max_size.h"
#include "tcg/seg/tcg_seg_attr_seg_env.h"
#include "tcg/swid/tcg_swid_attr_req.h"
#include "tcg/swid/tcg_swid_attr_tag_inv.h"
#include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
#include "swid/swid_error.h"
#include "swid/swid_inventory.h"
#include <tncif_names.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <bio/bio_reader.h>
typedef struct private_imv_swid_agent_t private_imv_swid_agent_t;
#define SWID_MAX_ATTR_SIZE 1000000000
/* Subscribed PA-TNC message subtypes */
static pen_type_t msg_types[] = {
{ PEN_TCG, PA_SUBTYPE_TCG_SWID }
};
/**
* Flag set when corresponding attribute has been received
*/
enum imv_swid_attr_t {
IMV_SWID_ATTR_TAG_INV = (1<<0),
IMV_SWID_ATTR_TAG_ID_INV = (1<<1)
};
/**
* Private data of an imv_swid_agent_t object.
*/
struct private_imv_swid_agent_t {
/**
* Public members of imv_swid_agent_t
*/
imv_agent_if_t public;
/**
* IMV agent responsible for generic functions
*/
imv_agent_t *agent;
/**
* REST API to strongTNC manager
*/
imv_swid_rest_t *rest_api;
};
METHOD(imv_agent_if_t, bind_functions, TNC_Result,
private_imv_swid_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
{
return this->agent->bind_functions(this->agent, bind_function);
}
METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id,
TNC_ConnectionState new_state)
{
imv_state_t *state;
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imv_swid_state_create(id);
return this->agent->create_state(this->agent, state);
case TNC_CONNECTION_STATE_DELETE:
return this->agent->delete_state(this->agent, id);
default:
return this->agent->change_state(this->agent, id, new_state, NULL);
}
}
/**
* Process a received message
*/
static TNC_Result receive_msg(private_imv_swid_agent_t *this,
imv_state_t *state, imv_msg_t *in_msg)
{
imv_swid_state_t *swid_state;
imv_msg_t *out_msg;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
TNC_Result result;
bool fatal_error = FALSE;
/* generate an outgoing PA-TNC message - we might need it */
out_msg = imv_msg_create_as_reply(in_msg);
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, out_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
out_msg->destroy(out_msg);
return result;
}
swid_state = (imv_swid_state_t*)state;
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
uint32_t request_id = 0, last_eid, eid_epoch;
swid_inventory_t *inventory;
pen_type_t type;
type = attr->get_type(attr);
if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
{
ietf_attr_pa_tnc_error_t *error_attr;
pen_type_t error_code;
chunk_t msg_info, description;
bio_reader_t *reader;
uint32_t max_attr_size;
bool success;
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
error_code = error_attr->get_error_code(error_attr);
if (error_code.vendor_id == PEN_TCG)
{
fatal_error = TRUE;
msg_info = error_attr->get_msg_info(error_attr);
reader = bio_reader_create(msg_info);
success = reader->read_uint32(reader, &request_id);
DBG1(DBG_IMV, "received TCG error '%N' for request %d",
swid_error_code_names, error_code.type, request_id);
if (!success)
{
reader->destroy(reader);
continue;
}
if (error_code.type == TCG_SWID_RESPONSE_TOO_LARGE)
{
if (!reader->read_uint32(reader, &max_attr_size))
{
reader->destroy(reader);
continue;
}
DBG1(DBG_IMV, " maximum PA-TNC attribute size is %u bytes",
max_attr_size);
}
description = reader->peek(reader);
if (description.len)
{
DBG1(DBG_IMV, " description: %.*s", description.len,
description.ptr);
}
reader->destroy(reader);
}
}
else if (type.vendor_id == PEN_ITA)
{
switch (type.type)
{
case ITA_ATTR_START_ANGEL:
swid_state->set_angel_count(swid_state, TRUE);
continue;
case ITA_ATTR_STOP_ANGEL:
swid_state->set_angel_count(swid_state, FALSE);
continue;
default:
continue;
}
}
else if (type.vendor_id != PEN_TCG)
{
continue;
}
switch (type.type)
{
case TCG_SWID_TAG_ID_INVENTORY:
{
tcg_swid_attr_tag_id_inv_t *attr_cast;
int tag_id_count;
state->set_action_flags(state, IMV_SWID_ATTR_TAG_ID_INV);
attr_cast = (tcg_swid_attr_tag_id_inv_t*)attr;
request_id = attr_cast->get_request_id(attr_cast);
last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch);
inventory = attr_cast->get_inventory(attr_cast);
tag_id_count = inventory->get_count(inventory);
DBG2(DBG_IMV, "received SWID tag ID inventory with %d item%s "
"for request %d at eid %d of epoch 0x%08x",
tag_id_count, (tag_id_count == 1) ? "" : "s",
request_id, last_eid, eid_epoch);
if (request_id == swid_state->get_request_id(swid_state))
{
swid_state->set_swid_inventory(swid_state, inventory);
swid_state->set_count(swid_state, tag_id_count, 0);
}
else
{
DBG1(DBG_IMV, "no workitem found for SWID tag ID inventory "
"with request ID %d", request_id);
}
break;
}
case TCG_SWID_TAG_INVENTORY:
{
tcg_swid_attr_tag_inv_t *attr_cast;
swid_tag_t *tag;
chunk_t tag_encoding;
json_object *jobj, *jarray, *jstring;
char *tag_str;
int tag_count;
enumerator_t *e;
state->set_action_flags(state, IMV_SWID_ATTR_TAG_INV);
attr_cast = (tcg_swid_attr_tag_inv_t*)attr;
request_id = attr_cast->get_request_id(attr_cast);
last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch);
inventory = attr_cast->get_inventory(attr_cast);
tag_count = inventory->get_count(inventory);
DBG2(DBG_IMV, "received SWID tag inventory with %d item%s for "
"request %d at eid %d of epoch 0x%08x",
tag_count, (tag_count == 1) ? "" : "s",
request_id, last_eid, eid_epoch);
if (request_id == swid_state->get_request_id(swid_state))
{
swid_state->set_count(swid_state, 0, tag_count);
if (this->rest_api)
{
jobj = json_object_new_object();
jarray = json_object_new_array();
json_object_object_add(jobj, "data", jarray);
e = inventory->create_enumerator(inventory);
while (e->enumerate(e, &tag))
{
tag_encoding = tag->get_encoding(tag);
tag_str = strndup(tag_encoding.ptr, tag_encoding.len);
DBG3(DBG_IMV, "%s", tag_str);
jstring = json_object_new_string(tag_str);
json_object_array_add(jarray, jstring);
free(tag_str);
}
e->destroy(e);
if (this->rest_api->post(this->rest_api,
"swid/add-tags/", jobj, NULL) != SUCCESS)
{
DBG1(DBG_IMV, "error in REST API add-tags request");
}
json_object_put(jobj);
}
}
else
{
DBG1(DBG_IMV, "no workitem found for SWID tag inventory "
"with request ID %d", request_id);
}
}
default:
continue;
}
}
enumerator->destroy(enumerator);
if (fatal_error)
{
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
TNC_IMV_EVALUATION_RESULT_ERROR);
result = out_msg->send_assessment(out_msg);
if (result == TNC_RESULT_SUCCESS)
{
result = this->agent->provide_recommendation(this->agent, state);
}
}
else
{
/* send PA-TNC message with the EXCL flag set */
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id,
TNC_MessageType msg_type, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id,
TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
{
imv_state_t *state;
imv_msg_t *in_msg;
TNC_Result result;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imv_msg_create_from_long_data(this->agent, state, id,
src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
result = receive_msg(this, state, in_msg);
in_msg->destroy(in_msg);
return result;
}
METHOD(imv_agent_if_t, batch_ending, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id)
{
imv_msg_t *out_msg;
imv_state_t *state;
imv_session_t *session;
imv_workitem_t *workitem;
imv_swid_state_t *swid_state;
imv_swid_handshake_state_t handshake_state;
pa_tnc_attr_t *attr;
TNC_IMVID imv_id;
TNC_Result result = TNC_RESULT_SUCCESS;
bool no_workitems = TRUE;
uint32_t request_id, received;
uint8_t flags;
enumerator_t *enumerator;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
swid_state = (imv_swid_state_t*)state;
handshake_state = swid_state->get_handshake_state(swid_state);
session = state->get_session(state);
imv_id = this->agent->get_id(this->agent);
if (handshake_state == IMV_SWID_STATE_END)
{
return TNC_RESULT_SUCCESS;
}
/* Create an empty out message - we might need it */
out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
msg_types[0]);
if (!imcv_db)
{
DBG2(DBG_IMV, "no workitems available - no evaluation possible");
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
swid_state->set_handshake_state(swid_state, IMV_SWID_STATE_END);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* Look for SWID tag workitem and create SWID tag request */
if (handshake_state == IMV_SWID_STATE_INIT &&
session->get_policy_started(session))
{
size_t max_attr_size = SWID_MAX_ATTR_SIZE;
size_t max_seg_size;
seg_contract_t *contract;
seg_contract_manager_t *contracts;
char buf[BUF_LEN];
enumerator = session->create_workitem_enumerator(session);
if (enumerator)
{
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY ||
workitem->get_type(workitem) != IMV_WORKITEM_SWID_TAGS)
{
continue;
}
flags = TCG_SWID_ATTR_REQ_FLAG_NONE;
if (strchr(workitem->get_arg_str(workitem), 'R'))
{
flags |= TCG_SWID_ATTR_REQ_FLAG_R;
}
if (strchr(workitem->get_arg_str(workitem), 'S'))
{
flags |= TCG_SWID_ATTR_REQ_FLAG_S;
}
if (strchr(workitem->get_arg_str(workitem), 'C'))
{
flags |= TCG_SWID_ATTR_REQ_FLAG_C;
}
/* Determine maximum PA-TNC attribute segment size */
max_seg_size = state->get_max_msg_len(state)
- PA_TNC_HEADER_SIZE
- PA_TNC_ATTR_HEADER_SIZE
- TCG_SEG_ATTR_SEG_ENV_HEADER;
/* Announce support of PA-TNC segmentation to IMC */
contract = seg_contract_create(msg_types[0], max_attr_size,
max_seg_size, TRUE, imv_id, FALSE);
contract->get_info_string(contract, buf, BUF_LEN, TRUE);
DBG2(DBG_IMV, "%s", buf);
contracts = state->get_contracts(state);
contracts->add_contract(contracts, contract);
attr = tcg_seg_attr_max_size_create(max_attr_size,
max_seg_size, TRUE);
out_msg->add_attribute(out_msg, attr);
/* Issue a SWID request */
request_id = workitem->get_id(workitem);
swid_state->set_request_id(swid_state, request_id);
attr = tcg_swid_attr_req_create(flags, request_id, 0);
out_msg->add_attribute(out_msg, attr);
workitem->set_imv_id(workitem, imv_id);
no_workitems = FALSE;
DBG2(DBG_IMV, "IMV %d issues SWID request %d",
imv_id, request_id);
break;
}
enumerator->destroy(enumerator);
if (no_workitems)
{
DBG2(DBG_IMV, "IMV %d has no workitems - "
"no evaluation requested", imv_id);
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
}
handshake_state = IMV_SWID_STATE_WORKITEMS;
swid_state->set_handshake_state(swid_state, handshake_state);
}
}
received = state->get_action_flags(state);
if (handshake_state == IMV_SWID_STATE_WORKITEMS &&
(received & (IMV_SWID_ATTR_TAG_INV|IMV_SWID_ATTR_TAG_ID_INV)) &&
swid_state->get_angel_count(swid_state) <= 0)
{
TNC_IMV_Evaluation_Result eval;
TNC_IMV_Action_Recommendation rec;
char result_str[BUF_LEN], *error_str = "", *command;
char *target, *separator;
int tag_id_count, tag_count, i;
size_t max_attr_size, attr_size, entry_size;
chunk_t tag_creator, unique_sw_id;
json_object *jrequest, *jresponse, *jvalue;
tcg_swid_attr_req_t *cast_attr;
swid_tag_id_t *tag_id;
status_t status = SUCCESS;
if (this->rest_api && (received & IMV_SWID_ATTR_TAG_ID_INV))
{
if (asprintf(&command, "sessions/%d/swid-measurement/",
session->get_session_id(session, NULL, NULL)) < 0)
{
error_str = "allocation of command string failed";
status = FAILED;
}
else
{
jrequest = swid_state->get_swid_inventory(swid_state);
status = this->rest_api->post(this->rest_api, command,
jrequest, &jresponse);
if (status == FAILED)
{
error_str = "error in REST API swid-measurement request";
}
free(command);
}
}
switch (status)
{
case SUCCESS:
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
{
swid_state->get_count(swid_state, &tag_id_count,
&tag_count);
snprintf(result_str, BUF_LEN, "received inventory of "
"%d SWID tag ID%s and %d SWID tag%s",
tag_id_count, (tag_id_count == 1) ? "" : "s",
tag_count, (tag_count == 1) ? "" : "s");
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
rec = workitem->set_result(workitem, result_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
break;
}
}
enumerator->destroy(enumerator);
break;
case NEED_MORE:
if (received & IMV_SWID_ATTR_TAG_INV)
{
error_str = "not all requested SWID tags were received";
status = FAILED;
json_object_put(jresponse);
break;
}
if (json_object_get_type(jresponse) != json_type_array)
{
error_str = "response was not a json_array";
status = FAILED;
json_object_put(jresponse);
break;
}
/* Compute the maximum TCG SWID Request attribute size */
max_attr_size = state->get_max_msg_len(state) -
PA_TNC_HEADER_SIZE;
/* Create the [first] TCG SWID Request attribute */
attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_REQ_MIN_SIZE;
attr = tcg_swid_attr_req_create(TCG_SWID_ATTR_REQ_FLAG_NONE,
swid_state->get_request_id(swid_state), 0);
tag_id_count = json_object_array_length(jresponse);
DBG1(DBG_IMV, "%d SWID tag target%s", tag_id_count,
(tag_id_count == 1) ? "" : "s");
for (i = 0; i < tag_id_count; i++)
{
jvalue = json_object_array_get_idx(jresponse, i);
if (json_object_get_type(jvalue) != json_type_string)
{
error_str = "json_string element expected in json_array";
status = FAILED;
json_object_put(jresponse);
break;
}
target = (char*)json_object_get_string(jvalue);
DBG1(DBG_IMV, " %s", target);
/* Separate target into tag_creator and unique_sw_id */
separator = strchr(target, '_');
if (!separator)
{
error_str = "separation of regid from "
"unique software ID failed";
break;
}
tag_creator = chunk_create(target, separator - target);
separator++;
unique_sw_id = chunk_create(separator, strlen(target) -
tag_creator.len - 1);
tag_id = swid_tag_id_create(tag_creator, unique_sw_id,
chunk_empty);
entry_size = 2 + tag_creator.len + 2 + unique_sw_id.len;
/* Have we reached the maximum attribute size? */
if (attr_size + entry_size > max_attr_size)
{
out_msg->add_attribute(out_msg, attr);
attr_size = PA_TNC_ATTR_HEADER_SIZE +
TCG_SWID_REQ_MIN_SIZE;
attr = tcg_swid_attr_req_create(
TCG_SWID_ATTR_REQ_FLAG_NONE,
swid_state->get_request_id(swid_state), 0);
}
cast_attr = (tcg_swid_attr_req_t*)attr;
cast_attr->add_target(cast_attr, tag_id);
}
json_object_put(jresponse);
out_msg->add_attribute(out_msg, attr);
break;
case FAILED:
default:
break;
}
if (status == FAILED)
{
enumerator = session->create_workitem_enumerator(session);
while (enumerator->enumerate(enumerator, &workitem))
{
if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
{
session->remove_workitem(session, enumerator);
eval = TNC_IMV_EVALUATION_RESULT_ERROR;
rec = workitem->set_result(workitem, error_str, eval);
state->update_recommendation(state, rec, eval);
imcv_db->finalize_workitem(imcv_db, workitem);
workitem->destroy(workitem);
break;
}
}
enumerator->destroy(enumerator);
}
}
/* finalized all workitems ? */
if (handshake_state == IMV_SWID_STATE_WORKITEMS &&
session->get_workitem_count(session, imv_id) == 0)
{
result = out_msg->send_assessment(out_msg);
out_msg->destroy(out_msg);
swid_state->set_handshake_state(swid_state, IMV_SWID_STATE_END);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
return this->agent->provide_recommendation(this->agent, state);
}
/* send non-empty PA-TNC message with excl flag not set */
if (out_msg->get_attribute_count(out_msg))
{
result = out_msg->send(out_msg, FALSE);
}
out_msg->destroy(out_msg);
return result;
}
METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
private_imv_swid_agent_t *this, TNC_ConnectionID id)
{
imv_state_t *state;
if (!this->agent->get_state(this->agent, id, &state))
{
return TNC_RESULT_FATAL;
}
return this->agent->provide_recommendation(this->agent, state);
}
METHOD(imv_agent_if_t, destroy, void,
private_imv_swid_agent_t *this)
{
DESTROY_IF(this->rest_api);
this->agent->destroy(this->agent);
free(this);
}
/**
* Described in header.
*/
imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id,
TNC_Version *actual_version)
{
private_imv_swid_agent_t *this;
imv_agent_t *agent;
char *rest_api_uri;
u_int rest_api_timeout;
agent = imv_agent_create(name, msg_types, countof(msg_types), id,
actual_version);
if (!agent)
{
return NULL;
}
agent->add_non_fatal_attr_type(agent,
pen_type_create(PEN_TCG, TCG_SEG_MAX_ATTR_SIZE_REQ));
INIT(this,
.public = {
.bind_functions = _bind_functions,
.notify_connection_change = _notify_connection_change,
.receive_message = _receive_message,
.receive_message_long = _receive_message_long,
.batch_ending = _batch_ending,
.solicit_recommendation = _solicit_recommendation,
.destroy = _destroy,
},
.agent = agent,
);
rest_api_uri = lib->settings->get_str(lib->settings,
"%s.plugins.imv-swid.rest_api_uri", NULL, lib->ns);
rest_api_timeout = lib->settings->get_int(lib->settings,
"%s.plugins.imv-swid.rest_api_timeout", 120, lib->ns);
if (rest_api_uri)
{
this->rest_api = imv_swid_rest_create(rest_api_uri, rest_api_timeout);
}
return &this->public;
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2013 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_swid_agent_t imv_swid_agent
* @{ @ingroup imv_swid
*/
#ifndef IMV_SWID_AGENT_H_
#define IMV_SWID_AGENT_H_
#include <imv/imv_agent_if.h>
/**
* Creates an SWID IMV agent
*
* @param name Name of the IMV
* @param id ID of the IMV
* @param actual_version TNC IF-IMV version
*/
imv_agent_if_t* imv_swid_agent_create(const char* name, TNC_IMVID id,
TNC_Version *actual_version);
#endif /** IMV_SWID_AGENT_H_ @}*/
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "imv_swid_rest.h"
typedef struct private_imv_swid_rest_t private_imv_swid_rest_t;
/**
* Private data of an imv_swid_rest_t object.
*/
struct private_imv_swid_rest_t {
/**
* Public members of imv_swid_rest_t
*/
imv_swid_rest_t public;
/**
* URI of REST API
*/
char *uri;
/**
* Timeout of REST API connection
*/
u_int timeout;
};
#define HTTP_STATUS_CODE_PRECONDITION_FAILED 412
METHOD(imv_swid_rest_t, post, status_t,
private_imv_swid_rest_t *this, char *command, json_object *jrequest,
json_object **jresponse)
{
struct json_tokener *tokener;
chunk_t data, response = chunk_empty;
status_t status;
char *uri;
int code;
if (asprintf(&uri, "%s%s",this->uri, command) < 0)
{
return FAILED;
}
data = chunk_from_str((char*)json_object_to_json_string(jrequest));
status = lib->fetcher->fetch(lib->fetcher, uri, &response,
FETCH_TIMEOUT, this->timeout,
FETCH_REQUEST_DATA, data,
FETCH_REQUEST_TYPE, "application/json; charset=utf-8",
FETCH_REQUEST_HEADER, "Accept: application/json",
FETCH_REQUEST_HEADER, "Expect:",
FETCH_RESPONSE_CODE, &code,
FETCH_END);
free(uri);
if (status == SUCCESS)
{
return SUCCESS;
}
if (code != HTTP_STATUS_CODE_PRECONDITION_FAILED || !response.ptr)
{
DBG2(DBG_IMV, "REST http request failed with status code: %d", code);
return FAILED;
}
if (jresponse)
{
/* Parse HTTP response into a JSON object */
tokener = json_tokener_new();
*jresponse = json_tokener_parse_ex(tokener, response.ptr, response.len);
json_tokener_free(tokener);
}
free(response.ptr);
return NEED_MORE;
}
METHOD(imv_swid_rest_t, destroy, void,
private_imv_swid_rest_t *this)
{
free(this->uri);
free(this);
}
/**
* Described in header.
*/
imv_swid_rest_t *imv_swid_rest_create(char *uri, u_int timeout)
{
private_imv_swid_rest_t *this;
INIT(this,
.public = {
.post = _post,
.destroy = _destroy,
},
.uri = strdup(uri),
.timeout = timeout,
);
return &this->public;
}
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_swid imv_swid
* @ingroup libimcv_plugins
*
* @defgroup imv_swid_rest_t imv_swid_rest
* @{ @ingroup imv_swid
*/
#ifndef IMV_SWID_REST_H_
#define IMV_SWID_REST_H_
#include <library.h>
#include <json.h>
typedef struct imv_swid_rest_t imv_swid_rest_t;
/**
* Public REST interface
*/
struct imv_swid_rest_t {
/**
* Post a HTTP request including a JSON object
*
* @param jreq JSON object in HTTP request
* @param jresp JSON object in HTTP response if NEED_MORE
* @return Status (SUCCESS, NEED_MORE or FAILED)
*/
status_t (*post)(imv_swid_rest_t *this, char *command, json_object *jreq,
json_object **jresp);
/**
* Destroy imv_swid_rest_t object
*/
void (*destroy)(imv_swid_rest_t *this);
};
/**
* Create an imv_swid_rest_t instance
*
* @param uri REST URI (http://username:password@hostname[:port]/api/)
* @param timeout Timeout of the REST connection
*/
imv_swid_rest_t* imv_swid_rest_create(char *uri, u_int timeout);
#endif /** IMV_SWID_REST_H_ @}*/
@@ -0,0 +1,402 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imv_swid_state.h"
#include <imv/imv_lang_string.h>
#include <imv/imv_reason_string.h>
#include <imv/imv_remediation_string.h>
#include <swid/swid_tag_id.h>
#include <tncif_policy.h>
#include <utils/lexparser.h>
#include <utils/debug.h>
typedef struct private_imv_swid_state_t private_imv_swid_state_t;
/**
* Private data of an imv_swid_state_t object.
*/
struct private_imv_swid_state_t {
/**
* Public members of imv_swid_state_t
*/
imv_swid_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
uint32_t max_msg_len;
/**
* Flags set for completed actions
*/
uint32_t action_flags;
/**
* IMV database session associated with TNCCS connection
*/
imv_session_t *session;
/**
* PA-TNC attribute segmentation contracts associated with TNCCS connection
*/
seg_contract_manager_t *contracts;
/**
* IMV action recommendation
*/
TNC_IMV_Action_Recommendation rec;
/**
* IMV evaluation result
*/
TNC_IMV_Evaluation_Result eval;
/**
* IMV Scanner handshake state
*/
imv_swid_handshake_state_t handshake_state;
/**
* TNC Reason String
*/
imv_reason_string_t *reason_string;
/**
* IETF Remediation Instructions String
*/
imv_remediation_string_t *remediation_string;
/**
* SWID Tag Request ID
*/
uint32_t request_id;
/**
* Number of processed SWID Tag IDs
*/
int tag_id_count;
/**
* Number of processed SWID Tags
*/
int tag_count;
/**
* Top level JSON object
*/
json_object *jobj;
/**
* JSON array containing an inventory of SWID Tag IDs
*/
json_object *jarray;
/**
* Angel count
*/
int angel_count;
};
METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
private_imv_swid_state_t *this)
{
return this->connection_id;
}
METHOD(imv_state_t, has_long, bool,
private_imv_swid_state_t *this)
{
return this->has_long;
}
METHOD(imv_state_t, has_excl, bool,
private_imv_swid_state_t *this)
{
return this->has_excl;
}
METHOD(imv_state_t, set_flags, void,
private_imv_swid_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imv_state_t, set_max_msg_len, void,
private_imv_swid_state_t *this, uint32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imv_state_t, get_max_msg_len, uint32_t,
private_imv_swid_state_t *this)
{
return this->max_msg_len;
}
METHOD(imv_state_t, set_action_flags, void,
private_imv_swid_state_t *this, uint32_t flags)
{
this->action_flags |= flags;
}
METHOD(imv_state_t, get_action_flags, uint32_t,
private_imv_swid_state_t *this)
{
return this->action_flags;
}
METHOD(imv_state_t, set_session, void,
private_imv_swid_state_t *this, imv_session_t *session)
{
this->session = session;
}
METHOD(imv_state_t, get_session, imv_session_t*,
private_imv_swid_state_t *this)
{
return this->session;
}
METHOD(imv_state_t, get_contracts, seg_contract_manager_t*,
private_imv_swid_state_t *this)
{
return this->contracts;
}
METHOD(imv_state_t, change_state, void,
private_imv_swid_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imv_state_t, get_recommendation, void,
private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation *rec,
TNC_IMV_Evaluation_Result *eval)
{
*rec = this->rec;
*eval = this->eval;
}
METHOD(imv_state_t, set_recommendation, void,
private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = rec;
this->eval = eval;
}
METHOD(imv_state_t, update_recommendation, void,
private_imv_swid_state_t *this, TNC_IMV_Action_Recommendation rec,
TNC_IMV_Evaluation_Result eval)
{
this->rec = tncif_policy_update_recommendation(this->rec, rec);
this->eval = tncif_policy_update_evaluation(this->eval, eval);
}
METHOD(imv_state_t, get_reason_string, bool,
private_imv_swid_state_t *this, enumerator_t *language_enumerator,
chunk_t *reason_string, char **reason_language)
{
return FALSE;
}
METHOD(imv_state_t, get_remediation_instructions, bool,
private_imv_swid_state_t *this, enumerator_t *language_enumerator,
chunk_t *string, char **lang_code, char **uri)
{
return FALSE;
}
METHOD(imv_state_t, destroy, void,
private_imv_swid_state_t *this)
{
json_object_put(this->jobj);
DESTROY_IF(this->session);
DESTROY_IF(this->reason_string);
DESTROY_IF(this->remediation_string);
this->contracts->destroy(this->contracts);
free(this);
}
METHOD(imv_swid_state_t, set_handshake_state, void,
private_imv_swid_state_t *this, imv_swid_handshake_state_t new_state)
{
this->handshake_state = new_state;
}
METHOD(imv_swid_state_t, get_handshake_state, imv_swid_handshake_state_t,
private_imv_swid_state_t *this)
{
return this->handshake_state;
}
METHOD(imv_swid_state_t, set_request_id, void,
private_imv_swid_state_t *this, uint32_t request_id)
{
this->request_id = request_id;
}
METHOD(imv_swid_state_t, get_request_id, uint32_t,
private_imv_swid_state_t *this)
{
return this->request_id;
}
METHOD(imv_swid_state_t, set_swid_inventory, void,
private_imv_swid_state_t *this, swid_inventory_t *inventory)
{
chunk_t tag_creator, unique_sw_id;
char software_id[256];
json_object *jstring;
swid_tag_id_t *tag_id;
enumerator_t *enumerator;
enumerator = inventory->create_enumerator(inventory);
while (enumerator->enumerate(enumerator, &tag_id))
{
/* Construct software ID from tag creator and unique software ID */
tag_creator = tag_id->get_tag_creator(tag_id);
unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
snprintf(software_id, 256, "%.*s_%.*s",
tag_creator.len, tag_creator.ptr,
unique_sw_id.len, unique_sw_id.ptr);
DBG3(DBG_IMV, " %s", software_id);
/* Add software ID to JSON array */
jstring = json_object_new_string(software_id);
json_object_array_add(this->jarray, jstring);
}
enumerator->destroy(enumerator);
}
METHOD(imv_swid_state_t, get_swid_inventory, json_object*,
private_imv_swid_state_t *this)
{
return this->jobj;
}
METHOD(imv_swid_state_t, set_count, void,
private_imv_swid_state_t *this, int tag_id_count, int tag_count)
{
this->tag_id_count += tag_id_count;
this->tag_count += tag_count;
}
METHOD(imv_swid_state_t, get_count, void,
private_imv_swid_state_t *this, int *tag_id_count, int *tag_count)
{
if (tag_id_count)
{
*tag_id_count = this->tag_id_count;
}
if (tag_count)
{
*tag_count = this->tag_count;
}
}
METHOD(imv_swid_state_t, set_angel_count, void,
private_imv_swid_state_t *this, bool start)
{
this->angel_count += start ? 1 : -1;
}
METHOD(imv_swid_state_t, get_angel_count, int,
private_imv_swid_state_t *this)
{
return this->angel_count;
}
/**
* Described in header.
*/
imv_state_t *imv_swid_state_create(TNC_ConnectionID connection_id)
{
private_imv_swid_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.set_action_flags = _set_action_flags,
.get_action_flags = _get_action_flags,
.set_session = _set_session,
.get_session= _get_session,
.get_contracts = _get_contracts,
.change_state = _change_state,
.get_recommendation = _get_recommendation,
.set_recommendation = _set_recommendation,
.update_recommendation = _update_recommendation,
.get_reason_string = _get_reason_string,
.get_remediation_instructions = _get_remediation_instructions,
.destroy = _destroy,
},
.set_handshake_state = _set_handshake_state,
.get_handshake_state = _get_handshake_state,
.set_request_id = _set_request_id,
.get_request_id = _get_request_id,
.set_swid_inventory = _set_swid_inventory,
.get_swid_inventory = _get_swid_inventory,
.set_count = _set_count,
.get_count = _get_count,
.set_angel_count = _set_angel_count,
.get_angel_count = _get_angel_count,
},
.state = TNC_CONNECTION_STATE_CREATE,
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.contracts = seg_contract_manager_create(),
.jobj = json_object_new_object(),
.jarray = json_object_new_array(),
);
json_object_object_add(this->jobj, "data", this->jarray);
return &this->public.interface;
}
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2013-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imv_swid imv_swid
* @ingroup libimcv_plugins
*
* @defgroup imv_swid_state_t imv_swid_state
* @{ @ingroup imv_swid
*/
#ifndef IMV_SWID_STATE_H_
#define IMV_SWID_STATE_H_
#include <imv/imv_state.h>
#include <swid/swid_inventory.h>
#include <library.h>
#include <json.h>
typedef struct imv_swid_state_t imv_swid_state_t;
typedef enum imv_swid_handshake_state_t imv_swid_handshake_state_t;
/**
* IMV OS Handshake States (state machine)
*/
enum imv_swid_handshake_state_t {
IMV_SWID_STATE_INIT,
IMV_SWID_STATE_WORKITEMS,
IMV_SWID_STATE_END
};
/**
* Internal state of an imv_swid_t connection instance
*/
struct imv_swid_state_t {
/**
* imv_state_t interface
*/
imv_state_t interface;
/**
* Set state of the handshake
*
* @param new_state the handshake state of IMV
*/
void (*set_handshake_state)(imv_swid_state_t *this,
imv_swid_handshake_state_t new_state);
/**
* Get state of the handshake
*
* @return the handshake state of IMV
*/
imv_swid_handshake_state_t (*get_handshake_state)(imv_swid_state_t *this);
/**
* Set the SWID request ID
*
* @param request_id SWID request ID to be set
*/
void (*set_request_id)(imv_swid_state_t *this, uint32_t request_id);
/**
* Get the SWID request ID
*
* @return SWID request ID
*/
uint32_t (*get_request_id)(imv_swid_state_t *this);
/**
* Set or extend the SWID Tag ID inventory in the state
*
* @param inventory SWID Tags ID inventory to be added
*/
void (*set_swid_inventory)(imv_swid_state_t *this, swid_inventory_t *inventory);
/**
* Get the encoding of the complete SWID Tag ID inventory
*
* @return SWID Tags ID inventory as a JSON array
*/
json_object* (*get_swid_inventory)(imv_swid_state_t *this);
/**
* Set [or with multiple attributes increment] SWID Tag [ID] counters
*
* @param tag_id_count Number of received SWID Tag IDs
* @param tag_count Number of received SWID Tags
*/
void (*set_count)(imv_swid_state_t *this, int tag_id_count, int tag_count);
/**
* Set [or with multiple attributes increment] SWID Tag [ID] counters
*
* @param tag_id_count Number of received SWID Tag IDs
* @param tag_count Number of received SWID Tags
*/
void (*get_count)(imv_swid_state_t *this, int *tag_id_count, int *tag_count);
/**
* Increase/Decrease the ITA Angel count
*
* @param start TRUE increases and FALSE decreases count by one
*/
void (*set_angel_count)(imv_swid_state_t *this, bool start);
/**
* Get the ITA Angel count
*
* @return ITA Angel count
*/
int (*get_angel_count)(imv_swid_state_t *this);
};
/**
* Create an imv_swid_state_t instance
*
* @param id connection ID
*/
imv_state_t* imv_swid_state_create(TNC_ConnectionID id);
#endif /** IMV_SWID_STATE_H_ @}*/