From: Andreas Steffen Date: Wed, 30 Dec 2020 09:16:57 +0000 (+0100) Subject: libimcv: Support symlinks introduced by usrmerge X-Git-Tag: 5.9.2dr1~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ea1dac2030d2367e3d4b7b1314fe0943ff7cd94;p=thirdparty%2Fstrongswan.git 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. --- diff --git a/src/libimcv/Android.mk b/src/libimcv/Android.mk index cde6ce23f9..8549175aac 100644 --- a/src/libimcv/Android.mk +++ b/src/libimcv/Android.mk @@ -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 \ diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index 444de3f425..f44ab52b81 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -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 \ diff --git a/src/libimcv/ita/ita_attr.c b/src/libimcv/ita/ita_attr.c index 1d8db71cbc..788bb775f1 100644 --- a/src/libimcv/ita/ita_attr.c +++ b/src/libimcv/ita/ita_attr.c @@ -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; } diff --git a/src/libimcv/ita/ita_attr.h b/src/libimcv/ita/ita_attr.h index 726537420a..2bd18ce42e 100644 --- a/src/libimcv/ita/ita_attr.h +++ b/src/libimcv/ita/ita_attr.h @@ -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 }; /** diff --git a/src/libimcv/ita/ita_attr_symlinks.c b/src/libimcv/ita/ita_attr_symlinks.c new file mode 100644 index 0000000000..f8c59c972b --- /dev/null +++ b/src/libimcv/ita/ita_attr_symlinks.c @@ -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 . + * + * 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 +#include +#include +#include +#include + +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; +} diff --git a/src/libimcv/ita/ita_attr_symlinks.h b/src/libimcv/ita/ita_attr_symlinks.h new file mode 100644 index 0000000000..458e6f50d2 --- /dev/null +++ b/src/libimcv/ita/ita_attr_symlinks.h @@ -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 . + * + * 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_ @}*/ diff --git a/src/libimcv/plugins/imc_attestation/imc_attestation.c b/src/libimcv/plugins/imc_attestation/imc_attestation.c index f592a51345..c58e5238bc 100644 --- a/src/libimcv/plugins/imc_attestation/imc_attestation.c +++ b/src/libimcv/plugins/imc_attestation/imc_attestation.c @@ -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 #include #include +#include #include #include #include @@ -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); diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c index a1fc6466dc..4d17f1ee45 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_agent.c @@ -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 #include #include +#include #include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include #include @@ -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; } diff --git a/src/libimcv/plugins/imv_attestation/imv_attestation_build.c b/src/libimcv/plugins/imv_attestation/imv_attestation_build.c index ec54ce0cf5..9f30020d9a 100644 --- a/src/libimcv/plugins/imv_attestation/imv_attestation_build.c +++ b/src/libimcv/plugins/imv_attestation/imv_attestation_build.c @@ -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 #include #include +#include +#include #include @@ -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); diff --git a/src/libimcv/pts/components/ita/ita_comp_ima.c b/src/libimcv/pts/components/ita/ita_comp_ima.c index 752aa267dd..b1084e0af6 100644 --- a/src/libimcv/pts/components/ita/ita_comp_ima.c +++ b/src/libimcv/pts/components/ita/ita_comp_ima.c @@ -13,6 +13,9 @@ * for more details. */ +#define _GNU_SOURCE +#include + #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)) - { - hex_digest = chunk_from_str(hex_digest_buf); - digest = chunk_from_hex(hex_digest, digest_buf); + status_t alt_status; + char *alt_path; - 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 + alt_path = alternative_pathname(pts, ima_name); + if (alt_path) + { + 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 = VERIFY_ERROR; + status = alt_status; } + free(alt_path); } - e->destroy(e); - } - else - { - status = FAILED; } switch (status) diff --git a/src/libimcv/pts/pts.c b/src/libimcv/pts/pts.c index a03703dddc..aeeae60759 100644 --- a/src/libimcv/pts/pts.c +++ b/src/libimcv/pts/pts.c @@ -27,8 +27,10 @@ #include #include #include +#include #include + #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, diff --git a/src/libimcv/pts/pts.h b/src/libimcv/pts/pts.h index b9fac0a6e5..b2a3890457 100644 --- a/src/libimcv/pts/pts.h +++ b/src/libimcv/pts/pts.h @@ -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 @@ -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 * diff --git a/src/libimcv/pts/pts_symlinks.c b/src/libimcv/pts/pts_symlinks.c new file mode 100644 index 0000000000..152a8b5903 --- /dev/null +++ b/src/libimcv/pts/pts_symlinks.c @@ -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 . + * + * 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 +#include + +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; +} + diff --git a/src/libimcv/pts/pts_symlinks.h b/src/libimcv/pts/pts_symlinks.h new file mode 100644 index 0000000000..291a7e104e --- /dev/null +++ b/src/libimcv/pts/pts_symlinks.h @@ -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 . + * + * 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 + +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_ @}*/