libimcv: Support symlinks introduced by usrmerge

Debian, Ubuntu, Fedora et. al. started to apply usrmerge to their
latest Linux distributions, i.e.  /bin, /sbin, and /lib are now
symbolical links to /usr/bin, /usr/sbin, and /usr/lib, respectively.
Since executables and libraries are contained only once in Linux
packages (e.g. /bin/cp in coreutils but not /usr/bin/cp) this leads
to missing file measurments due to the symlinks when doing remote
attestation.

The new ita_attr_symlinks PA-TNC attribute fixes this problem by
collecting symbolic links pointing to directories on the client
platform.
This commit is contained in:
Andreas Steffen 2020-12-30 10:16:57 +01:00
parent 9b4a2322d6
commit 2ea1dac203
14 changed files with 944 additions and 54 deletions

View File

@ -42,6 +42,7 @@ libimcv_la_SOURCES := \
ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
ita/ita_attr_settings.h ita/ita_attr_settings.c \
ita/ita_attr_angel.h ita/ita_attr_angel.c \
ita/ita_attr_symlinks.h ita/ita_attr_symlinks.c \
os_info/os_info.h os_info/os_info.c \
pa_tnc/pa_tnc_attr.h \
pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
@ -60,6 +61,7 @@ libimcv_la_SOURCES := \
pts/pts_ima_bios_list.h pts/pts_ima_bios_list.c \
pts/pts_ima_event_list.h pts/pts_ima_event_list.c \
pts/pts_meas_algo.h pts/pts_meas_algo.c \
pts/pts_symlinks.h pts/pts_symlinks.c \
pts/components/pts_component.h \
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \

View File

