Merged libpts into libimcv
This commit is contained in:
@@ -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, "e_sig))
|
||||
{
|
||||
DBG1(DBG_IMC, "error occurred during TPM quote operation");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Send Simple Evidence Final attribute */
|
||||
flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
|
||||
PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
|
||||
comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
|
||||
|
||||
attr = tcg_pts_attr_simple_evid_final_create(flags,
|
||||
comp_hash_algorithm, pcr_composite, quote_sig);
|
||||
msg->add_attribute(msg, attr);
|
||||
break;
|
||||
}
|
||||
/* 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_ @}*/
|
||||
@@ -0,0 +1 @@
|
||||
regid.2004-03.org.strongswan*.swidtag
|
||||
@@ -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
|
||||
@@ -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_ @}*/
|
||||
+30
@@ -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>
|
||||
+30
@@ -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>
|
||||
+30
@@ -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>
|
||||
+30
@@ -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>
|
||||
+30
@@ -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>
|
||||
+30
@@ -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>
|
||||
+30
@@ -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
@@ -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, "e_info))
|
||||
{
|
||||
DBG1(DBG_IMV, "unable to construct TPM Quote Info");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!chunk_equals(pcr_comp, pcr_composite))
|
||||
{
|
||||
DBG1(DBG_IMV, "received PCR Composite does not match "
|
||||
"constructed one");
|
||||
attestation_state->set_measurement_error(attestation_state,
|
||||
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
|
||||
goto quote_error;
|
||||
}
|
||||
DBG2(DBG_IMV, "received PCR Composite matches constructed one");
|
||||
|
||||
if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig))
|
||||
{
|
||||
attestation_state->set_measurement_error(attestation_state,
|
||||
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL);
|
||||
goto quote_error;
|
||||
}
|
||||
DBG2(DBG_IMV, "TPM Quote Info signature verification successful");
|
||||
|
||||
quote_error:
|
||||
free(pcr_composite.ptr);
|
||||
free(quote_info.ptr);
|
||||
|
||||
/**
|
||||
* Finalize any pending measurement registrations and check
|
||||
* if all expected component measurements were received
|
||||
*/
|
||||
result = bio_writer_create(128);
|
||||
attestation_state->finalize_components(attestation_state,
|
||||
result);
|
||||
|
||||
enumerator = session->create_workitem_enumerator(session);
|
||||
while (enumerator->enumerate(enumerator, &workitem))
|
||||
{
|
||||
if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST)
|
||||
{
|
||||
TNC_IMV_Action_Recommendation rec;
|
||||
TNC_IMV_Evaluation_Result eval;
|
||||
uint32_t error;
|
||||
|
||||
error = attestation_state->get_measurement_error(
|
||||
attestation_state);
|
||||
if (error & (IMV_ATTESTATION_ERROR_COMP_EVID_FAIL |
|
||||
IMV_ATTESTATION_ERROR_COMP_EVID_PEND |
|
||||
IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL))
|
||||
{
|
||||
reason_string = imv_reason_string_create("en", ", ");
|
||||
attestation_state->add_comp_evid_reasons(
|
||||
attestation_state, reason_string);
|
||||
result->write_data(result, chunk_from_str("; "));
|
||||
result->write_data(result,
|
||||
reason_string->get_encoding(reason_string));
|
||||
reason_string->destroy(reason_string);
|
||||
eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
|
||||
}
|
||||
session->remove_workitem(session, enumerator);
|
||||
|
||||
result->write_uint8(result, '\0');
|
||||
result_buf = result->get_buf(result);
|
||||
rec = workitem->set_result(workitem, result_buf.ptr,
|
||||
eval);
|
||||
state->update_recommendation(state, rec, eval);
|
||||
imcv_db->finalize_workitem(imcv_db, workitem);
|
||||
workitem->destroy(workitem);
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_END);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
result->destroy(result);
|
||||
}
|
||||
|
||||
if (attr_cast->get_evid_sig(attr_cast, &evid_sig))
|
||||
{
|
||||
/** TODO: What to do with Evidence Signature */
|
||||
DBG1(DBG_IMV, "this version of the Attestation IMV can not "
|
||||
"handle Evidence Signatures");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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_ @}*/
|
||||
@@ -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
|
||||
@@ -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_ @}*/
|
||||
Reference in New Issue
Block a user