777 lines
22 KiB
C
777 lines
22 KiB
C
/*
|
|
* 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/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_database.h>
|
|
#include <pts/pts_creds.h>
|
|
#include <pts/pts_error.h>
|
|
|
|
#include <tcg/tcg_attr.h>
|
|
#include <tcg/tcg_pts_attr_proto_caps.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_meas_algo.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_funct_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 <tncif_pa_subtypes.h>
|
|
|
|
#include <pen/pen.h>
|
|
#include <debug.h>
|
|
#include <credentials/credential_manager.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 = 0;
|
|
|
|
/**
|
|
* 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, *uri, *cadir;
|
|
|
|
if (imv_attestation)
|
|
{
|
|
DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
|
|
return TNC_RESULT_ALREADY_INITIALIZED;
|
|
}
|
|
if (!pts_meas_probe_algorithms(&supported_algorithms))
|
|
{
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Specify supported PTS measurement algorithms
|
|
*
|
|
* sha1 : PTS_MEAS_ALGO_SHA1
|
|
* sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
|
|
* sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
|
|
*
|
|
* we expect the PTS-IMC to select the strongest supported algorithm
|
|
*/
|
|
hash_alg = lib->settings->get_str(lib->settings,
|
|
"libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
|
|
if (!strcaseeq(hash_alg, "sha384") && !strcaseeq(hash_alg, "sha2_384"))
|
|
{
|
|
/* remove SHA384 algorithm */
|
|
supported_algorithms &= ~PTS_MEAS_ALGO_SHA384;
|
|
}
|
|
if (strcaseeq(hash_alg, "sha1"))
|
|
{
|
|
/* remove SHA256 algorithm */
|
|
supported_algorithms &= ~PTS_MEAS_ALGO_SHA256;
|
|
}
|
|
|
|
/* 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;
|
|
imv_attestation_state_t *attestation_state;
|
|
TNC_Result result;
|
|
|
|
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:
|
|
result = imv_attestation->change_state(imv_attestation, connection_id,
|
|
new_state, &state);
|
|
if (result != TNC_RESULT_SUCCESS)
|
|
{
|
|
return result;
|
|
}
|
|
attestation_state = (imv_attestation_state_t*)state;
|
|
|
|
/* TODO: Get some configurations */
|
|
|
|
return TNC_RESULT_SUCCESS;
|
|
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;
|
|
pa_tnc_attr_t *attr;
|
|
pts_t *pts;
|
|
imv_state_t *state;
|
|
imv_attestation_state_t *attestation_state;
|
|
imv_attestation_handshake_state_t handshake_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;
|
|
handshake_state = attestation_state->get_handshake_state(attestation_state);
|
|
pts = attestation_state->get_pts(attestation_state);
|
|
|
|
msg = pa_tnc_msg_create();
|
|
|
|
|
|
/* 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_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);
|
|
|
|
/* Does the PTS-IMC have TPM support? */
|
|
if (pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T)
|
|
{
|
|
/* 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);
|
|
}
|
|
|
|
/* 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 = 1;
|
|
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;
|
|
}
|
|
case IMV_ATTESTATION_STATE_IML:
|
|
DBG1(DBG_IMV, "Attestation IMV has nothing to send: \"%s\"",
|
|
handshake_state);
|
|
return TNC_RESULT_FATAL;
|
|
default:
|
|
DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
|
|
handshake_state);
|
|
return TNC_RESULT_FATAL;
|
|
}
|
|
|
|
msg->build(msg);
|
|
result = imv_attestation->send_message(imv_attestation, connection_id,
|
|
msg->get_encoding(msg));
|
|
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;
|
|
imv_state_t *state;
|
|
imv_attestation_state_t *attestation_state;
|
|
pts_t *pts;
|
|
enumerator_t *enumerator;
|
|
TNC_Result result;
|
|
bool fatal_error = FALSE;
|
|
bool measurement_error = FALSE;
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
fatal_error = TRUE;
|
|
}
|
|
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)
|
|
{
|
|
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);
|
|
pts->set_meas_algorithm(pts, selected_algorithm);
|
|
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)
|
|
{
|
|
/* TODO generate error attribute */
|
|
break;
|
|
}
|
|
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;
|
|
}
|
|
|
|
/* PTS-based Attestation Evidence */
|
|
case TCG_PTS_SIMPLE_COMP_EVID:
|
|
{
|
|
/** TODO: Implement saving the PCR number, Hash Algo = communicated one,
|
|
* PCR transform (truncate SHA256, SHA384), PCR before and after values
|
|
*/
|
|
break;
|
|
}
|
|
|
|
case TCG_PTS_SIMPLE_EVID_FINAL:
|
|
{
|
|
/** TODO: Implement construct Quote structure over saved values from
|
|
* TCG_PTS_SIMPLE_COMP_EVID and compare with received one
|
|
*/
|
|
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)
|
|
{
|
|
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_request(attestation_state,
|
|
request_id, &file_id, &is_dir))
|
|
{
|
|
DBG1(DBG_IMV, " no entry found for this request");
|
|
break;
|
|
}
|
|
|
|
/* check hashes from database against measurements */
|
|
e_hash = pts_db->create_hash_enumerator(pts_db,
|
|
platform_info, algo, file_id, is_dir);
|
|
if (!measurements->verify(measurements, e_hash, is_dir))
|
|
{
|
|
measurement_error = TRUE;
|
|
}
|
|
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;
|
|
enumerator_t *e;
|
|
pts_file_metadata_t *entry;
|
|
|
|
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, "File name: %s", entry->filename);
|
|
DBG1(DBG_IMV, " type: %d", entry->type);
|
|
DBG1(DBG_IMV, " size: %d", entry->filesize);
|
|
DBG1(DBG_IMV, " create time: %s", ctime(&entry->create_time));
|
|
DBG1(DBG_IMV, " last modified: %s", ctime(&entry->last_modify_time));
|
|
DBG1(DBG_IMV, " last accessed: %s", ctime(&entry->last_access_time));
|
|
DBG1(DBG_IMV, " owner id: %d", entry->owner_id);
|
|
DBG1(DBG_IMV, " group id: %d", entry->group_id);
|
|
}
|
|
|
|
e->destroy(e);
|
|
|
|
break;
|
|
}
|
|
|
|
/* TODO: Not implemented yet */
|
|
case TCG_PTS_DH_NONCE_PARAMS_RESP:
|
|
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_FUNCT_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;
|
|
}
|
|
}
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
pa_tnc_msg->destroy(pa_tnc_msg);
|
|
|
|
|
|
if (fatal_error)
|
|
{
|
|
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 (attestation_state->get_handshake_state(attestation_state) &
|
|
IMV_ATTESTATION_STATE_END)
|
|
{
|
|
if (attestation_state->get_request_count(attestation_state))
|
|
{
|
|
DBG1(DBG_IMV, "failure due to %d pending file measurements",
|
|
attestation_state->get_request_count(attestation_state));
|
|
measurement_error = TRUE;
|
|
}
|
|
if (measurement_error)
|
|
{
|
|
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);
|
|
}
|