@ -63,6 +63,7 @@ libimcv_la_SOURCES = \
ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
ita/ita_attr_settings.h ita/ita_attr_settings.c \
ita/ita_attr_angel.h ita/ita_attr_angel.c \
ita/ita_attr_symlinks.h ita/ita_attr_symlinks.c \
os_info/os_info.h os_info/os_info.c \
pa_tnc/pa_tnc_attr.h \
pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
@ -81,6 +82,7 @@ libimcv_la_SOURCES = \
pts/pts_ima_bios_list.h pts/pts_ima_bios_list.c \
pts/pts_ima_event_list.h pts/pts_ima_event_list.c \
pts/pts_meas_algo.h pts/pts_meas_algo.c \
pts/pts_symlinks.h pts/pts_symlinks.c \
pts/components/pts_component.h \
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2020 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@ -19,9 +19,10 @@
#include "ita/ita_attr_get_settings.h"
#include "ita/ita_attr_settings.h"
#include "ita/ita_attr_angel.h"
#include "ita/ita_attr_symlinks.h"
#include "generic/generic_attr_string.h"
ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_DEVICE_ID,
ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_SYMLINKS,
"Command",
"Dummy",
"Get Settings",
@ -29,7 +30,9 @@ ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_DEVICE_ID,
"Start Angel",
"Stop Angel",
"Echo",
"Device ID"
"Device ID",
"Get Symlinks",
"Symlinks"
);
/**
@ -55,6 +58,11 @@ pa_tnc_attr_t* ita_attr_create_from_data(uint32_t type, size_t length,
case ITA_ATTR_DEVICE_ID:
return generic_attr_string_create_from_data(length, value,
pen_type_create(PEN_ITA, type));
case ITA_ATTR_GET_SYMLINKS:
return generic_attr_string_create_from_data(length, value,
pen_type_create(PEN_ITA, type));
case ITA_ATTR_SYMLINKS:
return ita_attr_symlinks_create_from_data(length, value);
default:
return NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2020 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@ -38,7 +38,9 @@ enum ita_attr_t {
ITA_ATTR_START_ANGEL = 5,
ITA_ATTR_STOP_ANGEL = 6,
ITA_ATTR_ECHO = 7,
ITA_ATTR_DEVICE_ID = 8
ITA_ATTR_DEVICE_ID = 8,
ITA_ATTR_GET_SYMLINKS = 9,
ITA_ATTR_SYMLINKS = 10
};
/**

View File

@ -0,0 +1,318 @@
/*
* Copyright (C) 2020 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 "ita_attr_symlinks.h"
#include <pa_tnc/pa_tnc_msg.h>
#include <bio/bio_writer.h>
#include <bio/bio_reader.h>
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_ita_attr_symlinks_t private_ita_attr_symlinks_t;
/**
* List of Symbolic Links pointing to Directories
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Number of Symlinks |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Symlink #1 Length | Symlink #1 Path (Var Len) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Symlink #1 Path (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Directory #1 Length | Directory #1 Path (Var Len) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Directory #1 Path (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Symlink #2 Length | Symlink #2 Path (Var Len) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Symlink #2 Path (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Directory #2 Length | Directory #2 Path (Var Len) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Directory #2 Path (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ...........................
*/
#define ITA_ATTR_SYMLINKS_SIZE 4
/**
* Private data of an ita_attr_symlinks_t object.
*/
struct private_ita_attr_symlinks_t {
/**
* Public members of ita_attr_symlinks_t
*/
ita_attr_symlinks_t public;
/**
* Vendor-specific attribute type
*/
pen_type_t type;
/**
* Length of attribute value
*/
size_t length;
/**
* Offset up to which attribute value has been processed
*/
size_t offset;
/**
* Current position of attribute value pointer
*/
chunk_t value;
/**
* Contains complete attribute or current segment
*/
chunk_t segment;
/**
* Noskip flag
*/
bool noskip_flag;
/**
* Number of symbolic link entries
*/
uint32_t count;
/**
* List of symbolic links
*/
pts_symlinks_t *symlinks;
/**
* Reference count
*/
refcount_t ref;
};
METHOD(pa_tnc_attr_t, get_type, pen_type_t,
private_ita_attr_symlinks_t *this)
{
return this->type;
}
METHOD(pa_tnc_attr_t, get_value, chunk_t,
private_ita_attr_symlinks_t *this)
{
return this->value;
}
METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
private_ita_attr_symlinks_t *this)
{
return this->noskip_flag;
}
METHOD(pa_tnc_attr_t, set_noskip_flag,void,
private_ita_attr_symlinks_t *this, bool noskip)
{
this->noskip_flag = noskip;
}
METHOD(pa_tnc_attr_t, build, void,
private_ita_attr_symlinks_t *this)
{
bio_writer_t *writer;
enumerator_t *enumerator;
chunk_t symlink, dir;
if (this->value.ptr)
{
return;
}
this->count = this->symlinks->get_count(this->symlinks);
writer = bio_writer_create(ITA_ATTR_SYMLINKS_SIZE);
writer->write_uint32(writer, this->count);
enumerator = this->symlinks->create_enumerator(this->symlinks);
while (enumerator->enumerate(enumerator, &symlink, &dir))
{
writer->write_data16(writer, symlink);
writer->write_data16(writer, dir);
}
enumerator->destroy(enumerator);
this->value = writer->extract_buf(writer);
this->segment = this->value;
this->length = this->value.len;
writer->destroy(writer);
}
METHOD(pa_tnc_attr_t, process, status_t,
private_ita_attr_symlinks_t *this, uint32_t *offset)
{
bio_reader_t *reader;
chunk_t symlink, dir;
status_t status = NEED_MORE;
if (this->offset == 0)
{
if (this->length < ITA_ATTR_SYMLINKS_SIZE)
{
DBG1(DBG_TNC, "insufficient data for %N/%N", pen_names, PEN_ITA,
ita_attr_names, this->type.type);
*offset = this->offset;
return FAILED;
}
if (this->value.len < ITA_ATTR_SYMLINKS_SIZE)
{
return NEED_MORE;
}
reader = bio_reader_create(this->value);
reader->read_uint32(reader, &this->count);
this->offset = ITA_ATTR_SYMLINKS_SIZE;
this->value = reader->peek(reader);
reader->destroy(reader);
}
this->symlinks = pts_symlinks_create();
reader = bio_reader_create(this->value);
while (this->count)
{
if (!reader->read_data16(reader, &symlink) ||
!reader->read_data16(reader, &dir))
{
goto end;
}
this->offset += this->value.len - reader->remaining(reader);
this->value = reader->peek(reader);
this->symlinks->add(this->symlinks, symlink, dir);
this->count--;
}
status = SUCCESS;
if (this->length != this->offset)
{
DBG1(DBG_TNC, "inconsistent length for %N/%N", pen_names, PEN_ITA,
ita_attr_names, this->type.type);
*offset = this->offset;
status = FAILED;
}
end:
reader->destroy(reader);
return status;
}
METHOD(pa_tnc_attr_t, add_segment, void,
private_ita_attr_symlinks_t *this, chunk_t segment)
{
this->value = chunk_cat("cc", this->value, segment);
chunk_free(&this->segment);
this->segment = this->value;
}
METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
private_ita_attr_symlinks_t *this)
{
ref_get(&this->ref);
return &this->public.pa_tnc_attribute;
}
METHOD(pa_tnc_attr_t, destroy, void,
private_ita_attr_symlinks_t *this)
{
if (ref_put(&this->ref))
{
DESTROY_IF(this->symlinks);
free(this->segment.ptr);
free(this);
}
}
METHOD(ita_attr_symlinks_t, get_symlinks, pts_symlinks_t*,
private_ita_attr_symlinks_t *this)
{
return this->symlinks;
}
/**
* Described in header.
*/
pa_tnc_attr_t *ita_attr_symlinks_create(pts_symlinks_t *symlinks)
{
private_ita_attr_symlinks_t *this;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_symlinks = _get_symlinks,
},
.type = { PEN_ITA, ITA_ATTR_SYMLINKS },
.symlinks = symlinks->get_ref(symlinks),
.ref = 1,
);
return &this->public.pa_tnc_attribute;
}
/**
* Described in header.
*/
pa_tnc_attr_t *ita_attr_symlinks_create_from_data(size_t length, chunk_t data)
{
private_ita_attr_symlinks_t *this;
INIT(this,
.public = {
.pa_tnc_attribute = {
.get_type = _get_type,
.get_value = _get_value,
.get_noskip_flag = _get_noskip_flag,
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
.add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.get_symlinks = _get_symlinks,
},
.type = { PEN_ITA, ITA_ATTR_SYMLINKS },
.length = length,
.segment = chunk_clone(data),
.ref = 1,
);
/* received either complete attribute value or first segment */
this->value = this->segment;
return &this->public.pa_tnc_attribute;
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 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 ita_attr_sysmlinks ita_attr_sysmlinks
* @{ @ingroup ita_attr
*/
#ifndef ITA_ATTR_SYMLINKS_H_
#define ITA_ATTR_SYMLINKS_H_
typedef struct ita_attr_symlinks_t ita_attr_symlinks_t;
#include "ita/ita_attr.h"
#include "pa_tnc/pa_tnc_attr.h"
#include "pts/pts_symlinks.h"
/**
* Class implementing the ITA Symlinks attribute
*
*/
struct ita_attr_symlinks_t {
/**
* Public PA-TNC attribute interface
*/
pa_tnc_attr_t pa_tnc_attribute;
/**
* Get list of symbolic links
*
* @return List of symbolic links pointing to directories
*/
pts_symlinks_t* (*get_symlinks)(ita_attr_symlinks_t *this);
};
/**
* Creates an ita_attr_sysmlinks_t object
*/
pa_tnc_attr_t* ita_attr_symlinks_create(pts_symlinks_t *symlinks);
/**
* Creates an ita_attr_sysmlinks_t object from received data
*
* @param length Total length of attribute value
* @param value Unparsed attribute value (might be a segment)
*/
pa_tnc_attr_t* ita_attr_symlinks_create_from_data(size_t length, chunk_t value);
#endif /** ITA_ATTR_SYMLINKS_H_ @}*/

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2020 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@ -24,6 +24,7 @@
#include <ietf/ietf_attr_product_info.h>
#include <ietf/ietf_attr_string_version.h>
#include <ietf/ietf_attr_assess_result.h>
#include <ita/ita_attr_symlinks.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <os_info/os_info.h>
@ -200,6 +201,25 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
break;
}
}
else if (type.vendor_id == PEN_ITA)
{
if (type.type == ITA_ATTR_GET_SYMLINKS)
{
pts_symlinks_t *symlinks;
chunk_t dir;
pts_t *pts;
dir = attr->get_value(attr);
attestation_state = (imc_attestation_state_t*)state;
pts = attestation_state->get_pts(attestation_state);
symlinks = pts->extract_symlinks(pts, dir);
if (symlinks)
{
attr = ita_attr_symlinks_create(symlinks);
out_msg->add_attribute(out_msg, attr);
}
}
}
}
enumerator->destroy(enumerator);

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2015 Andreas Steffen
* Copyright (C) 2011-2020 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@ -34,6 +34,7 @@
#include <ietf/ietf_attr_product_info.h>
#include <ietf/ietf_attr_string_version.h>
#include <ita/ita_attr.h>
#include <ita/ita_attr_symlinks.h>
#include <tcg/tcg_attr.h>
#include <tcg/pts/tcg_pts_attr_meas_algo.h>
#include <tcg/pts/tcg_pts_attr_proto_caps.h>
@ -44,6 +45,7 @@
#include <pts/pts.h>
#include <pts/pts_database.h>
#include <pts/pts_creds.h>
#include <pts/pts_symlinks.h>
#include <pts/components/ita/ita_comp_func_name.h>
#include <tncif_pa_subtypes.h>
@ -287,6 +289,20 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
session->set_device_id(session, value);
break;
}
case ITA_ATTR_SYMLINKS:
{
imv_attestation_state_t *attestation_state;
ita_attr_symlinks_t *attr_cast;
pts_symlinks_t *symlinks;
pts_t *pts;
attr_cast = (ita_attr_symlinks_t*)attr;
symlinks = attr_cast->get_symlinks(attr_cast);
attestation_state = (imv_attestation_state_t*)state;
pts = attestation_state->get_pts(attestation_state);
pts->set_symlinks(pts, symlinks);
break;
}
default:
break;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2011-2012 Sansar Choinyambuu
* Copyright (C) 2011-2014 Andreas Steffen
* Copyright (C) 2011-2020 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@ -23,6 +23,8 @@
#include <tcg/pts/tcg_pts_attr_get_aik.h>
#include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
#include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
#include <generic/generic_attr_string.h>
#include <ita/ita_attr.h>
#include <utils/debug.h>
@ -138,6 +140,11 @@ bool imv_attestation_build(imv_msg_t *out_msg, imv_state_t *state,
if (attr)
{
/* Send Get Symlinks attribute */
out_msg->add_attribute(out_msg, generic_attr_string_create(
chunk_from_str("/"),
pen_type_create(PEN_ITA, ITA_ATTR_GET_SYMLINKS)));
/* Send Request Functional Component Evidence attribute */
out_msg->add_attribute(out_msg, attr);

View File

@ -13,6 +13,9 @@
* for more details.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "ita_comp_ima.h"
#include "ita_comp_func_name.h"
@ -497,6 +500,123 @@ static pts_meas_algorithms_t parse_validation_uri(pts_comp_evidence_t *evidence,
return hash_algo;
}
/**
* Look up all hashes for a given file and OS in the database and check
* if one of them matches the IMA measurement
*/
static status_t verify_ima_measuremnt(pts_t *pts, pts_database_t *pts_db,
pts_meas_algorithms_t hash_algo,
pts_meas_algorithms_t algo,
bool pcr_padding, chunk_t measurement,
char* ima_algo, char* ima_name,
char *filename)
{
status_t status = NOT_FOUND;
pts_meas_algorithms_t meas_algo;
uint8_t *hex_digest_buf;
uint8_t digest_buf[HASH_SIZE_SHA512];
uint8_t hash_buf[HASH_SIZE_SHA512];
size_t hash_size;
chunk_t hash, digest, hex_digest;
enumerator_t *e;
hash_size = pts_meas_algo_hash_size(algo);
hash = chunk_create(hash_buf, hash_size);
if (pcr_padding)
{
memset(hash_buf, 0x00, hash_size);
meas_algo = PTS_MEAS_ALGO_SHA1;
}
else
{
meas_algo = algo;
}
e = pts_db->create_file_meas_enumerator(pts_db, pts->get_platform_id(pts),
hash_algo, filename);
if (!e)
{
return FAILED;
}
while (e->enumerate(e, &hex_digest_buf))
{
hex_digest = chunk_from_str(hex_digest_buf);
digest = chunk_from_hex(hex_digest, digest_buf);
if (!pts_ima_event_hash(digest, ima_algo, ima_name, meas_algo, hash_buf))
{
status = FAILED;
break;
}
if (chunk_equals_const(measurement, hash))
{
status = SUCCESS;
break;
}
else
{
status = VERIFY_ERROR;
}
}
e->destroy(e);
return status;
}
/**
* Generate an alternative pathname based on symbolic link info
*/
static char* alternative_pathname(pts_t * pts, char *path)
{
pts_symlinks_t *symlinks;
enumerator_t *enumerator;
chunk_t prefix1, prefix2;
char *alt_path = NULL;
size_t path_len = strlen(path);
int ret;
symlinks = pts->get_symlinks(pts);
if (!symlinks || symlinks->get_count(symlinks) == 0)
{
return NULL;
}
enumerator = symlinks->create_enumerator(symlinks);
while (enumerator->enumerate(enumerator, &prefix1, &prefix2))
{
/* replace prefix2 by prefix1*/
if (path_len > prefix2.len && path[prefix2.len] == '/' &&
memeq(path, prefix2.ptr, prefix2.len))
{
ret = asprintf(&alt_path, "%.*s%s", (int)prefix1.len, prefix1.ptr,
path + prefix2.len);
if (ret <= 0)
{
alt_path = NULL;
}
break;
}
/* replace prefix1 by prefix2 */
if (path_len > prefix1.len && path[prefix1.len] == '/' &&
memeq(path, prefix1.ptr, prefix1.len))
{
ret = asprintf(&alt_path, "%.*s%s", (int)prefix2.len, prefix2.ptr,
path + prefix1.len);
if (ret <= 0)
{
alt_path = NULL;
}
break;
}
}
enumerator->destroy(enumerator);
return alt_path;
}
METHOD(pts_component_t, verify, status_t,
pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
pts_comp_evidence_t *evidence)
@ -665,14 +785,8 @@ METHOD(pts_component_t, verify, status_t,
break;
case IMA_STATE_RUNTIME:
{
chunk_t hex_digest, digest, hash;
uint8_t digest_buf[HASH_SIZE_SHA512], *hex_digest_buf;
uint8_t hash_buf[HASH_SIZE_SHA512];
size_t hash_size;
pts_meas_algorithms_t meas_algo;
enumerator_t *e;
this->count++;
if (evidence->get_validation(evidence, NULL) !=
PTS_COMP_EVID_VALIDATION_PASSED)
{
@ -680,50 +794,30 @@ METHOD(pts_component_t, verify, status_t,
this->count_failed++;
return FAILED;
}
hash_size = pts_meas_algo_hash_size(algo);
hash = chunk_create(hash_buf, hash_size);
if (this->pcr_padding)
{
memset(hash_buf, 0x00, hash_size);
meas_algo = PTS_MEAS_ALGO_SHA1;
}
else
{
meas_algo = algo;
}
status = verify_ima_measuremnt(pts, this->pts_db,
hash_algo, algo,
this->pcr_padding, measurement,
ima_algo, ima_name, ima_name);
e = this->pts_db->create_file_meas_enumerator(this->pts_db,
pts->get_platform_id(pts),
hash_algo, ima_name);
if (e)
if (status == NOT_FOUND || status == VERIFY_ERROR)
{
while (e->enumerate(e, &hex_digest_buf))
status_t alt_status;
char *alt_path;
alt_path = alternative_pathname(pts, ima_name);
if (alt_path)
{
hex_digest = chunk_from_str(hex_digest_buf);
digest = chunk_from_hex(hex_digest, digest_buf);
if (!pts_ima_event_hash(digest, ima_algo, ima_name,
meas_algo, hash_buf))
alt_status = verify_ima_measuremnt(pts, this->pts_db,
hash_algo, algo,
this->pcr_padding, measurement,
ima_algo, ima_name, alt_path);
if (alt_status != NOT_FOUND)
{
status = FAILED;
break;
}
if (chunk_equals_const(measurement, hash))
{
status = SUCCESS;
break;
}
else
{
status = VERIFY_ERROR;
status = alt_status;
}
free(alt_path);
}
e->destroy(e);
}
else
{
status = FAILED;
}
switch (status)

View File

@ -27,8 +27,10 @@
#include <sys/stat.h>
#include <libgen.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#ifndef TPM_TAG_QUOTE_INFO2
#define TPM_TAG_QUOTE_INFO2 0x0036
#endif
@ -89,6 +91,11 @@ struct private_pts_t {
*/
int platform_id;
/**
* List of directory symlinks received from IMC
*/
pts_symlinks_t *symlinks;
/**
* TRUE if IMC-PTS, FALSE if IMV-PTS
*/
@ -309,6 +316,104 @@ METHOD(pts_t, set_platform_id, void,
this->platform_id = pid;
}
METHOD(pts_t, extract_symlinks, pts_symlinks_t*,
private_pts_t *this, chunk_t pathname)
{
#ifndef WIN32
char path[BUF_LEN], real_path[BUF_LEN];
size_t path_len, real_path_len;
struct dirent *entry;
struct stat st;
DIR *dir;
/* open directory and prepare pathnames */
snprintf(path, BUF_LEN-1, "%.*s", (int)pathname.len, pathname.ptr);
dir = opendir(path);
if (!dir)
{
DBG1(DBG_PTS, "opening directory '%s' failed: %s", path,
strerror(errno));
return NULL;
}
if (pathname.len == 1 && path[0] == '/')
{
path_len = 1;
}
else
{
path[pathname.len] = '/';
path_len = pathname.len + 1;
}
real_path[0] = '/';
/* symlinks object is owned by pts object */
DESTROY_IF(this->symlinks);
this->symlinks = pts_symlinks_create();
while (TRUE)
{
entry = readdir(dir);
if (!entry)
{
/* no more entries -> exit */
break;
}
if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
{
continue;
}
/* assemble absolute path */
snprintf(path + path_len, BUF_LEN - path_len, "%s", entry->d_name);
/* only evaluate symlinks pointing to directories */
if (lstat(path, &st) == -1 || !S_ISLNK(st.st_mode) ||
stat(path, &st) == -1 || !S_ISDIR(st.st_mode))
{
continue;
}
real_path_len = readlink(path, real_path + 1, BUF_LEN - 1);
if (real_path_len <= 0)
{
continue;
}
this->symlinks->add(this->symlinks, chunk_from_str(path),
chunk_create(real_path, 1 + real_path_len));
}
closedir(dir);
#endif
return this->symlinks;
}
METHOD(pts_t, get_symlinks, pts_symlinks_t*,
private_pts_t *this)
{
return this->symlinks;
}
METHOD(pts_t, set_symlinks, void,
private_pts_t *this, pts_symlinks_t *symlinks)
{
enumerator_t *enumerator;
chunk_t symlink, dir;
DESTROY_IF(this->symlinks);
this->symlinks = symlinks->get_ref(symlinks);
DBG2(DBG_PTS, "adding directory symlinks:");
enumerator = symlinks->create_enumerator(symlinks);
while (enumerator->enumerate(enumerator, &symlink, &dir))
{
DBG2(DBG_PTS, " %.*s -> %.*s", (int)symlink.len, symlink.ptr,
(int)dir.len, dir.ptr);
}
enumerator->destroy(enumerator);
}
METHOD(pts_t, get_tpm, tpm_tss_t*,
private_pts_t *this)
{
@ -354,7 +459,7 @@ METHOD(pts_t, set_tpm_version_info, void,
{
DBG2(DBG_PTS, "%s 1.2 rev. %u.%u.%u.%u %.*s", TPM_VERSION_INFO_LABEL,
(uint32_t)major, (uint32_t)minor, (uint32_t)rev_major,
(uint32_t)rev_minor, vendor.len, vendor.ptr);
(uint32_t)rev_minor, (int)vendor.len, vendor.ptr);
}
else
{
@ -377,7 +482,7 @@ METHOD(pts_t, set_tpm_version_info, void,
{
DBG2(DBG_PTS, "%s 2.0 rev. %4.2f %u %.*s - startup locality: %u",
TPM_VERSION_INFO_LABEL, revision/100.0, year,
vendor.len, vendor.ptr, (uint32_t)locality);
(int)vendor.len, vendor.ptr, (uint32_t)locality);
}
else
{
@ -873,6 +978,7 @@ METHOD(pts_t, destroy, void,
DESTROY_IF(this->pcrs);
DESTROY_IF(this->aik_cert);
DESTROY_IF(this->dh);
DESTROY_IF(this->symlinks);
free(this->initiator_nonce.ptr);
free(this->responder_nonce.ptr);
free(this->secret.ptr);
@ -901,6 +1007,9 @@ pts_t *pts_create(bool is_imc)
.calculate_secret = _calculate_secret,
.get_platform_id = _get_platform_id,
.set_platform_id = _set_platform_id,
.extract_symlinks = _extract_symlinks,
.get_symlinks = _get_symlinks,
.set_symlinks = _set_symlinks,
.get_tpm = _get_tpm,
.get_tpm_version_info = _get_tpm_version_info,
.set_tpm_version_info = _set_tpm_version_info,

View File

@ -32,6 +32,7 @@ typedef struct pts_t pts_t;
#include "pts_dh_group.h"
#include "pts_pcr.h"
#include "pts_req_func_comp_evid.h"
#include "pts_symlinks.h"
#include "components/pts_comp_func_name.h"
#include <tpm_tss_quote_info.h>
@ -175,6 +176,29 @@ struct pts_t {
*/
void (*set_platform_id)(pts_t *this, int pid);
/**
* Extract all directory symlinks contained in a directory
*
* @param pathname Absolute pathname of directory
* @return List of directory symlinks
*/
pts_symlinks_t* (*extract_symlinks)(pts_t *this, chunk_t pathname);
/**
* Get list of directory symlinks received from IMC
*
* @return List of symbolic links
*/
pts_symlinks_t* (*get_symlinks)(pts_t *this);
/**
* Set list of directory symlinks received from IMC
*
* @param symlinks List of symbolic links
*/
void (*set_symlinks)(pts_t *this, pts_symlinks_t *symlinks);
/**
* Get TPM object handle
*

View File

@ -0,0 +1,149 @@
/*
* Copyright (C) 2020 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 "pts_symlinks.h"
#include <collections/linked_list.h>
#include <utils/debug.h>
typedef struct private_pts_symlinks_t private_pts_symlinks_t;
typedef struct entry_t entry_t;
/**
* Private data of a pts_symlinks_t object.
*
*/
struct private_pts_symlinks_t {
/**
* Public pts_symlinks_t interface.
*/
pts_symlinks_t public;
/**
* List of symbolic links pointing to directories
*/
linked_list_t *list;
/**
* Reference count
*/
refcount_t ref;
};
/**
* Symlink entry
*/
struct entry_t {
chunk_t symlink;
chunk_t dir;
};
/**
* Free an entry_t object
*/
static void free_entry(entry_t *entry)
{
if (entry)
{
free(entry->symlink.ptr);
free(entry->dir.ptr);
free(entry);
}
}
METHOD(pts_symlinks_t, get_count, int,
private_pts_symlinks_t *this)
{
return this->list->get_count(this->list);
}
METHOD(pts_symlinks_t, add, void,
private_pts_symlinks_t *this, chunk_t symlink, chunk_t dir)
{
entry_t *entry;
entry = malloc_thing(entry_t);
entry->symlink = chunk_clone(symlink);
entry->dir = chunk_clone(dir);
this->list->insert_last(this->list, entry);
}
CALLBACK(symlink_filter, bool,
void *null, enumerator_t *orig, va_list args)
{
entry_t *entry;
chunk_t *symlink;
chunk_t *dir;
VA_ARGS_VGET(args, symlink, dir);
if (orig->enumerate(orig, &entry))
{
*symlink = entry->symlink;
*dir = entry->dir;
return TRUE;
}
return FALSE;
}
METHOD(pts_symlinks_t, create_enumerator, enumerator_t*,
private_pts_symlinks_t *this)
{
return enumerator_create_filter(this->list->create_enumerator(this->list),
symlink_filter, NULL, NULL);
}
METHOD(pts_symlinks_t, get_ref, pts_symlinks_t*,
private_pts_symlinks_t *this)
{
ref_get(&this->ref);
return &this->public;
}
METHOD(pts_symlinks_t, destroy, void,
private_pts_symlinks_t *this)
{
if (ref_put(&this->ref))
{
this->list->destroy_function(this->list, (void *)free_entry);
free(this);
}
}
/**
* See header
*/
pts_symlinks_t *pts_symlinks_create()
{
private_pts_symlinks_t *this;
INIT(this,
.public = {
.get_count = _get_count,
.add = _add,
.create_enumerator = _create_enumerator,
.get_ref = _get_ref,
.destroy = _destroy,
},
.list = linked_list_create(),
.ref = 1,
);
return &this->public;
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2020 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 pts_symlinks pts_symlinks
* @{ @ingroup pts
*/
#ifndef PTS_SYMLINKS_H_
#define PTS_SYMLINKS_H_
#include <library.h>
typedef struct pts_symlinks_t pts_symlinks_t;
/**
* Class storing a list of symbolic links pointing to directories
*/
struct pts_symlinks_t {
/**
* Get the number of symbolic link entries
*
* @return Number of symbolic links
*/
int (*get_count)(pts_symlinks_t *this);
/**
* Add a symbolic link pointing to a directory
*
* @param symlink Pathname of symbolic link
* @param dir Pathname of directory the symlink points to
*/
void (*add)(pts_symlinks_t *this, chunk_t symlink, chunk_t dir);
/**
* Create a symlink enumerator
*
* @return Enumerator returning (chunk_t symlink, chunk_t dir)
*/
enumerator_t* (*create_enumerator)(pts_symlinks_t *this);
/**
* Get a new reference to the list of symbolic links
*
* @return this, with an increased refcount
*/
pts_symlinks_t* (*get_ref)(pts_symlinks_t *this);
/**
* Destroys a pts_symlinks_t object.
*/
void (*destroy)(pts_symlinks_t *this);
};
/**
* Creates a pts_symlinks_t object
*/
pts_symlinks_t* pts_symlinks_create();
#endif /** PTS_SYMLINKS_H_ @}*/