moved attestation plugins to libpts in order to resolve circular reference with libimcv
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libtncif \
|
||||
-I$(top_srcdir)/src/libimcv -I$(top_srcdir)/src/libpts
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
|
||||
imcv_LTLIBRARIES = imc-attestation.la
|
||||
|
||||
imc_attestation_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
|
||||
$(top_builddir)/src/libstrongswan/libstrongswan.la \
|
||||
$(top_builddir)/src/libpts/libpts.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
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Sansar Choinyambuu
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "imc_attestation_state.h"
|
||||
#include "imc_attestation_process.h"
|
||||
|
||||
#include <imc/imc_agent.h>
|
||||
#include <pa_tnc/pa_tnc_msg.h>
|
||||
#include <ietf/ietf_attr.h>
|
||||
#include <ietf/ietf_attr_pa_tnc_error.h>
|
||||
#include <ietf/ietf_attr_product_info.h>
|
||||
|
||||
#include <libpts.h>
|
||||
|
||||
#include <pts/pts_error.h>
|
||||
|
||||
#include <tcg/tcg_pts_attr_proto_caps.h>
|
||||
#include <tcg/tcg_pts_attr_meas_algo.h>
|
||||
#include <tncif_pa_subtypes.h>
|
||||
|
||||
#include <pen/pen.h>
|
||||
#include <debug.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
/* IMC definitions */
|
||||
|
||||
static const char imc_name[] = "Attestation";
|
||||
|
||||
#define IMC_VENDOR_ID PEN_TCG
|
||||
#define IMC_SUBTYPE 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;
|
||||
|
||||
/**
|
||||
* List of buffered Simple Component Evidences
|
||||
* To be sent on reception of Generate Attestation Evidence attribute
|
||||
*/
|
||||
static linked_list_t *evidences = NULL;
|
||||
|
||||
/**
|
||||
* Supported PTS Diffie Hellman Groups
|
||||
*/
|
||||
static pts_dh_group_t supported_dh_groups = 0;
|
||||
|
||||
/**
|
||||
* Supported PTS Diffie Hellman Groups
|
||||
*/
|
||||
static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
|
||||
|
||||
/**
|
||||
* List of buffered Simple Component Evidences
|
||||
* To be sent on reception of Generate Attestation Evidence attribute
|
||||
*/
|
||||
static linked_list_t *evidences = NULL;
|
||||
|
||||
/**
|
||||
* see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
|
||||
TNC_Version min_version,
|
||||
TNC_Version max_version,
|
||||
TNC_Version *actual_version)
|
||||
{
|
||||
if (imc_attestation)
|
||||
{
|
||||
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
|
||||
return TNC_RESULT_ALREADY_INITIALIZED;
|
||||
}
|
||||
if (!pts_meas_algo_probe(&supported_algorithms) ||
|
||||
!pts_dh_group_probe(&supported_dh_groups))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
|
||||
imc_id, actual_version);
|
||||
if (!imc_attestation)
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
|
||||
libpts_init();
|
||||
|
||||
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.7.2 of TCG TNC IF-IMC Specification 1.2
|
||||
*/
|
||||
TNC_Result 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_DELETE:
|
||||
return imc_attestation->delete_state(imc_attestation, connection_id);
|
||||
case TNC_CONNECTION_STATE_HANDSHAKE:
|
||||
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.7.3 of TCG TNC IF-IMC Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
|
||||
TNC_ConnectionID connection_id)
|
||||
{
|
||||
imc_state_t *state;
|
||||
imc_attestation_state_t *attestation_state;
|
||||
pts_t *pts;
|
||||
char *platform_info;
|
||||
TNC_Result result = TNC_RESULT_SUCCESS;
|
||||
|
||||
if (!imc_attestation)
|
||||
{
|
||||
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
/* get current IMC state */
|
||||
if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
attestation_state = (imc_attestation_state_t*)state;
|
||||
pts = attestation_state->get_pts(attestation_state);
|
||||
|
||||
platform_info = pts->get_platform_info(pts);
|
||||
if (platform_info)
|
||||
{
|
||||
pa_tnc_msg_t *pa_tnc_msg;
|
||||
pa_tnc_attr_t *attr;
|
||||
|
||||
pa_tnc_msg = pa_tnc_msg_create();
|
||||
attr = ietf_attr_product_info_create(0, 0, platform_info);
|
||||
pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
|
||||
pa_tnc_msg->build(pa_tnc_msg);
|
||||
result = imc_attestation->send_message(imc_attestation, connection_id,
|
||||
pa_tnc_msg->get_encoding(pa_tnc_msg));
|
||||
pa_tnc_msg->destroy(pa_tnc_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
|
||||
TNC_ConnectionID connection_id,
|
||||
TNC_BufferReference msg,
|
||||
TNC_UInt32 msg_len,
|
||||
TNC_MessageType msg_type)
|
||||
{
|
||||
pa_tnc_msg_t *pa_tnc_msg;
|
||||
pa_tnc_attr_t *attr;
|
||||
linked_list_t *attr_list;
|
||||
imc_state_t *state;
|
||||
imc_attestation_state_t *attestation_state;
|
||||
enumerator_t *enumerator;
|
||||
TNC_Result result;
|
||||
|
||||
if (!imc_attestation)
|
||||
{
|
||||
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
/* get current IMC state */
|
||||
if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
attestation_state = (imc_attestation_state_t*)state;
|
||||
|
||||
/* parse received PA-TNC message and automatically handle any errors */
|
||||
result = imc_attestation->receive_message(imc_attestation, connection_id,
|
||||
chunk_create(msg, msg_len), msg_type,
|
||||
&pa_tnc_msg);
|
||||
|
||||
/* no parsed PA-TNC attributes available if an error occurred */
|
||||
if (!pa_tnc_msg)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
attr_list = linked_list_create();
|
||||
result = TNC_RESULT_SUCCESS;
|
||||
|
||||
/* analyze PA-TNC attributes */
|
||||
enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
|
||||
while (enumerator->enumerate(enumerator, &attr))
|
||||
{
|
||||
if (attr->get_vendor_id(attr) == PEN_IETF &&
|
||||
attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
|
||||
{
|
||||
ietf_attr_pa_tnc_error_t *error_attr;
|
||||
pa_tnc_error_code_t error_code;
|
||||
chunk_t msg_info, attr_info;
|
||||
u_int32_t offset;
|
||||
|
||||
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
|
||||
error_code = error_attr->get_error_code(error_attr);
|
||||
msg_info = error_attr->get_msg_info(error_attr);
|
||||
|
||||
DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
|
||||
pa_tnc_error_code_names, error_code, &msg_info);
|
||||
switch (error_code)
|
||||
{
|
||||
case PA_ERROR_INVALID_PARAMETER:
|
||||
offset = error_attr->get_offset(error_attr);
|
||||
DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
|
||||
break;
|
||||
case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
|
||||
attr_info = error_attr->get_attr_info(error_attr);
|
||||
DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
result = TNC_RESULT_FATAL;
|
||||
}
|
||||
else if (attr->get_vendor_id(attr) == PEN_TCG)
|
||||
{
|
||||
if (!imc_attestation_process(attr, attr_list, attestation_state,
|
||||
supported_algorithms, supported_dh_groups))
|
||||
{
|
||||
result = TNC_RESULT_FATAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
pa_tnc_msg->destroy(pa_tnc_msg);
|
||||
|
||||
if (result == TNC_RESULT_SUCCESS && attr_list->get_count(attr_list))
|
||||
{
|
||||
pa_tnc_msg = pa_tnc_msg_create();
|
||||
|
||||
enumerator = attr_list->create_enumerator(attr_list);
|
||||
while (enumerator->enumerate(enumerator, &attr))
|
||||
{
|
||||
pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
pa_tnc_msg->build(pa_tnc_msg);
|
||||
result = imc_attestation->send_message(imc_attestation, connection_id,
|
||||
pa_tnc_msg->get_encoding(pa_tnc_msg));
|
||||
pa_tnc_msg->destroy(pa_tnc_msg);
|
||||
}
|
||||
|
||||
attr_list->destroy(attr_list);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
|
||||
*/
|
||||
TNC_Result 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.7.6 of TCG TNC IF-IMC Specification 1.2
|
||||
*/
|
||||
TNC_Result 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;
|
||||
}
|
||||
|
||||
libpts_deinit();
|
||||
|
||||
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.2
|
||||
*/
|
||||
TNC_Result 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,466 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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 <libpts.h>
|
||||
#include <pts/pts.h>
|
||||
|
||||
#include <tcg/tcg_pts_attr_proto_caps.h>
|
||||
#include <tcg/tcg_pts_attr_meas_algo.h>
|
||||
#include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
|
||||
#include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
|
||||
#include <tcg/tcg_pts_attr_dh_nonce_finish.h>
|
||||
#include <tcg/tcg_pts_attr_get_tpm_version_info.h>
|
||||
#include <tcg/tcg_pts_attr_tpm_version_info.h>
|
||||
#include <tcg/tcg_pts_attr_get_aik.h>
|
||||
#include <tcg/tcg_pts_attr_aik.h>
|
||||
#include <tcg/tcg_pts_attr_req_func_comp_evid.h>
|
||||
#include <tcg/tcg_pts_attr_gen_attest_evid.h>
|
||||
#include <tcg/tcg_pts_attr_simple_comp_evid.h>
|
||||
#include <tcg/tcg_pts_attr_simple_evid_final.h>
|
||||
#include <tcg/tcg_pts_attr_req_file_meas.h>
|
||||
#include <tcg/tcg_pts_attr_file_meas.h>
|
||||
#include <tcg/tcg_pts_attr_req_file_meta.h>
|
||||
#include <tcg/tcg_pts_attr_unix_file_meta.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <utils/lexparser.h>
|
||||
|
||||
#define DEFAULT_NONCE_LEN 20
|
||||
|
||||
bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||
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;
|
||||
bool valid_path;
|
||||
|
||||
pts = attestation_state->get_pts(attestation_state);
|
||||
switch (attr->get_type(attr))
|
||||
{
|
||||
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);
|
||||
attr_list->insert_last(attr_list, 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);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send Measurement Algorithm Selection attribute */
|
||||
pts->set_meas_algorithm(pts, selected_algorithm);
|
||||
attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE);
|
||||
attr_list->insert_last(attr_list, 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,
|
||||
"libimcv.plugins.imc-attestation.nonce_len",
|
||||
DEFAULT_NONCE_LEN);
|
||||
|
||||
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);
|
||||
attr_list->insert_last(attr_list, 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);
|
||||
attr_list->insert_last(attr_list, 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);
|
||||
attr_list->insert_last(attr_list, 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,
|
||||
"libimcv.plugins.imc-attestation.nonce_len",
|
||||
DEFAULT_NONCE_LEN);
|
||||
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;
|
||||
|
||||
if (!pts->get_tpm_version_info(pts, &tpm_version_info))
|
||||
{
|
||||
attr_info = attr->get_value(attr);
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send TPM Version Info attribute */
|
||||
attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
|
||||
attr_list->insert_last(attr_list, 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);
|
||||
attr_list->insert_last(attr_list, 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;
|
||||
|
||||
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)
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
pts_error, attr_info);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
else if (!valid_path)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
TCG_PTS_INVALID_DELIMITER, attr_info);
|
||||
attr_list->insert_last(attr_list, 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->do_measurements(pts, request_id,
|
||||
pathname, is_directory);
|
||||
if (!measurements)
|
||||
{
|
||||
/* TODO handle error codes from measurements */
|
||||
return FALSE;
|
||||
}
|
||||
attr = tcg_pts_attr_file_meas_create(measurements);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
attr_list->insert_last(attr_list, 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;
|
||||
|
||||
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)
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
pts_error, attr_info);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
else if (!valid_path)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
TCG_PTS_INVALID_DELIMITER, attr_info);
|
||||
attr_list->insert_last(attr_list, 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);
|
||||
attr_list->insert_last(attr_list, 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;
|
||||
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)
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
TCG_PTS_UNABLE_DET_TTC, attr_info);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
if (flags & PTS_REQ_FUNC_COMP_EVID_VER &&
|
||||
!(negotiated_caps & PTS_PROTO_CAPS_V))
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
TCG_PTS_UNABLE_LOCAL_VAL, attr_info);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
if (flags & PTS_REQ_FUNC_COMP_EVID_CURR &&
|
||||
!(negotiated_caps & PTS_PROTO_CAPS_C))
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
TCG_PTS_UNABLE_CUR_EVID, attr_info);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
if (flags & PTS_REQ_FUNC_COMP_EVID_PCR &&
|
||||
!(negotiated_caps & PTS_PROTO_CAPS_T))
|
||||
{
|
||||
attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
|
||||
TCG_PTS_UNABLE_DET_PCR, attr_info);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
break;
|
||||
}
|
||||
if (depth > 0)
|
||||
{
|
||||
DBG1(DBG_IMC, "the Attestation IMC currently does not "
|
||||
"support sub component measurements");
|
||||
return FALSE;
|
||||
}
|
||||
comp = pts_components->create(pts_components, name, depth);
|
||||
if (!comp)
|
||||
{
|
||||
DBG2(DBG_IMC, " not registered: no evidence provided");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* do the component evidence measurement[s] */
|
||||
do
|
||||
{
|
||||
status = comp->measure(comp, pts, &evid);
|
||||
if (status == FAILED)
|
||||
{
|
||||
break;
|
||||
}
|
||||
attestation_state->add_evidence(attestation_state, evid);
|
||||
}
|
||||
while (status == NEED_MORE);
|
||||
comp->destroy(comp);
|
||||
}
|
||||
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 buffered Simple Component Evidences */
|
||||
while (attestation_state->next_evidence(attestation_state, &evid))
|
||||
{
|
||||
pts->select_pcr(pts, evid->get_extended_pcr(evid));
|
||||
|
||||
/* Send Simple Component Evidence */
|
||||
attr = tcg_pts_attr_simple_comp_evid_create(evid);
|
||||
attr_list->insert_last(attr_list, attr);
|
||||
}
|
||||
|
||||
use_quote2 = lib->settings->get_bool(lib->settings,
|
||||
"libimcv.plugins.imc-attestation.use_quote2", TRUE);
|
||||
if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, "e_sig))
|
||||
{
|
||||
DBG1(DBG_IMC, "error occured 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);
|
||||
attr_list->insert_last(attr_list, 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_process
|
||||
*/
|
||||
|
||||
#ifndef IMC_ATTESTATION_PROCESS_H_
|
||||
#define IMC_ATTESTATION_PROCESS_H_
|
||||
|
||||
#include "imc_attestation_state.h"
|
||||
|
||||
#include <library.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 attr_list list with PA-TNC error attributes
|
||||
* @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, linked_list_t *attr_list,
|
||||
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,129 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Sansar Choinyambuu
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "imc_attestation_state.h"
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <debug.h>
|
||||
|
||||
typedef struct private_imc_attestation_state_t private_imc_attestation_state_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;
|
||||
|
||||
/**
|
||||
* PTS object
|
||||
*/
|
||||
pts_t *pts;
|
||||
|
||||
/**
|
||||
* PTS Component Evidence 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, change_state, void,
|
||||
private_imc_attestation_state_t *this, TNC_ConnectionState new_state)
|
||||
{
|
||||
this->state = new_state;
|
||||
}
|
||||
|
||||
|
||||
METHOD(imc_state_t, destroy, void,
|
||||
private_imc_attestation_state_t *this)
|
||||
{
|
||||
this->pts->destroy(this->pts);
|
||||
this->list->destroy_offset(this->list, offsetof(pts_comp_evidence_t, destroy));
|
||||
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, add_evidence, void,
|
||||
private_imc_attestation_state_t *this, pts_comp_evidence_t *evidence)
|
||||
{
|
||||
this->list->insert_last(this->list, evidence);
|
||||
}
|
||||
|
||||
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;
|
||||
char *platform_info;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.interface = {
|
||||
.get_connection_id = _get_connection_id,
|
||||
.change_state = _change_state,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.get_pts = _get_pts,
|
||||
.add_evidence = _add_evidence,
|
||||
.next_evidence = _next_evidence,
|
||||
},
|
||||
.connection_id = connection_id,
|
||||
.state = TNC_CONNECTION_STATE_CREATE,
|
||||
.pts = pts_create(TRUE),
|
||||
.list = linked_list_create(),
|
||||
);
|
||||
|
||||
platform_info = lib->settings->get_str(lib->settings,
|
||||
"libimcv.plugins.imc-attestation.platform_info", NULL);
|
||||
if (platform_info)
|
||||
{
|
||||
this->pts->set_platform_info(this->pts, platform_info);
|
||||
}
|
||||
|
||||
return &this->public.interface;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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_state_t imc_attestation_state
|
||||
* @{ @ingroup imc_attestation_state
|
||||
*/
|
||||
|
||||
#ifndef IMC_ATTESTATION_STATE_H_
|
||||
#define IMC_ATTESTATION_STATE_H_
|
||||
|
||||
#include <imc/imc_state.h>
|
||||
#include <pts/pts.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);
|
||||
|
||||
/**
|
||||
* Add an entry to the Component Evidence list
|
||||
*
|
||||
* @param entry Component Evidence entry
|
||||
*/
|
||||
void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *entry);
|
||||
|
||||
/**
|
||||
* Removes next Component Evidence entry from 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 @@
|
||||
attest
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/src/libstrongswan \
|
||||
-I$(top_srcdir)/src/libtncif \
|
||||
-I$(top_srcdir)/src/libimcv \
|
||||
-I$(top_srcdir)/src/libpts
|
||||
|
||||
AM_CFLAGS = -rdynamic -DPLUGINS=\""${attest_plugins}\""
|
||||
|
||||
imcv_LTLIBRARIES = imv-attestation.la
|
||||
|
||||
imv_attestation_la_LIBADD = \
|
||||
$(top_builddir)/src/libimcv/libimcv.la \
|
||||
$(top_builddir)/src/libstrongswan/libstrongswan.la \
|
||||
$(top_builddir)/src/libpts/libpts.la
|
||||
|
||||
imv_attestation_la_SOURCES = imv_attestation.c \
|
||||
imv_attestation_state.h imv_attestation_state.c \
|
||||
imv_attestation_process.h imv_attestation_process.c \
|
||||
imv_attestation_build.h imv_attestation_build.c
|
||||
|
||||
imv_attestation_la_LDFLAGS = -module -avoid-version
|
||||
|
||||
ipsec_PROGRAMS = attest
|
||||
attest_SOURCES = attest.c \
|
||||
attest_usage.h attest_usage.c \
|
||||
attest_db.h attest_db.c \
|
||||
tables.sql data.sql
|
||||
attest_LDADD = \
|
||||
$(top_builddir)/src/libimcv/libimcv.la \
|
||||
$(top_builddir)/src/libpts/libpts.la \
|
||||
$(top_builddir)/src/libstrongswan/libstrongswan.la
|
||||
attest.o : $(top_builddir)/config.status
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <imcv.h>
|
||||
#include <libpts.h>
|
||||
#include <pts/pts_meas_algo.h>
|
||||
|
||||
#include "attest_db.h"
|
||||
#include "attest_usage.h"
|
||||
|
||||
/**
|
||||
* global debug output variables
|
||||
*/
|
||||
static int debug_level = 0;
|
||||
static bool stderr_quiet = TRUE;
|
||||
|
||||
/**
|
||||
* attest dbg function
|
||||
*/
|
||||
static void attest_dbg(debug_t group, level_t level, char *fmt, ...)
|
||||
{
|
||||
int priority = LOG_INFO;
|
||||
char buffer[8192];
|
||||
char *current = buffer, *next;
|
||||
va_list args;
|
||||
|
||||
if (level <= debug_level)
|
||||
{
|
||||
if (!stderr_quiet)
|
||||
{
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write in memory buffer first */
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
/* do a syslog with every line */
|
||||
while (current)
|
||||
{
|
||||
next = strchr(current, '\n');
|
||||
if (next)
|
||||
{
|
||||
*(next++) = '\0';
|
||||
}
|
||||
syslog(priority, "%s\n", current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* global attestation database object
|
||||
*/
|
||||
attest_db_t *attest;
|
||||
|
||||
/**
|
||||
* atexit handler to close db on shutdown
|
||||
*/
|
||||
static void cleanup(void)
|
||||
{
|
||||
attest->destroy(attest);
|
||||
libpts_deinit();
|
||||
libimcv_deinit();
|
||||
closelog();
|
||||
}
|
||||
|
||||
static void do_args(int argc, char *argv[])
|
||||
{
|
||||
enum {
|
||||
OP_UNDEF,
|
||||
OP_USAGE,
|
||||
OP_FILES,
|
||||
OP_COMPONENTS,
|
||||
OP_PRODUCTS,
|
||||
OP_HASHES,
|
||||
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' },
|
||||
{ "files", no_argument, NULL, 'f' },
|
||||
{ "products", no_argument, NULL, 'p' },
|
||||
{ "hashes", no_argument, NULL, 'H' },
|
||||
{ "add", no_argument, NULL, 'a' },
|
||||
{ "delete", no_argument, NULL, 'd' },
|
||||
{ "del", no_argument, NULL, 'd' },
|
||||
{ "products", no_argument, NULL, 'p' },
|
||||
{ "hashes", no_argument, NULL, 'H' },
|
||||
{ "add", no_argument, NULL, 'a' },
|
||||
{ "delete", no_argument, NULL, 'd' },
|
||||
{ "del", no_argument, NULL, 'd' },
|
||||
{ "directory", required_argument, NULL, 'D' },
|
||||
{ "dir", required_argument, NULL, 'D' },
|
||||
{ "file", required_argument, NULL, 'F' },
|
||||
{ "product", required_argument, NULL, 'P' },
|
||||
{ "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' },
|
||||
{ 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 'f':
|
||||
op = OP_FILES;
|
||||
continue;
|
||||
case 'p':
|
||||
op = OP_PRODUCTS;
|
||||
continue;
|
||||
case 'H':
|
||||
op = OP_HASHES;
|
||||
continue;
|
||||
case 'a':
|
||||
op = OP_ADD;
|
||||
continue;
|
||||
case 'd':
|
||||
op = OP_DEL;
|
||||
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 'H':
|
||||
op = OP_HASHES;
|
||||
continue;
|
||||
case 'a':
|
||||
op = OP_ADD;
|
||||
continue;
|
||||
case 'd':
|
||||
op = OP_DEL;
|
||||
continue;
|
||||
case 'D':
|
||||
if (!attest->set_directory(attest, optarg, op == OP_ADD))
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
continue;
|
||||
case 'F':
|
||||
if (!attest->set_file(attest, optarg, op == OP_ADD))
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
continue;
|
||||
case 'P':
|
||||
if (!attest->set_product(attest, optarg, op == OP_ADD))
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case OP_USAGE:
|
||||
usage();
|
||||
break;
|
||||
case OP_PRODUCTS:
|
||||
attest->list_products(attest);
|
||||
break;
|
||||
case OP_COMPONENTS:
|
||||
attest->list_components(attest);
|
||||
break;
|
||||
case OP_FILES:
|
||||
attest->list_files(attest);
|
||||
break;
|
||||
case OP_HASHES:
|
||||
attest->list_hashes(attest);
|
||||
break;
|
||||
case OP_ADD:
|
||||
attest->add(attest);
|
||||
break;
|
||||
case OP_DEL:
|
||||
attest->delete(attest);
|
||||
break;
|
||||
case OP_HASHES:
|
||||
attest->list_hashes(attest);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *uri;
|
||||
|
||||
/* enable attest debugging hook */
|
||||
dbg = attest_dbg;
|
||||
openlog("attest", 0, LOG_DEBUG);
|
||||
|
||||
atexit(library_deinit);
|
||||
|
||||
/* initialize library */
|
||||
if (!library_init(NULL))
|
||||
{
|
||||
exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
|
||||
}
|
||||
if (!lib->plugins->load(lib->plugins, NULL,
|
||||
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();
|
||||
libpts_init();
|
||||
|
||||
do_args(argc, argv);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Andreas Steffen
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "attest_db.h"
|
||||
|
||||
#include "libpts.h"
|
||||
#include "pts/components/pts_comp_func_name.h"
|
||||
|
||||
typedef struct private_attest_db_t private_attest_db_t;
|
||||
|
||||
/**
|
||||
* Private data of an attest_db_t object.
|
||||
*/
|
||||
struct private_attest_db_t {
|
||||
|
||||
/**
|
||||
* Public members of attest_db_state_t
|
||||
*/
|
||||
attest_db_t public;
|
||||
|
||||
/**
|
||||
* Software product to be queried
|
||||
*/
|
||||
char *product;
|
||||
|
||||
/**
|
||||
* Primary key of software product to be queried
|
||||
*/
|
||||
int pid;
|
||||
|
||||
/**
|
||||
* TRUE if product has been set
|
||||
*/
|
||||
bool product_set;
|
||||
|
||||
/**
|
||||
* Measurement file to be queried
|
||||
*/
|
||||
char *file;
|
||||
|
||||
/**
|
||||
* Primary key of measurement file to be queried
|
||||
*/
|
||||
int fid;
|
||||
|
||||
/**
|
||||
* TRUE if file has been set
|
||||
*/
|
||||
bool file_set;
|
||||
|
||||
/**
|
||||
* Directory containing the Measurement file to be queried
|
||||
*/
|
||||
char *dir;
|
||||
|
||||
/**
|
||||
* Primary key of the directory to be queried
|
||||
*/
|
||||
int did;
|
||||
|
||||
/**
|
||||
* TRUE if directory has been set
|
||||
*/
|
||||
bool dir_set;
|
||||
|
||||
/**
|
||||
* Component Functional Name to be queried
|
||||
*/
|
||||
pts_comp_func_name_t *cfn;
|
||||
|
||||
/**
|
||||
* Primary key of the Component Functional Name to be queried
|
||||
*/
|
||||
int cid;
|
||||
|
||||
/**
|
||||
* TRUE if Component Functional Name has been set
|
||||
*/
|
||||
bool comp_set;
|
||||
|
||||
/**
|
||||
* File measurement hash algorithm
|
||||
*/
|
||||
pts_meas_algorithms_t algo;
|
||||
|
||||
/**
|
||||
* Attestation database
|
||||
*/
|
||||
database_t *db;
|
||||
|
||||
};
|
||||
|
||||
char* print_cfn(pts_comp_func_name_t *cfn)
|
||||
{
|
||||
static char buf[BUF_LEN];
|
||||
char flags[8];
|
||||
int type, vid, name, qualifier, n;
|
||||
enum_name_t *names, *types;
|
||||
|
||||
vid = cfn->get_vendor_id(cfn),
|
||||
name = cfn->get_name(cfn);
|
||||
qualifier = cfn->get_qualifier(cfn);
|
||||
n = snprintf(buf, BUF_LEN, "0x%06x/0x%08x-0x%02x", vid, name, qualifier);
|
||||
|
||||
names = pts_components->get_comp_func_names(pts_components, vid);
|
||||
types = pts_components->get_qualifier_type_names(pts_components, vid);
|
||||
type = pts_components->get_qualifier(pts_components, cfn, flags);
|
||||
if (names && types)
|
||||
{
|
||||
n = snprintf(buf + n, BUF_LEN - n, " %N/%N [%s] %N",
|
||||
pen_names, vid, names, name, flags, types, type);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_product, bool,
|
||||
private_attest_db_t *this, char *product, bool create)
|
||||
{
|
||||
enumerator_t *e;
|
||||
|
||||
if (this->product_set)
|
||||
{
|
||||
printf("product has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
this->product = strdup(product);
|
||||
|
||||
e = this->db->query(this->db, "SELECT id FROM products WHERE name = ?",
|
||||
DB_TEXT, product, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &this->pid))
|
||||
{
|
||||
this->product_set = TRUE;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
if (this->product_set)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
{
|
||||
printf("product '%s' not found in database\n", product);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Add a new database entry */
|
||||
this->product_set = this->db->execute(this->db, &this->pid,
|
||||
"INSERT INTO products (name) VALUES (?)",
|
||||
DB_TEXT, product) == 1;
|
||||
|
||||
printf("product '%s' %sinserted into database\n", product,
|
||||
this->product_set ? "" : "could not be ");
|
||||
|
||||
return this->product_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_pid, bool,
|
||||
private_attest_db_t *this, int pid)
|
||||
{
|
||||
enumerator_t *e;
|
||||
char *product;
|
||||
|
||||
if (this->product_set)
|
||||
{
|
||||
printf("product has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
this->pid = pid;
|
||||
|
||||
e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?",
|
||||
DB_INT, pid, DB_TEXT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &product))
|
||||
{
|
||||
this->product = strdup(product);
|
||||
this->product_set = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("no product found with pid %d in database\n", pid);
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
return this->product_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_file, bool,
|
||||
private_attest_db_t *this, char *file, bool create)
|
||||
{
|
||||
enumerator_t *e;
|
||||
|
||||
if (this->file_set)
|
||||
{
|
||||
printf("file has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
this->file = strdup(file);
|
||||
|
||||
e = this->db->query(this->db, "SELECT id FROM files WHERE path = ?",
|
||||
DB_TEXT, file, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &this->fid))
|
||||
{
|
||||
this->file_set = TRUE;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
if (this->file_set)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
{
|
||||
printf("file '%s' not found in database\n", file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Add a new database entry */
|
||||
this->file_set = this->db->execute(this->db, &this->fid,
|
||||
"INSERT INTO files (type, path) VALUES (0, ?)",
|
||||
DB_TEXT, file) == 1;
|
||||
|
||||
printf("file '%s' %sinserted into database\n", file,
|
||||
this->file_set ? "" : "could not be ");
|
||||
|
||||
return this->file_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_fid, bool,
|
||||
private_attest_db_t *this, int fid)
|
||||
{
|
||||
enumerator_t *e;
|
||||
char *file;
|
||||
|
||||
if (this->file_set)
|
||||
{
|
||||
printf("file has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
this->fid = fid;
|
||||
|
||||
e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?",
|
||||
DB_INT, fid, DB_TEXT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &file))
|
||||
{
|
||||
this->file = strdup(file);
|
||||
this->file_set = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("no file found with fid %d\n", fid);
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
return this->file_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_directory, bool,
|
||||
private_attest_db_t *this, char *dir, bool create)
|
||||
{
|
||||
enumerator_t *e;
|
||||
|
||||
if (this->dir_set)
|
||||
{
|
||||
printf("directory has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
free(this->dir);
|
||||
this->dir = strdup(dir);
|
||||
|
||||
e = this->db->query(this->db,
|
||||
"SELECT id FROM files WHERE type = 1 AND path = ?",
|
||||
DB_TEXT, dir, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &this->did))
|
||||
{
|
||||
this->dir_set = TRUE;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
if (this->dir_set)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
{
|
||||
printf("directory '%s' not found in database\n", dir);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Add a new database entry */
|
||||
this->dir_set = this->db->execute(this->db, &this->did,
|
||||
"INSERT INTO files (type, path) VALUES (1, ?)",
|
||||
DB_TEXT, dir) == 1;
|
||||
|
||||
printf("directory '%s' %sinserted into database\n", dir,
|
||||
this->dir_set ? "" : "could not be ");
|
||||
|
||||
return this->dir_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_did, bool,
|
||||
private_attest_db_t *this, int did)
|
||||
{
|
||||
enumerator_t *e;
|
||||
char *dir;
|
||||
|
||||
if (this->dir_set)
|
||||
{
|
||||
printf("directory has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
this->did = did;
|
||||
|
||||
e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?",
|
||||
DB_INT, did, DB_TEXT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &dir))
|
||||
{
|
||||
free(this->dir);
|
||||
this->dir = strdup(dir);
|
||||
this->dir_set = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("no directory found with did %d\n", did);
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
return this->dir_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_component, bool,
|
||||
private_attest_db_t *this, char *comp, bool create)
|
||||
{
|
||||
enumerator_t *e;
|
||||
char *pos1, *pos2;
|
||||
int vid, name, qualifier;
|
||||
pts_comp_func_name_t *cfn;
|
||||
|
||||
if (this->comp_set)
|
||||
{
|
||||
printf("component has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* parse component string */
|
||||
pos1 = strchr(comp, '/');
|
||||
pos2 = strchr(comp, '-');
|
||||
if (!pos1 || !pos2)
|
||||
{
|
||||
printf("component string must have the form \"vendor_id/name-qualifier\"\n");
|
||||
return FALSE;
|
||||
}
|
||||
vid = atoi(comp);
|
||||
name = atoi(pos1 + 1);
|
||||
qualifier = atoi(pos2 + 1);
|
||||
cfn = pts_comp_func_name_create(vid, name, qualifier);
|
||||
|
||||
e = this->db->query(this->db,
|
||||
"SELECT id FROM components "
|
||||
"WHERE vendor_id = ? AND name = ? AND qualifier = ?",
|
||||
DB_INT, vid, DB_INT, name, DB_INT, qualifier, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &this->cid))
|
||||
{
|
||||
this->comp_set = TRUE;
|
||||
this->cfn = cfn;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
if (this->comp_set)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!create)
|
||||
{
|
||||
printf("component '%s' not found in database\n", print_cfn(cfn));
|
||||
cfn->destroy(cfn);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Add a new database entry */
|
||||
this->comp_set = this->db->execute(this->db, &this->cid,
|
||||
"INSERT INTO components (vendor_id, name, qualifier) "
|
||||
"VALUES (?, ?, ?)",
|
||||
DB_INT, vid, DB_INT, name, DB_INT, qualifier) == 1;
|
||||
|
||||
printf("component '%s' %sinserted into database\n", print_cfn(cfn),
|
||||
this->comp_set ? "" : "could not be ");
|
||||
if (this->comp_set)
|
||||
{
|
||||
this->cfn = cfn;
|
||||
}
|
||||
else
|
||||
{
|
||||
cfn->destroy(cfn);
|
||||
}
|
||||
return this->comp_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_cid, bool,
|
||||
private_attest_db_t *this, int cid)
|
||||
{
|
||||
enumerator_t *e;
|
||||
int vid, name, qualifier;
|
||||
|
||||
if (this->comp_set)
|
||||
{
|
||||
printf("component has already been set\n");
|
||||
return FALSE;
|
||||
}
|
||||
this->cid = cid;
|
||||
|
||||
e = this->db->query(this->db, "SELECT vendor_id, name, qualifier "
|
||||
"FROM components WHERE id = ?",
|
||||
DB_INT, cid, DB_INT, DB_INT, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &vid, &name, &qualifier))
|
||||
{
|
||||
this->cfn = pts_comp_func_name_create(vid, name, qualifier);
|
||||
this->comp_set = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("no component found with cid %d\n", cid);
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
return this->comp_set;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, set_algo, void,
|
||||
private_attest_db_t *this, pts_meas_algorithms_t algo)
|
||||
{
|
||||
this->algo = algo;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, list_components, void,
|
||||
private_attest_db_t *this)
|
||||
{
|
||||
enumerator_t *e;
|
||||
pts_comp_func_name_t *cfn;
|
||||
int cid, vid, name, qualifier, count = 0;
|
||||
|
||||
if (this->pid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT c.id, c.vendor_id, c.name, c.qualifier "
|
||||
"FROM components AS c "
|
||||
"JOIN product_component AS pc ON c.id = pc.component "
|
||||
"WHERE pc.product = ? ORDER BY c.vendor_id, c.name, c.qualifier",
|
||||
DB_INT, this->pid, DB_INT, DB_INT, DB_INT, DB_INT);
|
||||
}
|
||||
else
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT id, vendor_id, name, qualifier FROM components "
|
||||
"ORDER BY vendor_id, name, qualifier",
|
||||
DB_INT, DB_INT, DB_INT, DB_INT);
|
||||
}
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &cid, &vid, &name, &qualifier))
|
||||
{
|
||||
cfn = pts_comp_func_name_create(vid, name, qualifier);
|
||||
printf("%3d: %s\n", cid, print_cfn(cfn));
|
||||
cfn->destroy(cfn);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
|
||||
printf("%d component%s found", count, (count == 1) ? "" : "s");
|
||||
if (this->product_set)
|
||||
{
|
||||
printf(" for product '%s'", this->product);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, list_files, void,
|
||||
private_attest_db_t *this)
|
||||
{
|
||||
enumerator_t *e;
|
||||
char *file, *file_type[] = { " ", "d", "r" };
|
||||
int fid, type, meas, meta, count = 0;
|
||||
|
||||
if (this->pid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT f.id, f.type, f.path, pf.measurement, pf.metadata "
|
||||
"FROM files AS f "
|
||||
"JOIN product_file AS pf ON f.id = pf.file "
|
||||
"WHERE pf.product = ? ORDER BY f.path",
|
||||
DB_INT, this->pid, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &fid, &type, &file, &meas, &meta))
|
||||
{
|
||||
type = (type < 0 || type > 2) ? 0 : type;
|
||||
printf("%3d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ",
|
||||
file_type[type], file);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT id, type, path FROM files "
|
||||
"ORDER BY path",
|
||||
DB_INT, DB_INT, DB_TEXT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &fid, &type, &file))
|
||||
{
|
||||
type = (type < 0 || type > 2) ? 0 : type;
|
||||
printf("%3d: %s %s\n", fid, file_type[type], file);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d file%s found", count, (count == 1) ? "" : "s");
|
||||
if (this->product_set)
|
||||
{
|
||||
printf(" for product '%s'", this->product);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, list_products, void,
|
||||
private_attest_db_t *this)
|
||||
{
|
||||
enumerator_t *e;
|
||||
char *product;
|
||||
int pid, meas, meta, count = 0;
|
||||
|
||||
if (this->fid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT p.id, p.name, pf.measurement, pf.metadata "
|
||||
"FROM products AS p "
|
||||
"JOIN product_file AS pf ON p.id = pf.product "
|
||||
"WHERE pf.file = ? ORDER BY p.name",
|
||||
DB_INT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &pid, &product, &meas, &meta))
|
||||
{
|
||||
printf("%3d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ",
|
||||
product);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
}
|
||||
else if (this->cid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT p.id, p.name FROM products AS p "
|
||||
"JOIN product_component AS pc ON p.id = pc.product "
|
||||
"WHERE pc.component = ? ORDER BY p.name",
|
||||
DB_INT, this->cid, DB_INT, DB_TEXT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &pid, &product, &meas, &meta))
|
||||
{
|
||||
printf("%3d: %s\n", pid, product);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e = this->db->query(this->db, "SELECT id, name FROM products "
|
||||
"ORDER BY name",
|
||||
DB_INT, DB_TEXT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &pid, &product))
|
||||
{
|
||||
printf("%3d: %s\n", pid, product);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d product%s found", count, (count == 1) ? "" : "s");
|
||||
if (this->file_set)
|
||||
{
|
||||
printf(" for file '%s'", this->file);
|
||||
}
|
||||
else if (this->comp_set)
|
||||
{
|
||||
printf(" for component '%s'", print_cfn(this->cfn));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* get the directory if there is one from the files tables
|
||||
*/
|
||||
static void get_directory(private_attest_db_t *this, int did, char **directory)
|
||||
{
|
||||
enumerator_t *e;
|
||||
char *dir;
|
||||
|
||||
free(*directory);
|
||||
*directory = strdup("");
|
||||
|
||||
if (did)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT path from files WHERE id = ?",
|
||||
DB_INT, did, DB_TEXT);
|
||||
if (e)
|
||||
{
|
||||
if (e->enumerate(e, &dir))
|
||||
{
|
||||
free(*directory);
|
||||
*directory = strdup(dir);
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool slash(char *directory, char *file)
|
||||
{
|
||||
return *file != '/' && directory[max(0, strlen(directory)-1)] != '/';
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, list_hashes, void,
|
||||
private_attest_db_t *this)
|
||||
{
|
||||
enumerator_t *e;
|
||||
chunk_t hash;
|
||||
char *file, *dir, *product;
|
||||
int fid, fid_old = 0, did, did_old = 0, count = 0;
|
||||
|
||||
dir = strdup("");
|
||||
|
||||
if (this->pid && this->fid && this->cid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT hash FROM file_hashes "
|
||||
"WHERE algo = ? AND file = ? AND component = ? AND product = ?",
|
||||
DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->cid,
|
||||
DB_INT, this->pid, DB_BLOB);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &hash))
|
||||
{
|
||||
if (this->fid != fid_old)
|
||||
{
|
||||
printf("%3d: %s%s%s\n", this->fid, this->dir,
|
||||
slash(this->dir, this->file) ? "/" : "", this->file);
|
||||
fid_old = this->fid;
|
||||
}
|
||||
printf(" %#B '%s'\n", &hash, this->product);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
|
||||
printf("%d %N value%s found for component '%s'\n", count,
|
||||
hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
|
||||
(count == 1) ? "" : "s", print_cfn(this->cfn));
|
||||
}
|
||||
}
|
||||
else if (this->pid && this->fid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT hash FROM file_hashes "
|
||||
"WHERE algo = ? AND file = ? AND directory = ? AND product = ?",
|
||||
DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did,
|
||||
DB_INT, this->pid, DB_BLOB);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &hash))
|
||||
{
|
||||
if (this->fid != fid_old)
|
||||
{
|
||||
printf("%3d: %s%s%s\n", this->fid, this->dir,
|
||||
slash(this->dir, this->file) ? "/" : "", this->file);
|
||||
fid_old = this->fid;
|
||||
}
|
||||
printf(" %#B\n", &hash);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
|
||||
printf("%d %N value%s found for product '%s'\n", count,
|
||||
hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
|
||||
(count == 1) ? "" : "s", this->product);
|
||||
}
|
||||
}
|
||||
else if (this->pid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT f.id, f. f.path, fh.hash, fh.directory "
|
||||
"FROM file_hashes AS fh "
|
||||
"JOIN files AS f ON f.id = fh.file "
|
||||
"WHERE fh.algo = ? AND fh.product = ? "
|
||||
"ORDER BY fh.directory, f.path",
|
||||
DB_INT, this->algo, DB_INT, this->pid,
|
||||
DB_INT, DB_TEXT, DB_BLOB, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &fid, &file, &hash, &did))
|
||||
{
|
||||
if (fid != fid_old || did != did_old)
|
||||
{
|
||||
if (did != did_old)
|
||||
{
|
||||
get_directory(this, did, &dir);
|
||||
}
|
||||
printf("%3d: %s%s%s\n", fid,
|
||||
dir, slash(dir, file) ? "/" : "", file);
|
||||
fid_old = fid;
|
||||
did_old = did;
|
||||
}
|
||||
printf(" %#B\n", &hash);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
|
||||
printf("%d %N value%s found for product '%s'\n", count,
|
||||
hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
|
||||
(count == 1) ? "" : "s", this->product);
|
||||
}
|
||||
}
|
||||
else if (this->fid)
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT p.name, fh.hash, fh.directory "
|
||||
"FROM file_hashes AS fh "
|
||||
"JOIN products AS p ON p.id = fh.product "
|
||||
"WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?"
|
||||
"ORDER BY p.name",
|
||||
DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did,
|
||||
DB_TEXT, DB_BLOB, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &product, &hash, &did))
|
||||
{
|
||||
printf("%#B '%s'\n", &hash, product);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
|
||||
printf("%d %N value%s found for file '%s%s%s'\n",
|
||||
count, hash_algorithm_names, pts_meas_algo_to_hash(this->algo),
|
||||
(count == 1) ? "" : "s", this->dir,
|
||||
slash(this->dir, this->file) ? "/" : "", this->file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e = this->db->query(this->db,
|
||||
"SELECT f.id, f.path, p.name, fh.hash, fh.directory "
|
||||
"FROM file_hashes AS fh "
|
||||
"JOIN files AS f ON f.id = fh.file "
|
||||
"JOIN products AS p ON p.id = fh.product "
|
||||
"WHERE fh.algo = ? "
|
||||
"ORDER BY fh.directory, f.path, p.name",
|
||||
DB_INT, this->algo,
|
||||
DB_INT, DB_TEXT, DB_TEXT, DB_BLOB, DB_INT);
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &fid, &file, &product, &hash, &did))
|
||||
{
|
||||
if (fid != fid_old || did != did_old)
|
||||
{
|
||||
if (did != did_old)
|
||||
{
|
||||
get_directory(this, did, &dir);
|
||||
did_old = did;
|
||||
}
|
||||
printf("%3d: %s%s%s\n", fid,
|
||||
dir, slash(dir, file) ? "/" : "", file);
|
||||
fid_old = fid;
|
||||
}
|
||||
printf(" %#B '%s'\n", &hash, product);
|
||||
count++;
|
||||
}
|
||||
e->destroy(e);
|
||||
|
||||
printf("%d %N value%s found\n", count, hash_algorithm_names,
|
||||
pts_meas_algo_to_hash(this->algo), (count == 1) ? "" : "s");
|
||||
}
|
||||
}
|
||||
free(dir);
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, add, bool,
|
||||
private_attest_db_t *this)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, delete, bool,
|
||||
private_attest_db_t *this)
|
||||
{
|
||||
bool success;
|
||||
|
||||
if (this->pid && (this->fid || this->did))
|
||||
{
|
||||
printf("deletion of product/file entries not supported yet\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (this->pid)
|
||||
{
|
||||
success = this->db->execute(this->db, NULL,
|
||||
"DELETE FROM products WHERE id = ?",
|
||||
DB_UINT, this->pid) > 0;
|
||||
|
||||
printf("product '%s' %sdeleted from database\n", this->product,
|
||||
success ? "" : "could not be ");
|
||||
return success;
|
||||
}
|
||||
|
||||
if (this->fid)
|
||||
{
|
||||
success = this->db->execute(this->db, NULL,
|
||||
"DELETE FROM files WHERE id = ?",
|
||||
DB_UINT, this->fid) > 0;
|
||||
|
||||
printf("file '%s' %sdeleted from database\n", this->file,
|
||||
success ? "" : "could not be ");
|
||||
return success;
|
||||
}
|
||||
|
||||
if (this->did)
|
||||
{
|
||||
success = this->db->execute(this->db, NULL,
|
||||
"DELETE FROM files WHERE type = 1 AND id = ?",
|
||||
DB_UINT, this->did) > 0;
|
||||
|
||||
printf("directory '%s' %sdeleted from database\n", this->dir,
|
||||
success ? "" : "could not be ");
|
||||
return success;
|
||||
}
|
||||
|
||||
if (this->cid)
|
||||
{
|
||||
success = this->db->execute(this->db, NULL,
|
||||
"DELETE FROM components WHERE id = ?",
|
||||
DB_UINT, this->cid) > 0;
|
||||
|
||||
printf("component '%s' %sdeleted from database\n", print_cfn(this->cfn),
|
||||
success ? "" : "could not be ");
|
||||
return success;
|
||||
}
|
||||
|
||||
printf("empty delete command\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(attest_db_t, destroy, void,
|
||||
private_attest_db_t *this)
|
||||
{
|
||||
DESTROY_IF(this->db);
|
||||
DESTROY_IF(this->cfn);
|
||||
free(this->product);
|
||||
free(this->file);
|
||||
free(this->dir);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
attest_db_t *attest_db_create(char *uri)
|
||||
{
|
||||
private_attest_db_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.set_product = _set_product,
|
||||
.set_pid = _set_pid,
|
||||
.set_file = _set_file,
|
||||
.set_fid = _set_fid,
|
||||
.set_directory = _set_directory,
|
||||
.set_did = _set_did,
|
||||
.set_component = _set_component,
|
||||
.set_cid = _set_cid,
|
||||
.set_algo = _set_algo,
|
||||
.list_products = _list_products,
|
||||
.list_files = _list_files,
|
||||
.list_components = _list_components,
|
||||
.list_hashes = _list_hashes,
|
||||
.add = _add,
|
||||
.delete = _delete,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.dir = strdup(""),
|
||||
.algo = PTS_MEAS_ALGO_SHA256,
|
||||
.db = lib->db->create(lib->db, uri),
|
||||
);
|
||||
|
||||
if (!this->db)
|
||||
{
|
||||
fprintf(stderr, "opening database failed.\n");
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Andreas Steffen
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @defgroup attest_db_t attest_db
|
||||
* @{ @ingroup attest_db
|
||||
*/
|
||||
|
||||
#ifndef ATTEST_DB_H_
|
||||
#define ATTEST_DB_H_
|
||||
|
||||
#include <pts/pts_meas_algo.h>
|
||||
|
||||
#include <library.h>
|
||||
|
||||
typedef struct attest_db_t attest_db_t;
|
||||
|
||||
/**
|
||||
* Attestation database object
|
||||
*/
|
||||
struct attest_db_t {
|
||||
|
||||
/**
|
||||
* 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 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 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 hash algorithm
|
||||
*
|
||||
* @param algo hash algorithm
|
||||
*/
|
||||
void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo);
|
||||
|
||||
/**
|
||||
* List all products stored in the database
|
||||
*/
|
||||
void (*list_products)(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 selected measurement hashes stored in the database
|
||||
*/
|
||||
void (*list_hashes)(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,56 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Andreas Steffen
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "attest_usage.h"
|
||||
|
||||
/**
|
||||
* print attest usage info
|
||||
*/
|
||||
void usage(void)
|
||||
{
|
||||
printf("\
|
||||
Usage:\n\
|
||||
ipsec attest --files|--components|--products|--hashes|--add|--del [options]\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 --components [--product <name>|--pid <id>]\n\
|
||||
Show a list of components with a software product name 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 --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|--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 --add --file <path>|--dir <path>|--product <name>\n\
|
||||
Add a file, directory or product entry\n\
|
||||
\n\
|
||||
ipsec attest --del --file <path>|--fid <id>|--dir <path>|--did <id>|--product <name>|--pid <id>\n\
|
||||
Delete a file, directory or product entry referenced either by value or by primary key\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_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,656 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Sansar Choinyambuu
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "imv_attestation_state.h"
|
||||
#include "imv_attestation_process.h"
|
||||
#include "imv_attestation_build.h"
|
||||
|
||||
#include <imv/imv_agent.h>
|
||||
#include <pa_tnc/pa_tnc_msg.h>
|
||||
#include <ietf/ietf_attr.h>
|
||||
#include <ietf/ietf_attr_pa_tnc_error.h>
|
||||
#include <ietf/ietf_attr_product_info.h>
|
||||
|
||||
#include <libpts.h>
|
||||
|
||||
#include <pts/pts.h>
|
||||
#include <pts/pts_database.h>
|
||||
#include <pts/pts_creds.h>
|
||||
|
||||
#include <tcg/tcg_attr.h>
|
||||
|
||||
#include <tncif_pa_subtypes.h>
|
||||
|
||||
#include <pen/pen.h>
|
||||
#include <debug.h>
|
||||
#include <credentials/credential_manager.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
/* IMV definitions */
|
||||
|
||||
static const char imv_name[] = "Attestation";
|
||||
|
||||
#define IMV_VENDOR_ID PEN_TCG
|
||||
#define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
|
||||
|
||||
static imv_agent_t *imv_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;
|
||||
|
||||
/**
|
||||
* Supported PTS Diffie Hellman Groups
|
||||
*/
|
||||
static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
|
||||
|
||||
/**
|
||||
* PTS file measurement database
|
||||
*/
|
||||
static pts_database_t *pts_db;
|
||||
|
||||
/**
|
||||
* PTS credentials
|
||||
*/
|
||||
static pts_creds_t *pts_creds;
|
||||
|
||||
/**
|
||||
* PTS credential manager
|
||||
*/
|
||||
static credential_manager_t *pts_credmgr;
|
||||
|
||||
/**
|
||||
* see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
|
||||
TNC_Version min_version,
|
||||
TNC_Version max_version,
|
||||
TNC_Version *actual_version)
|
||||
{
|
||||
char *hash_alg, *dh_group, *uri, *cadir;
|
||||
|
||||
if (imv_attestation)
|
||||
{
|
||||
DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
|
||||
return TNC_RESULT_ALREADY_INITIALIZED;
|
||||
}
|
||||
if (!pts_meas_algo_probe(&supported_algorithms) ||
|
||||
!pts_dh_group_probe(&supported_dh_groups))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
if (!pts_probe_dh_groups(&supported_dh_groups))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
|
||||
imv_id, actual_version);
|
||||
if (!imv_attestation)
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
|
||||
libpts_init();
|
||||
|
||||
if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
|
||||
{
|
||||
DBG1(DBG_IMV, "no common IF-IMV version");
|
||||
return TNC_RESULT_NO_COMMON_VERSION;
|
||||
}
|
||||
|
||||
hash_alg = lib->settings->get_str(lib->settings,
|
||||
"libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
|
||||
dh_group = lib->settings->get_str(lib->settings,
|
||||
"libimcv.plugins.imv-attestation.dh_group", "ecp256");
|
||||
|
||||
if (!pts_meas_algo_update(hash_alg, &supported_algorithms) ||
|
||||
!pts_dh_group_update(dh_group, &supported_dh_groups))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify supported PTS Diffie-Hellman groups
|
||||
*
|
||||
* modp1024: PTS_DH_GROUP_IKE2
|
||||
* modp1536: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5
|
||||
* modp2048: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14
|
||||
* ecp256: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
|
||||
* PTS_DH_GROUP_IKE19
|
||||
* ecp384: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
|
||||
* PTS_DH_GROUP_IKE19 | PTS_DH_GROUP_IKE20
|
||||
*
|
||||
* we expect the PTS-IMC to select the strongest supported group
|
||||
*/
|
||||
dh_group = lib->settings->get_str(lib->settings,
|
||||
"libimcv.plugins.imv-attestation.dh_group", "ecp256");
|
||||
|
||||
if (!pts_meas_algo_update(hash_alg, &supported_algorithms) ||
|
||||
!pts_dh_group_update(dh_group, &supported_dh_groups))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
|
||||
/* create a PTS credential manager */
|
||||
pts_credmgr = credential_manager_create();
|
||||
|
||||
/* create PTS credential set */
|
||||
cadir = lib->settings->get_str(lib->settings,
|
||||
"libimcv.plugins.imv-attestation.cadir", NULL);
|
||||
pts_creds = pts_creds_create(cadir);
|
||||
if (pts_creds)
|
||||
{
|
||||
pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds));
|
||||
}
|
||||
|
||||
/* attach file measurement database */
|
||||
uri = lib->settings->get_str(lib->settings,
|
||||
"libimcv.plugins.imv-attestation.database", NULL);
|
||||
pts_db = pts_database_create(uri);
|
||||
|
||||
return TNC_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
|
||||
TNC_ConnectionID connection_id,
|
||||
TNC_ConnectionState new_state)
|
||||
{
|
||||
imv_state_t *state;
|
||||
|
||||
if (!imv_attestation)
|
||||
{
|
||||
DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
switch (new_state)
|
||||
{
|
||||
case TNC_CONNECTION_STATE_CREATE:
|
||||
state = imv_attestation_state_create(connection_id);
|
||||
return imv_attestation->create_state(imv_attestation, state);
|
||||
case TNC_CONNECTION_STATE_DELETE:
|
||||
return imv_attestation->delete_state(imv_attestation, connection_id);
|
||||
case TNC_CONNECTION_STATE_HANDSHAKE:
|
||||
default:
|
||||
return imv_attestation->change_state(imv_attestation, connection_id,
|
||||
new_state, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static TNC_Result send_message(TNC_ConnectionID connection_id)
|
||||
{
|
||||
pa_tnc_msg_t *msg;
|
||||
imv_state_t *state;
|
||||
imv_attestation_state_t *attestation_state;
|
||||
TNC_Result result;
|
||||
|
||||
if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
attestation_state = (imv_attestation_state_t*)state;
|
||||
msg = pa_tnc_msg_create();
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (imv_attestation_build(msg, attestation_state, supported_algorithms,
|
||||
supported_dh_groups, pts_db))
|
||||
{
|
||||
msg->build(msg);
|
||||
result = imv_attestation->send_message(imv_attestation, connection_id,
|
||||
msg->get_encoding(msg));
|
||||
=======
|
||||
if (handshake_state == IMV_ATTESTATION_STATE_NONCE_REQ &&
|
||||
!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T))
|
||||
{
|
||||
DBG1(DBG_IMV, "PTS-IMC has no TPM capability - "
|
||||
"advancing to PTS measurement phase");
|
||||
handshake_state = IMV_ATTESTATION_STATE_MEAS;
|
||||
>>>>>>> added the IMV_ATTESTATION_STATE_NONCE_REQ state
|
||||
}
|
||||
else
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
result = TNC_RESULT_FATAL;
|
||||
=======
|
||||
case IMV_ATTESTATION_STATE_INIT:
|
||||
{
|
||||
pts_proto_caps_flag_t flags;
|
||||
|
||||
/* 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);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
/* Send Measurement Algorithms attribute */
|
||||
attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_NONCE_REQ);
|
||||
break;
|
||||
}
|
||||
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,
|
||||
"libimcv.plugins.imv-attestation.min_nonce_len", 0);
|
||||
attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
|
||||
supported_dh_groups);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(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;
|
||||
|
||||
/* 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);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
/* Send Get TPM Version attribute */
|
||||
attr = tcg_pts_attr_get_tpm_version_info_create();
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
/* Send Get AIK attribute */
|
||||
attr = tcg_pts_attr_get_aik_create();
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_MEAS);
|
||||
break;
|
||||
}
|
||||
case IMV_ATTESTATION_STATE_MEAS:
|
||||
{
|
||||
|
||||
enumerator_t *enumerator;
|
||||
u_int32_t delimiter = SOLIDUS_UTF;
|
||||
char *platform_info, *pathname;
|
||||
u_int16_t request_id;
|
||||
int id, type;
|
||||
bool is_dir;
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_COMP_EVID);
|
||||
|
||||
/* Get Platform and OS of the PTS-IMC */
|
||||
platform_info = pts->get_platform_info(pts);
|
||||
|
||||
if (!pts_db || !platform_info)
|
||||
{
|
||||
DBG1(DBG_IMV, "%s%s%s not available",
|
||||
(pts_db) ? "" : "pts database",
|
||||
(!pts_db && !platform_info) ? "and" : "",
|
||||
(platform_info) ? "" : "platform info");
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_IMV, "platform is '%s'", platform_info);
|
||||
|
||||
/* Send Request File Metadata attribute */
|
||||
attr = tcg_pts_attr_req_file_meta_create(FALSE, SOLIDUS_UTF, "/etc/tnc_config");
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
/* Send Request File Measurement attribute */
|
||||
enumerator = pts_db->create_file_enumerator(pts_db, platform_info);
|
||||
if (!enumerator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (enumerator->enumerate(enumerator, &id, &type, &pathname))
|
||||
{
|
||||
is_dir = (type != 0);
|
||||
request_id = attestation_state->add_request(attestation_state,
|
||||
id, is_dir);
|
||||
DBG2(DBG_IMV, "measurement request %d for %s '%s'",
|
||||
request_id, is_dir ? "directory" : "file", pathname);
|
||||
attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
|
||||
delimiter, pathname);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
break;
|
||||
}
|
||||
case IMV_ATTESTATION_STATE_COMP_EVID:
|
||||
{
|
||||
pts_attr_req_funct_comp_evid_flag_t flags;
|
||||
u_int32_t sub_comp_depth;
|
||||
pts_qualifier_t qualifier;
|
||||
pts_funct_comp_name_t name;
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_END);
|
||||
|
||||
flags = PTS_REQ_FUNC_COMP_FLAG_PCR;
|
||||
sub_comp_depth = 0;
|
||||
qualifier.kernel = FALSE;
|
||||
qualifier.sub_component = FALSE;
|
||||
qualifier.type = PTS_FUNC_COMP_TYPE_ALL;
|
||||
name = PTS_FUNC_COMP_NAME_BIOS;
|
||||
|
||||
/* Send Request Functional Component Evidence attribute */
|
||||
attr = tcg_pts_attr_req_funct_comp_evid_create(flags, sub_comp_depth,
|
||||
PEN_TCG, qualifier, name);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
/* Send Generate Attestation Evidence attribute */
|
||||
attr = tcg_pts_attr_gen_attest_evid_create();
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
|
||||
handshake_state);
|
||||
return TNC_RESULT_FATAL;
|
||||
>>>>>>> added the IMV_ATTESTATION_STATE_NONCE_REQ state
|
||||
}
|
||||
msg->destroy(msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
|
||||
TNC_ConnectionID connection_id,
|
||||
TNC_BufferReference msg,
|
||||
TNC_UInt32 msg_len,
|
||||
TNC_MessageType msg_type)
|
||||
{
|
||||
pa_tnc_msg_t *pa_tnc_msg;
|
||||
pa_tnc_attr_t *attr;
|
||||
linked_list_t *attr_list;
|
||||
imv_state_t *state;
|
||||
imv_attestation_state_t *attestation_state;
|
||||
pts_t *pts;
|
||||
enumerator_t *enumerator;
|
||||
TNC_Result result;
|
||||
|
||||
if (!imv_attestation)
|
||||
{
|
||||
DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
/* get current IMV state */
|
||||
if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
attestation_state = (imv_attestation_state_t*)state;
|
||||
pts = attestation_state->get_pts(attestation_state);
|
||||
|
||||
/* parse received PA-TNC message and automatically handle any errors */
|
||||
result = imv_attestation->receive_message(imv_attestation, connection_id,
|
||||
chunk_create(msg, msg_len), msg_type,
|
||||
&pa_tnc_msg);
|
||||
|
||||
/* no parsed PA-TNC attributes available if an error occurred */
|
||||
if (!pa_tnc_msg)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
attr_list = linked_list_create();
|
||||
result = TNC_RESULT_SUCCESS;
|
||||
|
||||
/* analyze PA-TNC attributes */
|
||||
enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
|
||||
while (enumerator->enumerate(enumerator, &attr))
|
||||
{
|
||||
if (attr->get_vendor_id(attr) == PEN_IETF)
|
||||
{
|
||||
if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
|
||||
{
|
||||
ietf_attr_pa_tnc_error_t *error_attr;
|
||||
pen_t error_vendor_id;
|
||||
pa_tnc_error_code_t error_code;
|
||||
chunk_t msg_info, attr_info;
|
||||
u_int32_t offset;
|
||||
|
||||
error_attr = (ietf_attr_pa_tnc_error_t*)attr;
|
||||
error_vendor_id = error_attr->get_vendor_id(error_attr);
|
||||
error_code = error_attr->get_error_code(error_attr);
|
||||
msg_info = error_attr->get_msg_info(error_attr);
|
||||
|
||||
if (error_vendor_id == PEN_IETF)
|
||||
{
|
||||
DBG1(DBG_IMV, "received PA-TNC error '%N' "
|
||||
"concerning message %#B",
|
||||
pa_tnc_error_code_names, error_code, &msg_info);
|
||||
|
||||
switch (error_code)
|
||||
{
|
||||
case PA_ERROR_INVALID_PARAMETER:
|
||||
offset = error_attr->get_offset(error_attr);
|
||||
DBG1(DBG_IMV, " occurred at offset of %u bytes",
|
||||
offset);
|
||||
break;
|
||||
case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
|
||||
attr_info = error_attr->get_attr_info(error_attr);
|
||||
DBG1(DBG_IMV, " unsupported attribute %#B",
|
||||
&attr_info);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (error_vendor_id == PEN_TCG)
|
||||
{
|
||||
DBG1(DBG_IMV, "received TCG-PTS error '%N'",
|
||||
pts_error_code_names, error_code);
|
||||
DBG1(DBG_IMV, "error information: %B", &msg_info);
|
||||
}
|
||||
result = TNC_RESULT_FATAL;
|
||||
}
|
||||
else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION)
|
||||
{
|
||||
ietf_attr_product_info_t *attr_cast;
|
||||
char *platform_info;
|
||||
|
||||
attr_cast = (ietf_attr_product_info_t*)attr;
|
||||
platform_info = attr_cast->get_info(attr_cast, NULL, NULL);
|
||||
pts->set_platform_info(pts, platform_info);
|
||||
}
|
||||
}
|
||||
else if (attr->get_vendor_id(attr) == PEN_TCG)
|
||||
{
|
||||
if (!imv_attestation_process(attr, attr_list, attestation_state,
|
||||
supported_algorithms,supported_dh_groups, pts_db, pts_credmgr))
|
||||
{
|
||||
result = TNC_RESULT_FATAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
pa_tnc_msg->destroy(pa_tnc_msg);
|
||||
|
||||
if (result != TNC_RESULT_SUCCESS)
|
||||
{
|
||||
attr_list->destroy(attr_list);
|
||||
state->set_recommendation(state,
|
||||
TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
|
||||
TNC_IMV_EVALUATION_RESULT_ERROR);
|
||||
return imv_attestation->provide_recommendation(imv_attestation,
|
||||
connection_id);
|
||||
}
|
||||
|
||||
if (attr_list->get_count(attr_list))
|
||||
{
|
||||
pa_tnc_msg = pa_tnc_msg_create();
|
||||
|
||||
enumerator = attr_list->create_enumerator(attr_list);
|
||||
while (enumerator->enumerate(enumerator, &attr))
|
||||
{
|
||||
pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
pa_tnc_msg->build(pa_tnc_msg);
|
||||
result = imv_attestation->send_message(imv_attestation, connection_id,
|
||||
pa_tnc_msg->get_encoding(pa_tnc_msg));
|
||||
|
||||
pa_tnc_msg->destroy(pa_tnc_msg);
|
||||
attr_list->destroy(attr_list);
|
||||
|
||||
return result;
|
||||
}
|
||||
attr_list->destroy(attr_list);
|
||||
|
||||
if (attestation_state->get_handshake_state(attestation_state) ==
|
||||
IMV_ATTESTATION_STATE_END)
|
||||
{
|
||||
if (attestation_state->get_file_meas_request_count(attestation_state))
|
||||
{
|
||||
DBG1(DBG_IMV, "failure due to %d pending file measurements",
|
||||
attestation_state->get_file_meas_request_count(attestation_state));
|
||||
attestation_state->set_measurement_error(attestation_state);
|
||||
}
|
||||
if (attestation_state->get_component_count(attestation_state))
|
||||
{
|
||||
DBG1(DBG_IMV, "failure due to %d components waiting for evidence",
|
||||
attestation_state->get_component_count(attestation_state));
|
||||
attestation_state->set_measurement_error(attestation_state);
|
||||
}
|
||||
if (attestation_state->get_measurement_error(attestation_state))
|
||||
{
|
||||
state->set_recommendation(state,
|
||||
TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
|
||||
TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->set_recommendation(state,
|
||||
TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
|
||||
TNC_IMV_EVALUATION_RESULT_COMPLIANT);
|
||||
}
|
||||
return imv_attestation->provide_recommendation(imv_attestation,
|
||||
connection_id);
|
||||
}
|
||||
|
||||
return send_message(connection_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
|
||||
TNC_ConnectionID connection_id)
|
||||
{
|
||||
if (!imv_attestation)
|
||||
{
|
||||
DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
return imv_attestation->provide_recommendation(imv_attestation,
|
||||
connection_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
|
||||
TNC_ConnectionID connection_id)
|
||||
{
|
||||
imv_state_t *state;
|
||||
imv_attestation_state_t *attestation_state;
|
||||
|
||||
if (!imv_attestation)
|
||||
{
|
||||
DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
/* get current IMV state */
|
||||
if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
|
||||
{
|
||||
return TNC_RESULT_FATAL;
|
||||
}
|
||||
attestation_state = (imv_attestation_state_t*)state;
|
||||
|
||||
/* Check if IMV has to initiate the PA-TNC exchange */
|
||||
if (attestation_state->get_handshake_state(attestation_state) ==
|
||||
IMV_ATTESTATION_STATE_INIT)
|
||||
{
|
||||
return send_message(connection_id);
|
||||
}
|
||||
return TNC_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
|
||||
{
|
||||
if (!imv_attestation)
|
||||
{
|
||||
DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
if (pts_creds)
|
||||
{
|
||||
pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
|
||||
pts_creds->destroy(pts_creds);
|
||||
}
|
||||
DESTROY_IF(pts_db);
|
||||
DESTROY_IF(pts_credmgr);
|
||||
|
||||
libpts_deinit();
|
||||
|
||||
imv_attestation->destroy(imv_attestation);
|
||||
imv_attestation = NULL;
|
||||
|
||||
return TNC_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
|
||||
*/
|
||||
TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
|
||||
TNC_TNCS_BindFunctionPointer bind_function)
|
||||
{
|
||||
if (!imv_attestation)
|
||||
{
|
||||
DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
|
||||
return TNC_RESULT_NOT_INITIALIZED;
|
||||
}
|
||||
return imv_attestation->bind_functions(imv_attestation, bind_function);
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Sansar Choinyambuu
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "imv_attestation_build.h"
|
||||
#include "imv_attestation_state.h"
|
||||
|
||||
#include <libpts.h>
|
||||
#include <tcg/tcg_pts_attr_proto_caps.h>
|
||||
#include <tcg/tcg_pts_attr_meas_algo.h>
|
||||
#include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
|
||||
#include <tcg/tcg_pts_attr_dh_nonce_finish.h>
|
||||
#include <tcg/tcg_pts_attr_get_tpm_version_info.h>
|
||||
#include <tcg/tcg_pts_attr_get_aik.h>
|
||||
#include <tcg/tcg_pts_attr_req_func_comp_evid.h>
|
||||
#include <tcg/tcg_pts_attr_gen_attest_evid.h>
|
||||
#include <tcg/tcg_pts_attr_req_file_meas.h>
|
||||
#include <tcg/tcg_pts_attr_req_file_meta.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
bool imv_attestation_build(pa_tnc_msg_t *msg,
|
||||
imv_attestation_state_t *attestation_state,
|
||||
pts_meas_algorithms_t supported_algorithms,
|
||||
pts_dh_group_t supported_dh_groups,
|
||||
pts_database_t *pts_db)
|
||||
{
|
||||
imv_attestation_handshake_state_t handshake_state;
|
||||
pts_t *pts;
|
||||
pa_tnc_attr_t *attr = NULL;
|
||||
|
||||
handshake_state = attestation_state->get_handshake_state(attestation_state);
|
||||
pts = attestation_state->get_pts(attestation_state);
|
||||
|
||||
/* D-H attributes are redundant */
|
||||
/* when D-H Nonce Exchange is not selected on IMC side */
|
||||
if (handshake_state == IMV_ATTESTATION_STATE_NONCE_REQ &&
|
||||
!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
|
||||
{
|
||||
DBG1(DBG_IMV, "PTS-IMC is not using Diffie-Hellman Nonce negotiation,"
|
||||
"advancing to TPM Initialization phase");
|
||||
handshake_state = IMV_ATTESTATION_STATE_TPM_INIT;
|
||||
}
|
||||
/* TPM Version Info, AIK attributes are redundant */
|
||||
/* when TPM is not available on IMC side */
|
||||
if (handshake_state == IMV_ATTESTATION_STATE_TPM_INIT &&
|
||||
!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T))
|
||||
{
|
||||
DBG1(DBG_IMV, "PTS-IMC has not got TPM available,"
|
||||
"advancing to File Measurement phase");
|
||||
handshake_state = IMV_ATTESTATION_STATE_MEAS;
|
||||
}
|
||||
/* Component Measurement cannot be done without D-H Nonce Exchange */
|
||||
/* or TPM on IMC side */
|
||||
if (handshake_state == IMV_ATTESTATION_STATE_COMP_EVID &&
|
||||
(!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T) ||
|
||||
!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D)) )
|
||||
{
|
||||
DBG1(DBG_IMV, "PTS-IMC has not got TPM available,"
|
||||
"skipping Component Measurement phase");
|
||||
handshake_state = IMV_ATTESTATION_STATE_END;
|
||||
}
|
||||
|
||||
/* Switch on the attribute type IMV has received */
|
||||
switch (handshake_state)
|
||||
{
|
||||
case IMV_ATTESTATION_STATE_INIT:
|
||||
{
|
||||
pts_proto_caps_flag_t flags;
|
||||
|
||||
/* 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);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
/* Send Measurement Algorithms attribute */
|
||||
attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_NONCE_REQ);
|
||||
break;
|
||||
}
|
||||
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,
|
||||
"libimcv.plugins.imv-attestation.min_nonce_len", 0);
|
||||
attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
|
||||
supported_dh_groups);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(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 ((pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
|
||||
{
|
||||
/* 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);
|
||||
msg->add_attribute(msg, attr);
|
||||
}
|
||||
|
||||
/* Send Get TPM Version attribute */
|
||||
attr = tcg_pts_attr_get_tpm_version_info_create();
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
/* Send Get AIK attribute */
|
||||
attr = tcg_pts_attr_get_aik_create();
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_MEAS);
|
||||
break;
|
||||
}
|
||||
case IMV_ATTESTATION_STATE_MEAS:
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
u_int32_t delimiter = SOLIDUS_UTF;
|
||||
char *platform_info, *pathname;
|
||||
u_int16_t request_id;
|
||||
int id, type;
|
||||
bool is_dir;
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_COMP_EVID);
|
||||
|
||||
/* Get Platform and OS of the PTS-IMC */
|
||||
platform_info = pts->get_platform_info(pts);
|
||||
|
||||
if (!pts_db || !platform_info)
|
||||
{
|
||||
DBG1(DBG_IMV, "%s%s%s not available",
|
||||
(pts_db) ? "" : "pts database",
|
||||
(!pts_db && !platform_info) ? "and" : "",
|
||||
(platform_info) ? "" : "platform info");
|
||||
break;
|
||||
}
|
||||
DBG1(DBG_IMV, "platform is '%s'", platform_info);
|
||||
|
||||
/* Send Request File Metadata attribute */
|
||||
enumerator = pts_db->create_file_meta_enumerator(pts_db,
|
||||
platform_info);
|
||||
if (!enumerator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (enumerator->enumerate(enumerator, &type, &pathname))
|
||||
{
|
||||
is_dir = (type != 0);
|
||||
DBG2(DBG_IMV, "metadata request for %s '%s'",
|
||||
is_dir ? "directory" : "file", pathname);
|
||||
attr = tcg_pts_attr_req_file_meta_create(is_dir, delimiter,
|
||||
pathname);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
/* Send Request File Measurement attribute */
|
||||
enumerator = pts_db->create_file_meas_enumerator(pts_db,
|
||||
platform_info);
|
||||
if (!enumerator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (enumerator->enumerate(enumerator, &id, &type, &pathname))
|
||||
{
|
||||
is_dir = (type != 0);
|
||||
request_id = attestation_state->add_file_meas_request(
|
||||
attestation_state, id, is_dir);
|
||||
DBG2(DBG_IMV, "measurement request %d for %s '%s'",
|
||||
request_id, is_dir ? "directory" : "file", pathname);
|
||||
attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
|
||||
delimiter, pathname);
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
break;
|
||||
}
|
||||
case IMV_ATTESTATION_STATE_COMP_EVID:
|
||||
{
|
||||
tcg_pts_attr_req_func_comp_evid_t *attr_cast;
|
||||
enumerator_t *enumerator;
|
||||
char *platform_info;
|
||||
pts_component_t *comp;
|
||||
pts_comp_func_name_t *comp_name;
|
||||
int vid, name, qualifier;
|
||||
u_int8_t flags;
|
||||
u_int32_t depth;
|
||||
bool first = TRUE;
|
||||
|
||||
attestation_state->set_handshake_state(attestation_state,
|
||||
IMV_ATTESTATION_STATE_END);
|
||||
|
||||
/* Get Platform and OS of the PTS-IMC */
|
||||
platform_info = pts->get_platform_info(pts);
|
||||
if (!pts_db || !platform_info)
|
||||
{
|
||||
DBG1(DBG_IMV, "%s%s%s not available",
|
||||
(pts_db) ? "" : "pts database",
|
||||
(!pts_db && !platform_info) ? "and" : "",
|
||||
(platform_info) ? "" : "platform info");
|
||||
break;
|
||||
}
|
||||
|
||||
enumerator = pts_db->create_comp_evid_enumerator(pts_db, platform_info);
|
||||
if (!enumerator)
|
||||
{
|
||||
break;
|
||||
}
|
||||
DBG2(DBG_IMV, "evidence request by");
|
||||
while (enumerator->enumerate(enumerator, &vid, &name,
|
||||
&qualifier, &depth))
|
||||
{
|
||||
comp_name = pts_comp_func_name_create(vid, name, qualifier);
|
||||
comp_name->log(comp_name, " ");
|
||||
|
||||
comp = pts_components->create(pts_components, comp_name, depth);
|
||||
if (!comp)
|
||||
{
|
||||
DBG2(DBG_IMV, " not registered: removed from request");
|
||||
comp_name->destroy(comp_name);
|
||||
continue;
|
||||
}
|
||||
attestation_state->add_component(attestation_state, comp);
|
||||
if (first)
|
||||
{
|
||||
attr = tcg_pts_attr_req_func_comp_evid_create();
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
first = FALSE;
|
||||
}
|
||||
flags = comp->get_evidence_flags(comp);
|
||||
/* 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, comp_name);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (attr)
|
||||
{
|
||||
/* Send Request Functional Component Evidence attribute */
|
||||
msg->add_attribute(msg, attr);
|
||||
|
||||
/* Send Generate Attestation Evidence attribute */
|
||||
attr = tcg_pts_attr_gen_attest_evid_create();
|
||||
attr->set_noskip_flag(attr, TRUE);
|
||||
msg->add_attribute(msg, attr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
|
||||
handshake_state);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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_build
|
||||
*/
|
||||
|
||||
#ifndef IMV_ATTESTATION_BUILD_H_
|
||||
#define IMV_ATTESTATION_BUILD_H_
|
||||
|
||||
#include "imv_attestation_state.h"
|
||||
|
||||
#include <pa_tnc/pa_tnc_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 msg PA-TNC message to be built
|
||||
* @param attestation_state attestation 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
|
||||
* @return TRUE if successful
|
||||
*/
|
||||
bool imv_attestation_build(pa_tnc_msg_t *msg,
|
||||
imv_attestation_state_t *attestation_state,
|
||||
pts_meas_algorithms_t supported_algorithms,
|
||||
pts_dh_group_t supported_dh_groups,
|
||||
pts_database_t *pts_db);
|
||||
|
||||
#endif /** IMV_ATTESTATION_BUILD_H_ @}*/
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Sansar Choinyambuu
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "imv_attestation_process.h"
|
||||
|
||||
#include <ietf/ietf_attr_pa_tnc_error.h>
|
||||
|
||||
#include <pts/pts.h>
|
||||
|
||||
#include <tcg/tcg_pts_attr_aik.h>
|
||||
#include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
|
||||
#include <tcg/tcg_pts_attr_file_meas.h>
|
||||
#include <tcg/tcg_pts_attr_meas_algo.h>
|
||||
#include <tcg/tcg_pts_attr_proto_caps.h>
|
||||
#include <tcg/tcg_pts_attr_simple_comp_evid.h>
|
||||
#include <tcg/tcg_pts_attr_simple_evid_final.h>
|
||||
#include <tcg/tcg_pts_attr_tpm_version_info.h>
|
||||
#include <tcg/tcg_pts_attr_unix_file_meta.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
|
||||
imv_attestation_state_t *attestation_state,
|
||||
pts_meas_algorithms_t supported_algorithms,
|
||||
pts_dh_group_t supported_dh_groups,
|
||||
pts_database_t *pts_db,
|
||||
credential_manager_t *pts_credmgr)
|
||||
{
|
||||
pts_t *pts;
|
||||
|
||||
pts = attestation_state->get_pts(attestation_state);
|
||||
|
||||
switch (attr->get_type(attr))
|
||||
{
|
||||
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);
|
||||
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,
|
||||
"libimcv.plugins.imv-attestation.min_nonce_len", 0);
|
||||
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);
|
||||
attr_list->insert_last(attr_list, 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);
|
||||
attr_list->insert_last(attr_list, 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;
|
||||
}
|
||||
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;
|
||||
enumerator_t *e;
|
||||
bool trusted = FALSE;
|
||||
|
||||
attr_cast = (tcg_pts_attr_aik_t*)attr;
|
||||
aik = attr_cast->get_aik(attr_cast);
|
||||
if (!aik)
|
||||
{
|
||||
DBG1(DBG_IMV, "AIK unavailable");
|
||||
return FALSE;
|
||||
}
|
||||
if (aik->get_type(aik) == CERT_X509)
|
||||
{
|
||||
DBG1(DBG_IMV, "verifying AIK certificate");
|
||||
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))
|
||||
{
|
||||
trusted = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e->destroy(e);
|
||||
DBG1(DBG_IMV, "AIK certificate is %strusted",
|
||||
trusted ? "" : "not ");
|
||||
}
|
||||
pts->set_aik(pts, aik);
|
||||
break;
|
||||
}
|
||||
case TCG_PTS_FILE_MEAS:
|
||||
{
|
||||
tcg_pts_attr_file_meas_t *attr_cast;
|
||||
u_int16_t request_id;
|
||||
int file_count, file_id;
|
||||
pts_meas_algorithms_t algo;
|
||||
pts_file_meas_t *measurements;
|
||||
char *platform_info;
|
||||
enumerator_t *e_hash;
|
||||
bool is_dir;
|
||||
|
||||
platform_info = pts->get_platform_info(pts);
|
||||
if (!pts_db || !platform_info)
|
||||
{
|
||||
DBG1(DBG_IMV, "%s%s%s not available",
|
||||
(pts_db) ? "" : "pts database",
|
||||
(!pts_db && !platform_info) ? "and" : "",
|
||||
(platform_info) ? "" : "platform info");
|
||||
break;
|
||||
}
|
||||
|
||||
attr_cast = (tcg_pts_attr_file_meas_t*)attr;
|
||||
measurements = attr_cast->get_measurements(attr_cast);
|
||||
algo = pts->get_meas_algorithm(pts);
|
||||
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 (!attestation_state->check_off_file_meas_request(attestation_state,
|
||||
request_id, &file_id, &is_dir))
|
||||
{
|
||||
DBG1(DBG_IMV, " no entry found for file measurement request %d",
|
||||
request_id);
|
||||
break;
|
||||
}
|
||||
|
||||
/* check hashes from database against measurements */
|
||||
e_hash = pts_db->create_file_hash_enumerator(pts_db,
|
||||
platform_info, algo, file_id, is_dir);
|
||||
if (!measurements->verify(measurements, e_hash, is_dir))
|
||||
{
|
||||
attestation_state->set_measurement_error(attestation_state);
|
||||
}
|
||||
e_hash->destroy(e_hash);
|
||||
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;
|
||||
u_int32_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->check_off_component(attestation_state, name);
|
||||
if (!comp)
|
||||
{
|
||||
DBG1(DBG_IMV, " no entry found for component evidence request");
|
||||
break;
|
||||
}
|
||||
status = comp->verify(comp, pts, pts_db, evidence);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
default:
|
||||
case FAILED:
|
||||
attestation_state->set_measurement_error(attestation_state);
|
||||
/* fall through to next case */
|
||||
case SUCCESS:
|
||||
comp->destroy(comp);
|
||||
break;
|
||||
case NEED_MORE:
|
||||
/* re-enter component into list */
|
||||
attestation_state->add_component(attestation_state, comp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TCG_PTS_SIMPLE_EVID_FINAL:
|
||||
{
|
||||
tcg_pts_attr_simple_evid_final_t *attr_cast;
|
||||
u_int8_t flags;
|
||||
pts_meas_algorithms_t comp_hash_algorithm;
|
||||
chunk_t pcr_comp, tpm_quote_sig, evid_sig;
|
||||
chunk_t pcr_composite, quote_info;
|
||||
bool use_quote2, use_ver_info;
|
||||
|
||||
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");
|
||||
free(pcr_composite.ptr);
|
||||
free(quote_info.ptr);
|
||||
return FALSE;
|
||||
}
|
||||
DBG2(DBG_IMV, "received PCR Composite matches constructed one");
|
||||
free(pcr_composite.ptr);
|
||||
|
||||
if (!pts->verify_quote_signature(pts, quote_info, tpm_quote_sig))
|
||||
{
|
||||
free(quote_info.ptr);
|
||||
return FALSE;
|
||||
}
|
||||
DBG2(DBG_IMV, "TPM Quote Info signature verification successful");
|
||||
free(quote_info.ptr);
|
||||
}
|
||||
|
||||
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_process
|
||||
*/
|
||||
|
||||
#ifndef IMV_ATTESTATION_PROCESS_H_
|
||||
#define IMV_ATTESTATION_PROCESS_H_
|
||||
|
||||
#include "imv_attestation_state.h"
|
||||
|
||||
#include <library.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <credentials/credential_manager.h>
|
||||
#include <crypto/hashers/hasher.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 attr_list list with PA-TNC error attributes
|
||||
* @param attestation_state attestation 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, linked_list_t *attr_list,
|
||||
imv_attestation_state_t *attestation_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,356 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Sansar Choinyambuu
|
||||
* HSR Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "imv_attestation_state.h"
|
||||
|
||||
#include <utils/lexparser.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <debug.h>
|
||||
|
||||
typedef struct private_imv_attestation_state_t private_imv_attestation_state_t;
|
||||
typedef struct file_meas_request_t file_meas_request_t;
|
||||
|
||||
/**
|
||||
* PTS File/Directory Measurement request entry
|
||||
*/
|
||||
struct file_meas_request_t {
|
||||
u_int16_t id;
|
||||
int file_id;
|
||||
bool is_dir;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* File Measurement Request counter
|
||||
*/
|
||||
u_int16_t file_meas_request_counter;
|
||||
|
||||
/**
|
||||
* List of PTS File/Directory Measurement requests
|
||||
*/
|
||||
linked_list_t *file_meas_requests;
|
||||
|
||||
/**
|
||||
* List of Functional Components
|
||||
*/
|
||||
linked_list_t *components;
|
||||
|
||||
/**
|
||||
* PTS object
|
||||
*/
|
||||
pts_t *pts;
|
||||
|
||||
/**
|
||||
* Measurement error
|
||||
*/
|
||||
bool measurement_error;
|
||||
|
||||
};
|
||||
|
||||
typedef struct entry_t entry_t;
|
||||
|
||||
/**
|
||||
* Define an internal reason string entry
|
||||
*/
|
||||
struct entry_t {
|
||||
char *lang;
|
||||
char *string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Table of multi-lingual reason string entries
|
||||
*/
|
||||
static entry_t reasons[] = {
|
||||
{ "en", "IMV Attestation: Incorrect/pending file measurement/component"
|
||||
" evidence or invalid TPM Quote signature received" },
|
||||
{ "mn", "IMV Attestation: Буруу/хүлээгдэж байгаа файл/компонент хэмжилт "
|
||||
"эсвэл буруу TPM Quote гарын үсэг" },
|
||||
{ "de", "IMV Attestation: Falsche/Fehlende Dateimessung/Komponenten Beweis "
|
||||
"oder ungültige TPM Quote Unterschrift ist erhalten" },
|
||||
};
|
||||
|
||||
METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
|
||||
private_imv_attestation_state_t *this)
|
||||
{
|
||||
return this->connection_id;
|
||||
}
|
||||
|
||||
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, get_reason_string, bool,
|
||||
private_imv_attestation_state_t *this, chunk_t preferred_language,
|
||||
chunk_t *reason_string, chunk_t *reason_language)
|
||||
{
|
||||
chunk_t pref_lang, lang;
|
||||
u_char *pos;
|
||||
int i;
|
||||
|
||||
while (eat_whitespace(&preferred_language))
|
||||
{
|
||||
if (!extract_token(&pref_lang, ',', &preferred_language))
|
||||
{
|
||||
/* last entry in a comma-separated list or single entry */
|
||||
pref_lang = preferred_language;
|
||||
}
|
||||
|
||||
/* eat trailing whitespace */
|
||||
pos = pref_lang.ptr + pref_lang.len - 1;
|
||||
while (pref_lang.len && *pos-- == ' ')
|
||||
{
|
||||
pref_lang.len--;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < countof(reasons); i++)
|
||||
{
|
||||
lang = chunk_create(reasons[i].lang, strlen(reasons[i].lang));
|
||||
if (chunk_equals(lang, pref_lang))
|
||||
{
|
||||
*reason_language = lang;
|
||||
*reason_string = chunk_create(reasons[i].string,
|
||||
strlen(reasons[i].string));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* no preferred language match found - use the default language */
|
||||
*reason_string = chunk_create(reasons[0].string,
|
||||
strlen(reasons[0].string));
|
||||
*reason_language = chunk_create(reasons[0].lang,
|
||||
strlen(reasons[0].lang));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(imv_state_t, destroy, void,
|
||||
private_imv_attestation_state_t *this)
|
||||
{
|
||||
this->file_meas_requests->destroy_function(this->file_meas_requests, free);
|
||||
this->components->destroy_offset(this->components,
|
||||
offsetof(pts_component_t, destroy));
|
||||
this->pts->destroy(this->pts);
|
||||
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, add_file_meas_request, u_int16_t,
|
||||
private_imv_attestation_state_t *this, int file_id, bool is_dir)
|
||||
{
|
||||
file_meas_request_t *request;
|
||||
|
||||
request = malloc_thing(file_meas_request_t);
|
||||
request->id = ++this->file_meas_request_counter;
|
||||
request->file_id = file_id;
|
||||
request->is_dir = is_dir;
|
||||
this->file_meas_requests->insert_last(this->file_meas_requests, request);
|
||||
|
||||
return this->file_meas_request_counter;
|
||||
}
|
||||
|
||||
METHOD(imv_attestation_state_t, check_off_file_meas_request, bool,
|
||||
private_imv_attestation_state_t *this, u_int16_t id, int *file_id,
|
||||
bool* is_dir)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
file_meas_request_t *request;
|
||||
bool found = FALSE;
|
||||
|
||||
enumerator = this->file_meas_requests->create_enumerator(this->file_meas_requests);
|
||||
while (enumerator->enumerate(enumerator, &request))
|
||||
{
|
||||
if (request->id == id)
|
||||
{
|
||||
found = TRUE;
|
||||
*file_id = request->file_id;
|
||||
*is_dir = request->is_dir;
|
||||
this->file_meas_requests->remove_at(this->file_meas_requests, enumerator);
|
||||
free(request);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return found;
|
||||
}
|
||||
|
||||
METHOD(imv_attestation_state_t, get_file_meas_request_count, int,
|
||||
private_imv_attestation_state_t *this)
|
||||
{
|
||||
return this->file_meas_requests->get_count(this->file_meas_requests);
|
||||
}
|
||||
|
||||
METHOD(imv_attestation_state_t, add_component, void,
|
||||
private_imv_attestation_state_t *this, pts_component_t *entry)
|
||||
{
|
||||
this->components->insert_last(this->components, entry);
|
||||
}
|
||||
|
||||
METHOD(imv_attestation_state_t, check_off_component, pts_component_t*,
|
||||
private_imv_attestation_state_t *this, pts_comp_func_name_t *name)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
pts_component_t *entry, *found = NULL;
|
||||
|
||||
enumerator = this->components->create_enumerator(this->components);
|
||||
while (enumerator->enumerate(enumerator, &entry))
|
||||
{
|
||||
if (name->equals(name, entry->get_comp_func_name(entry)))
|
||||
{
|
||||
found = entry;
|
||||
this->components->remove_at(this->components, enumerator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return found;
|
||||
}
|
||||
|
||||
METHOD(imv_attestation_state_t, get_component_count, int,
|
||||
private_imv_attestation_state_t *this)
|
||||
{
|
||||
return this->components->get_count(this->components);
|
||||
}
|
||||
|
||||
METHOD(imv_attestation_state_t, get_measurement_error, bool,
|
||||
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)
|
||||
{
|
||||
this->measurement_error = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Described in header.
|
||||
*/
|
||||
imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
|
||||
{
|
||||
private_imv_attestation_state_t *this;
|
||||
char *platform_info;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.interface = {
|
||||
.get_connection_id = _get_connection_id,
|
||||
.change_state = _change_state,
|
||||
.get_recommendation = _get_recommendation,
|
||||
.set_recommendation = _set_recommendation,
|
||||
.get_reason_string = _get_reason_string,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.get_handshake_state = _get_handshake_state,
|
||||
.set_handshake_state = _set_handshake_state,
|
||||
.get_pts = _get_pts,
|
||||
.add_file_meas_request = _add_file_meas_request,
|
||||
.check_off_file_meas_request = _check_off_file_meas_request,
|
||||
.get_file_meas_request_count = _get_file_meas_request_count,
|
||||
.add_component = _add_component,
|
||||
.check_off_component = _check_off_component,
|
||||
.get_component_count = _get_component_count,
|
||||
.get_measurement_error = _get_measurement_error,
|
||||
.set_measurement_error = _set_measurement_error,
|
||||
},
|
||||
.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,
|
||||
.file_meas_requests = linked_list_create(),
|
||||
.components = linked_list_create(),
|
||||
.pts = pts_create(FALSE),
|
||||
);
|
||||
|
||||
platform_info = lib->settings->get_str(lib->settings,
|
||||
"libimcv.plugins.imv-attestation.platform_info", NULL);
|
||||
if (platform_info)
|
||||
{
|
||||
this->pts->set_platform_info(this->pts, platform_info);
|
||||
}
|
||||
|
||||
return &this->public.interface;
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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_state_t imv_attestation_state
|
||||
* @{ @ingroup imv_attestation_state
|
||||
*/
|
||||
|
||||
#ifndef IMV_ATTESTATION_STATE_H_
|
||||
#define IMV_ATTESTATION_STATE_H_
|
||||
|
||||
#include <imv/imv_state.h>
|
||||
#include <pts/pts.h>
|
||||
#include <library.h>
|
||||
|
||||
typedef struct imv_attestation_state_t imv_attestation_state_t;
|
||||
typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t;
|
||||
|
||||
/**
|
||||
* IMV Attestation Handshake States (state machine)
|
||||
*/
|
||||
enum imv_attestation_handshake_state_t {
|
||||
IMV_ATTESTATION_STATE_INIT,
|
||||
IMV_ATTESTATION_STATE_NONCE_REQ,
|
||||
IMV_ATTESTATION_STATE_TPM_INIT,
|
||||
IMV_ATTESTATION_STATE_MEAS,
|
||||
IMV_ATTESTATION_STATE_COMP_EVID,
|
||||
IMV_ATTESTATION_STATE_END,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Add an entry to the list of pending file/directory measurement requests
|
||||
*
|
||||
* @param file_id primary key into file table
|
||||
* @param is_dir TRUE if directory
|
||||
* @return unique request ID
|
||||
*/
|
||||
u_int16_t (*add_file_meas_request)(imv_attestation_state_t *this,
|
||||
int file_id, bool is_dir);
|
||||
|
||||
/**
|
||||
* Returns the number of pending file/directory measurement requests
|
||||
*
|
||||
* @return number of pending requests
|
||||
*/
|
||||
int (*get_file_meas_request_count)(imv_attestation_state_t *this);
|
||||
|
||||
/**
|
||||
* Check for presence of request_id and if found remove it from the list
|
||||
*
|
||||
* @param id unique request ID
|
||||
* @param file_id primary key into file table
|
||||
* @param is_dir return TRUE if request was for a directory
|
||||
* @return TRUE if request ID found, FALSE otherwise
|
||||
*/
|
||||
bool (*check_off_file_meas_request)(imv_attestation_state_t *this,
|
||||
u_int16_t id, int *file_id, bool *is_dir);
|
||||
|
||||
/**
|
||||
* Add an entry to the list of Functional Components waiting for evidence
|
||||
*
|
||||
* @param entry Functional Component
|
||||
*/
|
||||
void (*add_component)(imv_attestation_state_t *this, pts_component_t *entry);
|
||||
|
||||
/**
|
||||
* Returns the number of Functional Component waiting for evidence
|
||||
*
|
||||
* @return Number of waiting Functional Components
|
||||
*/
|
||||
int (*get_component_count)(imv_attestation_state_t *this);
|
||||
|
||||
/**
|
||||
* Check for presence of Functional Component and remove and return it
|
||||
*
|
||||
* @param name Name of the requested Functional Component
|
||||
* @return Functional Component if found, NULL otherwise
|
||||
*/
|
||||
pts_component_t* (*check_off_component)(imv_attestation_state_t *this,
|
||||
pts_comp_func_name_t *name);
|
||||
|
||||
/**
|
||||
* Indicates if a file measurement error occurred
|
||||
*
|
||||
* @return TRUE in case of measurement error
|
||||
*/
|
||||
bool (*get_measurement_error)(imv_attestation_state_t *this);
|
||||
|
||||
/**
|
||||
* Call if a file measurement error is encountered
|
||||
*/
|
||||
void (*set_measurement_error)(imv_attestation_state_t *this);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 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,55 @@
|
||||
/* PTS SQLite database */
|
||||
|
||||
DROP TABLE IF EXISTS files;
|
||||
CREATE TABLE files (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
type INTEGER NOT NULL,
|
||||
path TEXT NOT NULL
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS components;
|
||||
CREATE TABLE components (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
vendor_id INTEGER NOT NULL,
|
||||
name INTEGER NOT NULL,
|
||||
qualifier INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS products;
|
||||
CREATE TABLE products (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
DROP INDEX IF EXISTS products_name;
|
||||
CREATE INDEX products_name ON products (
|
||||
name
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS product_file;
|
||||
CREATE TABLE product_file (
|
||||
product INTEGER NOT NULL,
|
||||
file INTEGER NOT NULL,
|
||||
measurement INTEGER DEFAULT 0,
|
||||
metadata INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (product, file)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS product_component;
|
||||
CREATE TABLE product_component (
|
||||
product INTEGER NOT NULL,
|
||||
component INTEGER NOT NULL,
|
||||
depth INTEGER DEFAULT 0,
|
||||
sequence INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (product, component)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS file_hashes;
|
||||
CREATE TABLE file_hashes (
|
||||
file INTEGER NOT NULL,
|
||||
directory INTEGER DEFAULT 0,
|
||||
product INTEGER NOT NULL,
|
||||
component INTEGER DEFAULT 0,
|
||||
algo INTEGER NOT NULL,
|
||||
hash BLOB NOT NULL,
|
||||
PRIMARY KEY(file, directory, product, component, algo)
|
||||
);
|
||||
Reference in New Issue
Block a user