diff options
author | Romain Francoise <rfrancoise@debian.org> | 2014-10-21 19:28:38 +0200 |
---|---|---|
committer | Romain Francoise <rfrancoise@debian.org> | 2014-10-21 19:41:50 +0200 |
commit | b23b0e5609ed4b3d29396a1727aab035fa4a395f (patch) | |
tree | 091d0b144dd92a0c124b7fbe9eae68f79cb975dc /src/libimcv/pts | |
parent | 4a01a7e2574040cf246fd00ebff173b873c17349 (diff) | |
download | vyos-strongswan-b23b0e5609ed4b3d29396a1727aab035fa4a395f.tar.gz vyos-strongswan-b23b0e5609ed4b3d29396a1727aab035fa4a395f.zip |
Import upstream release 5.2.1
Diffstat (limited to 'src/libimcv/pts')
44 files changed, 8276 insertions, 0 deletions
diff --git a/src/libimcv/pts/components/ita/ita_comp_func_name.c b/src/libimcv/pts/components/ita/ita_comp_func_name.c new file mode 100644 index 000000000..a593281ba --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_func_name.c @@ -0,0 +1,45 @@ +/* + * 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 "ita_comp_func_name.h" + +char pts_ita_qualifier_flag_names[] = { 'K', 'S' }; + +ENUM_BEGIN(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_UNKNOWN, + PTS_ITA_QUALIFIER_TYPE_TNC, + "Unknown", + "Trusted Platform", + "Operating System", + "Graphical User Interface", + "Application", + "Networking", + "Library", + "TNC Defined Component" +); +ENUM_NEXT(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL, + PTS_ITA_QUALIFIER_TYPE_ALL, + PTS_ITA_QUALIFIER_TYPE_TNC, + "All Matching Components" +); +ENUM_END(pts_ita_qualifier_type_names, PTS_ITA_QUALIFIER_TYPE_ALL); + +ENUM(pts_ita_comp_func_names, PTS_ITA_COMP_FUNC_NAME_IGNORE, + PTS_ITA_COMP_FUNC_NAME_IMA, + "Ignore", + "Trusted GRUB Boot Loader", + "Trusted Boot", + "Linux IMA" +); + diff --git a/src/libimcv/pts/components/ita/ita_comp_func_name.h b/src/libimcv/pts/components/ita/ita_comp_func_name.h new file mode 100644 index 000000000..eb2f363f3 --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_func_name.h @@ -0,0 +1,85 @@ +/* + * 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 pts_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_FUNC_NAME_H_ +#define PTS_ITA_COMP_FUNC_NAME_H_ + +typedef enum pts_ita_qualifier_type_t pts_ita_qualifier_type_t; +typedef enum pts_ita_comp_func_name_t pts_ita_comp_func_name_t; + +#include <library.h> + +/** + * PTS Component Functional Name Qualifier Flags for the ITA namespace + */ +#define PTS_ITA_QUALIFIER_FLAG_KERNEL (1<<5) +#define PTS_ITA_QUALIFIER_FLAG_SUB (1<<4) + +extern char pts_ita_qualifier_flag_names[]; + +/** + * Size of the PTS Component Functional Name Qualifier Type field + */ +#define PTS_ITA_QUALIFIER_TYPE_SIZE 4 + +/** + * PTS Component Functional Name Qualifier Types for the ITA namespace + * equal to section 5.2 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_ita_qualifier_type_t { + /** Unknown */ + PTS_ITA_QUALIFIER_TYPE_UNKNOWN = 0x0, + /** Trusted Platform */ + PTS_ITA_QUALIFIER_TYPE_TRUSTED = 0x1, + /** Operating System */ + PTS_ITA_QUALIFIER_TYPE_OS = 0x2, + /** Graphical User Interface */ + PTS_ITA_QUALIFIER_TYPE_GUI = 0x3, + /** Application */ + PTS_ITA_QUALIFIER_TYPE_APP = 0x4, + /** Networking */ + PTS_ITA_QUALIFIER_TYPE_NET = 0x5, + /** Library */ + PTS_ITA_QUALIFIER_TYPE_LIB = 0x6, + /** TNC Defined Component */ + PTS_ITA_QUALIFIER_TYPE_TNC = 0x7, + /** All Matching Components */ + PTS_ITA_QUALIFIER_TYPE_ALL = 0xF, +}; + +extern enum_name_t *pts_ita_qualifier_type_names; + +/** + * PTS Component Functional Name Binary Enumeration for the ITA namespace + */ +enum pts_ita_comp_func_name_t { + /** Ignore */ + PTS_ITA_COMP_FUNC_NAME_IGNORE = 0x0000, + /** Trusted GRUB Boot Loader */ + PTS_ITA_COMP_FUNC_NAME_TGRUB = 0x0001, + /** Trusted Boot */ + PTS_ITA_COMP_FUNC_NAME_TBOOT = 0x0002, + /** Linux Integrity Measurement Architecture */ + PTS_ITA_COMP_FUNC_NAME_IMA = 0x0003, +}; + +extern enum_name_t *pts_ita_comp_func_names; + +#endif /** PTS_ITA_COMP_FUNC_NAME_H_ @}*/ diff --git a/src/libimcv/pts/components/ita/ita_comp_ima.c b/src/libimcv/pts/components/ita/ita_comp_ima.c new file mode 100644 index 000000000..3f92b04b1 --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_ima.c @@ -0,0 +1,914 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ita_comp_ima.h" +#include "ita_comp_func_name.h" + +#include "imcv.h" +#include "pts/pts_pcr.h" +#include "pts/pts_ima_bios_list.h" +#include "pts/pts_ima_event_list.h" +#include "pts/components/pts_component.h" + +#include <utils/debug.h> +#include <crypto/hashers/hasher.h> +#include <pen/pen.h> + +#define SECURITY_DIR "/sys/kernel/security/" +#define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements" +#define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements" +#define IMA_FILENAME_LEN_MAX 255 + +typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t; +typedef enum ima_state_t ima_state_t; + +enum ima_state_t { + IMA_STATE_INIT, + IMA_STATE_BIOS, + IMA_STATE_BOOT_AGGREGATE, + IMA_STATE_RUNTIME, + IMA_STATE_END +}; + +/** + * Private data of a pts_ita_comp_ima_t object. + * + */ +struct pts_ita_comp_ima_t { + + /** + * Public pts_component_t interface. + */ + pts_component_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * Sub-component depth + */ + uint32_t depth; + + /** + * PTS measurement database + */ + pts_database_t *pts_db; + + /** + * Primary key for AIK database entry + */ + int aik_id; + + /** + * Primary key for IMA BIOS Component Functional Name database entry + */ + int bios_cid; + + /** + * Primary key for IMA Runtime Component Functional Name database entry + */ + int ima_cid; + + /** + * Component is registering IMA BIOS measurements + */ + bool is_bios_registering; + + /** + * Component is registering IMA boot aggregate measurement + */ + bool is_ima_registering; + + /** + * Measurement sequence number + */ + int seq_no; + + /** + * Expected IMA BIOS measurement count + */ + int bios_count; + + /** + * IMA BIOS measurements + */ + pts_ima_bios_list_t *bios_list; + + /** + * IMA runtime file measurements + */ + pts_ima_event_list_t *ima_list; + + /** + * Whether to send pcr_before and pcr_after info + */ + bool pcr_info; + + /** + * Creation time of measurement + */ + time_t creation_time; + + /** + * IMA state machine + */ + ima_state_t state; + + /** + * Total number of component measurements + */ + int count; + + /** + * Number of successful component measurements + */ + int count_ok; + + /** + * Number of unknown component measurements + */ + int count_unknown; + + /** + * Number of differing component measurements + */ + int count_differ; + + /** + * Number of failed component measurements + */ + int count_failed; + + /** + * Reference count + */ + refcount_t ref; + +}; + +/** + * Extend measurement into PCR and create evidence + */ +static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, + uint8_t qualifier, pts_pcr_t *pcrs, + uint32_t pcr, chunk_t measurement) +{ + size_t pcr_len; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; + pts_comp_func_name_t *name; + pts_comp_evidence_t *evidence; + chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty; + + hash_algo = PTS_MEAS_ALGO_SHA1; + pcr_len = HASH_SIZE_SHA1; + pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + + if (this->pcr_info) + { + pcr_before = chunk_clone(pcrs->get(pcrs, pcr)); + } + pcr_after = pcrs->extend(pcrs, pcr, measurement); + if (!pcr_after.ptr) + { + free(pcr_before.ptr); + return NULL; + } + name = this->name->clone(this->name); + name->set_qualifier(name, qualifier); + evidence = pts_comp_evidence_create(name, this->depth, pcr, hash_algo, + pcr_transform, this->creation_time, measurement); + if (this->pcr_info) + { + pcr_after =chunk_clone(pcrs->get(pcrs, pcr)); + evidence->set_pcr_info(evidence, pcr_before, pcr_after); + } + return evidence; +} + +/** + * Generate an IMA or IMA-NG hash from an event digest and event name + * + * @param digest event digest + * @param ima_algo hash algorithm string ("sha1:", "sha256:", etc.) + * @param ima_name event name + * @param little_endian endianness of client platform + * @param algo hash algorithm used by TPM + * @param hash_buf hash value to be compared with TPM measurement + */ +static bool ima_hash(chunk_t digest, char *ima_algo, char *ima_name, + bool little_endian, pts_meas_algorithms_t algo, + char *hash_buf) +{ + hash_algorithm_t hash_alg; + hasher_t *hasher; + bool success; + + hash_alg = pts_meas_algo_to_hash(algo); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + if (!hasher) + { + DBG1(DBG_PTS, "%N hasher could not be created", + hash_algorithm_short_names, hash_alg); + return FALSE; + } + + if (ima_algo) + { + uint32_t d_len, n_len; + chunk_t algo_name, event_name, digest_len, name_len; + + /* IMA-NG hash */ + algo_name = chunk_create(ima_algo, strlen(ima_algo) + 1); + event_name = chunk_create(ima_name, strlen(ima_name) + 1); + + d_len = algo_name.len + digest.len; + digest_len = chunk_create((uint8_t*)&d_len, sizeof(d_len)); + /* TODO handle endianness of both client and server platforms */ + + n_len = event_name.len; + name_len = chunk_create((uint8_t*)&n_len, sizeof(n_len)); + /* TODO handle endianness of both client and server platforms */ + + success = hasher->get_hash(hasher, digest_len, NULL) && + hasher->get_hash(hasher, algo_name, NULL) && + hasher->get_hash(hasher, digest, NULL) && + hasher->get_hash(hasher, name_len, NULL) && + hasher->get_hash(hasher, event_name, hash_buf); + } + else + { + u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1]; + chunk_t file_name; + + /* IMA legacy hash */ + memset(filename_buffer, 0, sizeof(filename_buffer)); + strncpy(filename_buffer, ima_name, IMA_FILENAME_LEN_MAX); + file_name = chunk_create (filename_buffer, sizeof(filename_buffer)); + + success = hasher->get_hash(hasher, digest, NULL) && + hasher->get_hash(hasher, file_name, hash_buf); + } + hasher->destroy(hasher); + + return success; +} + +/** + * Compute and check boot aggregate value by hashing PCR0 to PCR7 + */ +static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement, + char *algo) +{ + u_char pcr_buffer[HASH_SIZE_SHA1]; + chunk_t boot_aggregate; + hasher_t *hasher; + uint32_t i; + bool success, pcr_ok = TRUE; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + DBG1(DBG_PTS, "%N hasher could not be created", + hash_algorithm_short_names, HASH_SHA1); + return FALSE; + } + for (i = 0; i < 8 && pcr_ok; i++) + { + pcr_ok = hasher->get_hash(hasher, pcrs->get(pcrs, i), NULL); + } + if (pcr_ok) + { + pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer); + } + hasher->destroy(hasher); + + if (pcr_ok) + { + boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer)); + + /* TODO handle endianness of client platform */ + pcr_ok = ima_hash(boot_aggregate, algo, "boot_aggregate", + TRUE, PTS_MEAS_ALGO_SHA1, pcr_buffer); + } + if (pcr_ok) + { + success = chunk_equals(boot_aggregate, measurement); + DBG1(DBG_PTS, "boot aggregate value is %scorrect", + success ? "":"in"); + return success; + } + else + { + DBG1(DBG_PTS, "failed to compute boot aggregate value"); + return FALSE; + } +} + +METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, + pts_ita_comp_ima_t *this) +{ + return this->name; +} + +METHOD(pts_component_t, get_evidence_flags, uint8_t, + pts_ita_comp_ima_t *this) +{ + return PTS_REQ_FUNC_COMP_EVID_PCR; +} + +METHOD(pts_component_t, get_depth, uint32_t, + pts_ita_comp_ima_t *this) +{ + return this->depth; +} + +METHOD(pts_component_t, measure, status_t, + pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts, + pts_comp_evidence_t **evidence) +{ + pts_pcr_t *pcrs; + pts_comp_evidence_t *evid = NULL; + size_t algo_len, name_len; + chunk_t measurement; + char *uri, *algo, *name; + uint32_t pcr; + status_t status; + + pcrs = pts->get_pcrs(pts); + + if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED)) + { + switch (this->state) + { + case IMA_STATE_INIT: + this->bios_list = pts_ima_bios_list_create( + IMA_BIOS_MEASUREMENTS); + if (!this->bios_list) + { + return FAILED; + } + this->creation_time = this->bios_list->get_time(this->bios_list); + this->bios_count = this->bios_list->get_count(this->bios_list); + this->state = IMA_STATE_BIOS; + /* fall through to next state */ + case IMA_STATE_BIOS: + status = this->bios_list->get_next(this->bios_list, &pcr, + &measurement); + if (status != SUCCESS) + { + DBG1(DBG_PTS, "could not retrieve bios measurement entry"); + return status; + } + evid = extend_pcr(this, qualifier, pcrs, pcr, measurement); + + this->state = this->bios_list->get_count(this->bios_list) ? + IMA_STATE_BIOS : IMA_STATE_INIT; + break; + default: + return FAILED; + } + } + else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_OS)) + { + switch (this->state) + { + case IMA_STATE_INIT: + this->ima_list = pts_ima_event_list_create( + IMA_RUNTIME_MEASUREMENTS); + if (!this->ima_list) + { + return FAILED; + } + this->creation_time = this->ima_list->get_time(this->ima_list); + this->count = this->ima_list->get_count(this->ima_list); + this->state = IMA_STATE_BOOT_AGGREGATE; + /* fall through to next state */ + case IMA_STATE_BOOT_AGGREGATE: + case IMA_STATE_RUNTIME: + status = this->ima_list->get_next(this->ima_list, &measurement, + &algo, &name); + if (status != SUCCESS) + { + DBG1(DBG_PTS, "could not retrieve ima measurement entry"); + return status; + } + if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count) + { + if (!check_boot_aggregate(pcrs, measurement, algo)) + { + return FAILED; + } + } + evid = extend_pcr(this, qualifier, pcrs, IMA_PCR, + measurement); + if (evid) + { + if (algo) + { + algo_len = strlen(algo); + name_len = strlen(name); + uri = malloc(algo_len + name_len + 1); + memcpy(uri, algo, algo_len); + strcpy(uri + algo_len, name); + } + else + { + uri = strdup(name); + } + evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED, + uri); + free(uri); + } + free(name); + free(algo); + + this->state = this->ima_list->get_count(this->ima_list) ? + IMA_STATE_RUNTIME : IMA_STATE_END; + break; + default: + return FAILED; + } + } + else + { + DBG1(DBG_PTS, "unsupported functional component name qualifier"); + return FAILED; + } + + *evidence = evid; + if (!evid) + { + return FAILED; + } + + return (this->state == IMA_STATE_INIT || this->state == IMA_STATE_END) ? + SUCCESS : NEED_MORE; +} + +/** + * Parse a validation URI of the form <hash algorithm>:<event name> + * into its components + */ +static pts_meas_algorithms_t parse_validation_uri(pts_comp_evidence_t *evidence, + char **ima_name, char **ima_algo, char *algo_buf) +{ + pts_meas_algorithms_t hash_algo; + char *uri, *pos, *algo, *name; + + evidence->get_validation(evidence, &uri); + + /* IMA-NG format? */ + pos = strchr(uri, ':'); + if (pos && (pos - uri + 1) < IMA_ALGO_LEN_MAX) + { + memset(algo_buf, '\0', IMA_ALGO_LEN_MAX); + memcpy(algo_buf, uri, pos - uri + 1); + algo = algo_buf; + name = pos + 1; + + if (streq(algo, "sha1:") || streq(algo, ":")) + { + hash_algo = PTS_MEAS_ALGO_SHA1; + } + else if (streq(algo, "sha256:")) + { + hash_algo = PTS_MEAS_ALGO_SHA256; + } + else if (streq(algo, "sha384:")) + { + hash_algo = PTS_MEAS_ALGO_SHA384; + } + else + { + hash_algo = PTS_MEAS_ALGO_NONE; + } + } + else + { + algo = NULL; + name = uri; + hash_algo = PTS_MEAS_ALGO_SHA1; + } + + if (ima_name) + { + *ima_name = name; + } + if (ima_algo) + { + *ima_algo = algo; + } + + return hash_algo; +} + +METHOD(pts_component_t, verify, status_t, + pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts, + pts_comp_evidence_t *evidence) +{ + bool has_pcr_info; + uint32_t pcr; + pts_meas_algorithms_t algo; + pts_pcr_transform_t transform; + pts_pcr_t *pcrs; + time_t creation_time; + chunk_t measurement, pcr_before, pcr_after; + status_t status = NOT_FOUND; + + this->aik_id = pts->get_aik_id(pts); + pcrs = pts->get_pcrs(pts); + measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform, + &creation_time); + + if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED)) + { + switch (this->state) + { + case IMA_STATE_INIT: + this->name->set_qualifier(this->name, qualifier); + status = this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->aik_id, algo, + &this->bios_cid, &this->bios_count); + this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN); + if (status != SUCCESS) + { + return status; + } + + if (this->bios_count) + { + DBG1(DBG_PTS, "checking %d BIOS evidence measurements", + this->bios_count); + } + else + { + DBG1(DBG_PTS, "registering BIOS evidence measurements"); + this->is_bios_registering = TRUE; + } + + this->state = IMA_STATE_BIOS; + /* fall through to next state */ + case IMA_STATE_BIOS: + if (this->is_bios_registering) + { + status = this->pts_db->insert_comp_measurement(this->pts_db, + measurement, this->bios_cid, this->aik_id, + ++this->seq_no, pcr, algo); + if (status != SUCCESS) + { + return status; + } + this->bios_count = this->seq_no + 1; + } + else + { + status = this->pts_db->check_comp_measurement(this->pts_db, + measurement, this->bios_cid, this->aik_id, + ++this->seq_no, pcr, algo); + if (status == FAILED) + { + return status; + } + } + break; + default: + return FAILED; + } + } + else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_OS)) + { + int ima_count; + char *ima_algo, *ima_name; + char algo_buf[IMA_ALGO_LEN_MAX]; + pts_meas_algorithms_t hash_algo; + + hash_algo = parse_validation_uri(evidence, &ima_name, &ima_algo, + algo_buf); + + switch (this->state) + { + case IMA_STATE_BIOS: + this->state = IMA_STATE_RUNTIME; + + if (!streq(ima_name, "boot_aggregate")) + { + DBG1(DBG_PTS, "ima: name must be 'boot_aggregate' " + "but is '%s'", ima_name); + return FAILED; + } + if (hash_algo != PTS_MEAS_ALGO_SHA1) + { + DBG1(DBG_PTS, "ima: boot_aggregate algorithm must be %N " + "but is %N", + pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1, + pts_meas_algorithm_names, hash_algo); + return FAILED; + } + if (!check_boot_aggregate(pcrs, measurement, ima_algo)) + { + return FAILED; + } + this->state = IMA_STATE_INIT; + /* fall through to next state */ + case IMA_STATE_INIT: + this->name->set_qualifier(this->name, qualifier); + status = this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->aik_id, algo, + &this->ima_cid, &ima_count); + this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN); + if (status != SUCCESS) + { + return status; + } + + if (ima_count) + { + DBG1(DBG_PTS, "checking boot aggregate evidence " + "measurement"); + status = this->pts_db->check_comp_measurement(this->pts_db, + measurement, this->ima_cid, + this->aik_id, 1, pcr, algo); + } + else + { + DBG1(DBG_PTS, "registering boot aggregate evidence " + "measurement"); + this->is_ima_registering = TRUE; + status = this->pts_db->insert_comp_measurement(this->pts_db, + measurement, this->ima_cid, + this->aik_id, 1, pcr, algo); + } + this->state = IMA_STATE_RUNTIME; + + if (status != SUCCESS) + { + return status; + } + break; + case IMA_STATE_RUNTIME: + { + uint8_t hash_buf[HASH_SIZE_SHA512]; + chunk_t digest, hash; + enumerator_t *e; + + this->count++; + if (evidence->get_validation(evidence, NULL) != + PTS_COMP_EVID_VALIDATION_PASSED) + { + DBG1(DBG_PTS, "evidence validation failed"); + this->count_failed++; + return FAILED; + } + hash = chunk_create(hash_buf, pts_meas_algo_hash_size(algo)); + + e = this->pts_db->create_file_meas_enumerator(this->pts_db, + pts->get_platform_id(pts), + hash_algo, ima_name); + if (e) + { + while (e->enumerate(e, &digest)) + { + if (!ima_hash(digest, ima_algo, ima_name, + FALSE, algo, hash_buf)) + { + status = FAILED; + break; + } + if (chunk_equals(measurement, hash)) + { + status = SUCCESS; + break; + } + else + { + status = VERIFY_ERROR; + } + } + e->destroy(e); + } + else + { + status = FAILED; + } + + switch (status) + { + case SUCCESS: + DBG3(DBG_PTS, "%#B for '%s' is ok", + &measurement, ima_name); + this->count_ok++; + break; + case NOT_FOUND: + DBG2(DBG_PTS, "%#B for '%s' not found", + &measurement, ima_name); + this->count_unknown++; + break; + case VERIFY_ERROR: + DBG1(DBG_PTS, "%#B for '%s' differs", + &measurement, ima_name); + this->count_differ++; + break; + case FAILED: + default: + DBG1(DBG_PTS, "%#B for '%s' failed", + &measurement, ima_name); + this->count_failed++; + } + break; + } + default: + return FAILED; + } + } + else + { + DBG1(DBG_PTS, "unsupported functional component name qualifier"); + return FAILED; + } + + has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); + if (has_pcr_info) + { + if (!chunk_equals(pcr_before, pcrs->get(pcrs, pcr))) + { + DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value", + pcr); + } + if (pcrs->set(pcrs, pcr, pcr_after)) + { + return status; + } + } + else + { + pcr_after = pcrs->extend(pcrs, pcr, measurement); + if (pcr_after.ptr) + { + return status; + } + } + return FAILED; +} + +METHOD(pts_component_t, finalize, bool, + pts_ita_comp_ima_t *this, uint8_t qualifier, bio_writer_t *result) +{ + char result_buf[BUF_LEN]; + char *pos = result_buf; + size_t len = BUF_LEN; + int written; + bool success = TRUE; + + this->name->set_qualifier(this->name, qualifier); + + if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED)) + { + /* finalize BIOS measurements */ + if (this->is_bios_registering) + { + /* close registration */ + this->is_bios_registering = FALSE; + + snprintf(pos, len, "registered %d BIOS evidence measurements", + this->seq_no); + } + else if (this->seq_no < this->bios_count) + { + snprintf(pos, len, "%d of %d BIOS evidence measurements missing", + this->bios_count - this->seq_no, this->bios_count); + success = FALSE; + } + else + { + snprintf(pos, len, "%d BIOS evidence measurements are ok", + this->bios_count); + } + } + else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_OS)) + { + /* finalize IMA file measurements */ + if (this->is_ima_registering) + { + /* close registration */ + this->is_ima_registering = FALSE; + + written = snprintf(pos, len, "registered IMA boot aggregate " + "evidence measurement; "); + pos += written; + len -= written; + } + if (this->count) + { + snprintf(pos, len, "processed %d IMA file evidence measurements: " + "%d ok, %d unknown, %d differ, %d failed", + this->count, this->count_ok, this->count_unknown, + this->count_differ, this->count_failed); + } + else + { + snprintf(pos, len, "no IMA file evidence measurements"); + success = FALSE; + } + } + else + { + snprintf(pos, len, "unsupported functional component name qualifier"); + success = FALSE; + } + this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN); + + DBG1(DBG_PTS, "%s", result_buf); + result->write_data(result, chunk_from_str(result_buf)); + + return success; +} + +METHOD(pts_component_t, get_ref, pts_component_t*, + pts_ita_comp_ima_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + +METHOD(pts_component_t, destroy, void, + pts_ita_comp_ima_t *this) +{ + int count; + + if (ref_put(&this->ref)) + { + + if (this->is_bios_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->bios_cid, this->aik_id); + DBG1(DBG_PTS, "deleted %d registered BIOS evidence measurements", + count); + } + if (this->is_ima_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->ima_cid, this->aik_id); + DBG1(DBG_PTS, "deleted registered boot aggregate evidence " + "measurement"); + } + DESTROY_IF(this->bios_list); + DESTROY_IF(this->ima_list); + this->name->destroy(this->name); + + free(this); + } +} + +/** + * See header + */ +pts_component_t *pts_ita_comp_ima_create(uint32_t depth, + pts_database_t *pts_db) +{ + pts_ita_comp_ima_t *this; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_evidence_flags = _get_evidence_flags, + .get_depth = _get_depth, + .measure = _measure, + .verify = _verify, + .finalize = _finalize, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA, + PTS_QUALIFIER_UNKNOWN), + .depth = depth, + .pts_db = pts_db, + .pcr_info = lib->settings->get_bool(lib->settings, + "%s.plugins.imc-attestation.pcr_info", FALSE, lib->ns), + .ref = 1, + ); + + return &this->public; +} + diff --git a/src/libimcv/pts/components/ita/ita_comp_ima.h b/src/libimcv/pts/components/ita/ita_comp_ima.h new file mode 100644 index 000000000..546d0a4b2 --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_ima.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011-2012 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_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_IMA_H_ +#define PTS_ITA_COMP_IMA_H_ + +#include "pts/components/pts_component.h" + +/** + * Create a PTS ITS Functional Component object + * + * @param depth Sub-component depth + * @param pts_db PTS measurement database + */ +pts_component_t* pts_ita_comp_ima_create(u_int32_t depth, + pts_database_t *pts_db); + +#endif /** PTS_ITA_COMP_IMA_H_ @}*/ diff --git a/src/libimcv/pts/components/ita/ita_comp_tboot.c b/src/libimcv/pts/components/ita/ita_comp_tboot.c new file mode 100644 index 000000000..273c18f31 --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_tboot.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ita_comp_tboot.h" +#include "ita_comp_func_name.h" + +#include "imcv.h" +#include "pts/components/pts_component.h" + +#include <utils/debug.h> +#include <pen/pen.h> + +typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t; + +/** + * Private data of a pts_ita_comp_tboot_t object. + * + */ +struct pts_ita_comp_tboot_t { + + /** + * Public pts_component_t interface. + */ + pts_component_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * Sub-component depth + */ + u_int32_t depth; + + /** + * PTS measurement database + */ + pts_database_t *pts_db; + + /** + * Primary key for AIK database entry + */ + int aik_id; + + /** + * Primary key for Component Functional Name database entry + */ + int cid; + + /** + * Primary key for AIK database entry + */ + int kid; + + /** + * Component is registering measurements + */ + bool is_registering; + + /** + * Time of TBOOT measurement + */ + time_t measurement_time; + + /** + * Expected measurement count + */ + int count; + + /** + * Measurement sequence number + */ + int seq_no; + + /** + * Reference count + */ + refcount_t ref; + +}; + +METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, + pts_ita_comp_tboot_t *this) +{ + return this->name; +} + +METHOD(pts_component_t, get_evidence_flags, u_int8_t, + pts_ita_comp_tboot_t *this) +{ + return PTS_REQ_FUNC_COMP_EVID_PCR; +} + +METHOD(pts_component_t, get_depth, u_int32_t, + pts_ita_comp_tboot_t *this) +{ + return this->depth; +} + +METHOD(pts_component_t, measure, status_t, + pts_ita_comp_tboot_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t **evidence) + +{ + size_t pcr_len; + pts_pcr_t *pcrs; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; + pts_comp_evidence_t *evid; + char *meas_hex, *pcr_before_hex, *pcr_after_hex; + chunk_t measurement, pcr_before, pcr_after; + u_int32_t extended_pcr; + + switch (this->seq_no++) + { + case 0: + /* dummy data since currently the TBOOT log is not retrieved */ + time(&this->measurement_time); + meas_hex = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.pcr17_meas", NULL, lib->ns); + pcr_before_hex = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.pcr17_before", NULL, lib->ns); + pcr_after_hex = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.pcr17_after", NULL, lib->ns); + extended_pcr = PCR_TBOOT_POLICY; + break; + case 1: + /* dummy data since currently the TBOOT log is not retrieved */ + meas_hex = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.pcr18_meas", NULL, lib->ns); + pcr_before_hex = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.pcr18_before", NULL, lib->ns); + pcr_after_hex = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.pcr18_after", NULL, lib->ns); + extended_pcr = PCR_TBOOT_MLE; + break; + default: + return FAILED; + } + + if (meas_hex == NULL || pcr_before_hex == NULL || pcr_after_hex == NULL) + { + return FAILED; + } + + hash_algo = PTS_MEAS_ALGO_SHA1; + pcr_len = HASH_SIZE_SHA1; + pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + + /* get and check the measurement data */ + measurement = chunk_from_hex( + chunk_create(meas_hex, strlen(meas_hex)), NULL); + pcr_before = chunk_from_hex( + chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL); + pcr_after = chunk_from_hex( + chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL); + if (pcr_before.len != pcr_len || pcr_after.len != pcr_len || + measurement.len != pcr_len) + { + DBG1(DBG_PTS, "TBOOT measurement or PCR data have the wrong size"); + free(measurement.ptr); + free(pcr_before.ptr); + free(pcr_after.ptr); + return FAILED; + } + + pcrs = pts->get_pcrs(pts); + pcrs->set(pcrs, extended_pcr, pcr_after); + evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), + this->depth, extended_pcr, hash_algo, pcr_transform, + this->measurement_time, measurement); + evid->set_pcr_info(evid, pcr_before, pcr_after); + + return (this->seq_no < 2) ? NEED_MORE : SUCCESS; +} + +METHOD(pts_component_t, verify, status_t, + pts_ita_comp_tboot_t *this, u_int8_t qualifier,pts_t *pts, + pts_comp_evidence_t *evidence) +{ + bool has_pcr_info; + u_int32_t extended_pcr, vid, name; + enum_name_t *names; + pts_meas_algorithms_t algo; + pts_pcr_transform_t transform; + pts_pcr_t *pcrs; + time_t measurement_time; + chunk_t measurement, pcr_before, pcr_after; + status_t status; + + this->aik_id = pts->get_aik_id(pts); + pcrs = pts->get_pcrs(pts); + measurement = evidence->get_measurement(evidence, &extended_pcr, + &algo, &transform, &measurement_time); + + status = this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->aik_id, algo, + &this->cid, &this->count); + if (status != SUCCESS) + { + return status; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = imcv_pts_components->get_comp_func_names(imcv_pts_components, vid); + + if (this->count) + { + DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence " + "measurements", this->count, pen_names, vid, names, name); + } + else + { + DBG1(DBG_PTS, "registering %N '%N' functional component evidence " + "measurements", pen_names, vid, names, name); + this->is_registering = TRUE; + } + + if (this->is_registering) + { + status = this->pts_db->insert_comp_measurement(this->pts_db, + measurement, this->cid, this->aik_id, + ++this->seq_no, extended_pcr, algo); + if (status != SUCCESS) + { + return status; + } + this->count = this->seq_no + 1; + } + else + { + status = this->pts_db->check_comp_measurement(this->pts_db, + measurement, this->cid, this->kid, + ++this->seq_no, extended_pcr, algo); + if (status != SUCCESS) + { + return status; + } + } + + has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); + if (has_pcr_info) + { + if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr))) + { + DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value", + extended_pcr); + } + if (pcrs->set(pcrs, extended_pcr, pcr_after)) + { + return SUCCESS; + } + } + + return SUCCESS; +} + +METHOD(pts_component_t, finalize, bool, + pts_ita_comp_tboot_t *this, u_int8_t qualifier, bio_writer_t *result) +{ + char result_buf[BUF_LEN]; + + if (this->is_registering) + { + /* close registration */ + this->is_registering = FALSE; + + snprintf(result_buf, BUF_LEN, "registered %d evidence measurements", + this->seq_no); + } + else if (this->seq_no < this->count) + { + snprintf(result_buf, BUF_LEN, "%d of %d evidence measurements " + "missing", this->count - this->seq_no, this->count); + return FALSE; + } + else + { + snprintf(result_buf, BUF_LEN, "%d evidence measurements are ok", + this->count); + } + DBG1(DBG_PTS, "%s", result_buf); + result->write_data(result, chunk_from_str(result_buf)); + + return TRUE; +} + +METHOD(pts_component_t, get_ref, pts_component_t*, + pts_ita_comp_tboot_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + +METHOD(pts_component_t, destroy, void, + pts_ita_comp_tboot_t *this) +{ + int count; + u_int32_t vid, name; + enum_name_t *names; + + if (ref_put(&this->ref)) + { + if (this->is_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->cid, this->aik_id); + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = imcv_pts_components->get_comp_func_names(imcv_pts_components, + vid); + DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component " + "evidence measurements", count, pen_names, vid, names, name); + } + this->name->destroy(this->name); + free(this); + } +} + +/** + * See header + */ +pts_component_t *pts_ita_comp_tboot_create(u_int32_t depth, + pts_database_t *pts_db) +{ + pts_ita_comp_tboot_t *this; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_evidence_flags = _get_evidence_flags, + .get_depth = _get_depth, + .measure = _measure, + .verify = _verify, + .finalize = _finalize, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT, + PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED), + .depth = depth, + .pts_db = pts_db, + .ref = 1, + ); + + return &this->public; +} + diff --git a/src/libimcv/pts/components/ita/ita_comp_tboot.h b/src/libimcv/pts/components/ita/ita_comp_tboot.h new file mode 100644 index 000000000..1e1a14831 --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_tboot.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_TBOOT_H_ +#define PTS_ITA_COMP_TBOOT_H_ + +#include "pts/components/pts_component.h" + +/** + * Create a PTS ITS Functional Component object + * + * @param depth Sub-component depth + * @param pts_db PTS measurement database + */ +pts_component_t* pts_ita_comp_tboot_create(u_int32_t depth, + pts_database_t *pts_db); + +#endif /** PTS_ITA_COMP_TBOOT_H_ @}*/ diff --git a/src/libimcv/pts/components/ita/ita_comp_tgrub.c b/src/libimcv/pts/components/ita/ita_comp_tgrub.c new file mode 100644 index 000000000..097e4c89c --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_tgrub.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2011-2012 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_comp_tgrub.h" +#include "ita_comp_func_name.h" + +#include "pts/components/pts_component.h" + +#include <utils/debug.h> +#include <pen/pen.h> + +typedef struct pts_ita_comp_tgrub_t pts_ita_comp_tgrub_t; + +/** + * Private data of a pts_ita_comp_tgrub_t object. + * + */ +struct pts_ita_comp_tgrub_t { + + /** + * Public pts_component_t interface. + */ + pts_component_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * Sub-component depth + */ + u_int32_t depth; + + /** + * PTS measurement database + */ + pts_database_t *pts_db; + + /** + * Reference count + */ + refcount_t ref; + +}; + +METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, + pts_ita_comp_tgrub_t *this) +{ + return this->name; +} + +METHOD(pts_component_t, get_evidence_flags, u_int8_t, + pts_ita_comp_tgrub_t *this) +{ + return PTS_REQ_FUNC_COMP_EVID_PCR; +} + +METHOD(pts_component_t, get_depth, u_int32_t, + pts_ita_comp_tgrub_t *this) +{ + return this->depth; +} + +METHOD(pts_component_t, measure, status_t, + pts_ita_comp_tgrub_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t **evidence) +{ + size_t pcr_len; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; + pts_comp_evidence_t *evid; + u_int32_t extended_pcr; + time_t measurement_time; + chunk_t measurement, pcr_before, pcr_after; + + /* Provisional implementation for TGRUB */ + extended_pcr = PCR_DEBUG; + time(&measurement_time); + + if (!pts->read_pcr(pts, extended_pcr, &pcr_after)) + { + DBG1(DBG_PTS, "error occurred while reading PCR: %d", extended_pcr); + return FAILED; + } + + hash_algo = PTS_MEAS_ALGO_SHA1; + pcr_len = HASH_SIZE_SHA1; + pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + + measurement = chunk_alloc(pcr_len); + memset(measurement.ptr, 0x00, measurement.len); + + pcr_before = chunk_alloc(pcr_len); + memset(pcr_before.ptr, 0x00, pcr_before.len); + + evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), + this->depth, extended_pcr, + hash_algo, pcr_transform, + measurement_time, measurement); + evid->set_pcr_info(evid, pcr_before, pcr_after); + + return SUCCESS; +} + +METHOD(pts_component_t, verify, status_t, + pts_ita_comp_tgrub_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t *evidence) +{ + bool has_pcr_info; + u_int32_t extended_pcr; + pts_meas_algorithms_t algo; + pts_pcr_transform_t transform; + pts_pcr_t *pcrs; + time_t measurement_time; + chunk_t pcr_before, pcr_after; + chunk_t measurement __attribute__((unused)); + + pcrs = pts->get_pcrs(pts); + measurement = evidence->get_measurement(evidence, &extended_pcr, + &algo, &transform, &measurement_time); + if (extended_pcr != PCR_DEBUG) + { + return FAILED; + } + + /* TODO check measurement in database */ + + has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); + if (has_pcr_info) + { + if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr))) + { + DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to pcr value"); + } + if (pcrs->set(pcrs, extended_pcr, pcr_after)) + { + return SUCCESS; + } + } + + return SUCCESS; +} + +METHOD(pts_component_t, finalize, bool, + pts_ita_comp_tgrub_t *this, u_int8_t qualifier, bio_writer_t *result) +{ + return FALSE; +} + +METHOD(pts_component_t, get_ref, pts_component_t*, + pts_ita_comp_tgrub_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + +METHOD(pts_component_t, destroy, void, + pts_ita_comp_tgrub_t *this) +{ + if (ref_put(&this->ref)) + { + this->name->destroy(this->name); + free(this); + } +} + +/** + * See header + */ +pts_component_t *pts_ita_comp_tgrub_create(u_int32_t depth, + pts_database_t *pts_db) +{ + pts_ita_comp_tgrub_t *this; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_evidence_flags = _get_evidence_flags, + .get_depth = _get_depth, + .measure = _measure, + .verify = _verify, + .finalize = _finalize, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TGRUB, + PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED), + .depth = depth, + .pts_db = pts_db, + .ref = 1, + ); + + return &this->public; +} diff --git a/src/libimcv/pts/components/ita/ita_comp_tgrub.h b/src/libimcv/pts/components/ita/ita_comp_tgrub.h new file mode 100644 index 000000000..59913c82d --- /dev/null +++ b/src/libimcv/pts/components/ita/ita_comp_tgrub.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_ita_comp_func_name pts_ita_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_ITA_COMP_TGRUB_H_ +#define PTS_ITA_COMP_TGRUB_H_ + +#include "pts/components/pts_component.h" + +/** + * Create a PTS ITS Functional Component object + * + * @param depth Sub-component depth + * @param pts_db PTS measurement database + */ +pts_component_t* pts_ita_comp_tgrub_create(u_int32_t depth, + pts_database_t *pts_db); + +#endif /** PTS_ITA_COMP_TGRUB_H_ @}*/ diff --git a/src/libimcv/pts/components/pts_comp_evidence.c b/src/libimcv/pts/components/pts_comp_evidence.c new file mode 100644 index 000000000..08c3d5e9a --- /dev/null +++ b/src/libimcv/pts/components/pts_comp_evidence.c @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu, Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pts/components/pts_comp_evidence.h" + +#include <utils/debug.h> + +typedef struct private_pts_comp_evidence_t private_pts_comp_evidence_t; + +/** + * Private data of a pts_comp_evidence_t object. + */ +struct private_pts_comp_evidence_t { + + /** + * Public pts_comp_evidence_t interface. + */ + pts_comp_evidence_t public; + + /** + * Component Functional Name + */ + pts_comp_func_name_t *name; + + /** + * Sub-Component Depth + */ + u_int32_t depth; + + /** + * Measurement Time + */ + time_t measurement_time; + + /** + * Measurement Time + */ + chunk_t measurement; + + /** + * Measurement Hash Algorithm + */ + pts_meas_algorithms_t hash_algorithm; + + /** + * Is PCR Information included? + */ + bool has_pcr_info; + + /** + * PCR the measurement was extended into + */ + u_int32_t extended_pcr; + + /** + * PCR value before extension + */ + chunk_t pcr_before; + + /** + * PCR value after extension + */ + chunk_t pcr_after; + + /** + * Transformation used for extending measurement into PCR + */ + pts_pcr_transform_t transform; + + /** + * Component Validation Result + */ + pts_comp_evid_validation_t validation; + + /** + * Verification Policy URI + */ + char *policy_uri; + +}; + +METHOD(pts_comp_evidence_t, get_comp_func_name, pts_comp_func_name_t*, + private_pts_comp_evidence_t *this, u_int32_t *depth) +{ + if (depth) + { + *depth = this->depth; + } + return this->name; +} + +METHOD(pts_comp_evidence_t, get_extended_pcr, u_int32_t, + private_pts_comp_evidence_t *this) +{ + return this->extended_pcr; +} + +METHOD(pts_comp_evidence_t, get_measurement, chunk_t, + private_pts_comp_evidence_t *this, u_int32_t *extended_pcr, + pts_meas_algorithms_t *algo, pts_pcr_transform_t *transform, + time_t *measurement_time) +{ + if (extended_pcr) + { + *extended_pcr = this->extended_pcr; + } + if (algo) + { + *algo = this->hash_algorithm; + } + if (transform) + { + *transform = this->transform; + } + if (measurement_time) + { + *measurement_time = this->measurement_time; + } + return this->measurement; +} + +METHOD(pts_comp_evidence_t, get_pcr_info, bool, + private_pts_comp_evidence_t *this, chunk_t *pcr_before, chunk_t *pcr_after) +{ + if (pcr_before) + { + *pcr_before = this->pcr_before; + } + if (pcr_after) + { + *pcr_after = this->pcr_after; + } + return this->has_pcr_info; +} + +METHOD(pts_comp_evidence_t, set_pcr_info, void, + private_pts_comp_evidence_t *this, chunk_t pcr_before, chunk_t pcr_after) +{ + this->has_pcr_info = TRUE; + this->pcr_before = pcr_before; + this->pcr_after = pcr_after; + + DBG3(DBG_PTS, "PCR %2d before value : %#B", this->extended_pcr, &pcr_before); + DBG3(DBG_PTS, "PCR %2d after value : %#B", this->extended_pcr, &pcr_after); +} + +METHOD(pts_comp_evidence_t, get_validation, pts_comp_evid_validation_t, + private_pts_comp_evidence_t *this, char **uri) +{ + if (uri) + { + *uri = this->policy_uri; + } + return this->validation; +} + +METHOD(pts_comp_evidence_t, set_validation, void, + private_pts_comp_evidence_t *this, pts_comp_evid_validation_t validation, + char *uri) +{ + this->validation = validation; + if (uri) + { + this->policy_uri = strdup(uri); + DBG3(DBG_PTS, "'%s'", uri); + } +} + +METHOD(pts_comp_evidence_t, destroy, void, + private_pts_comp_evidence_t *this) +{ + this->name->destroy(this->name); + free(this->measurement.ptr); + free(this->pcr_before.ptr); + free(this->pcr_after.ptr); + free(this->policy_uri); + free(this); +} + +/** + * See header + */ +pts_comp_evidence_t *pts_comp_evidence_create(pts_comp_func_name_t *name, + u_int32_t depth, + u_int32_t extended_pcr, + pts_meas_algorithms_t algo, + pts_pcr_transform_t transform, + time_t measurement_time, + chunk_t measurement) +{ + private_pts_comp_evidence_t *this; + + INIT(this, + .public = { + .get_comp_func_name = _get_comp_func_name, + .get_extended_pcr = _get_extended_pcr, + .get_measurement = _get_measurement, + .get_pcr_info = _get_pcr_info, + .set_pcr_info = _set_pcr_info, + .get_validation = _get_validation, + .set_validation = _set_validation, + .destroy = _destroy, + }, + .name = name, + .depth = depth, + .extended_pcr = extended_pcr, + .hash_algorithm = algo, + .transform = transform, + .measurement_time = measurement_time, + .measurement = measurement, + ); + + name->log(name, ""); + DBG3(DBG_PTS, "measurement time: %T", &measurement_time, FALSE); + DBG3(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement); + + return &this->public; +} + +/** + * See header + */ +pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo, + size_t pcr_len) +{ + size_t hash_size; + + hash_size = pts_meas_algo_hash_size(algo); + if (hash_size == 0) + { + return PTS_PCR_TRANSFORM_NO; + } + if (hash_size == pcr_len) + { + return PTS_PCR_TRANSFORM_MATCH; + } + if (hash_size > pcr_len) + { + return PTS_PCR_TRANSFORM_LONG; + } + return PTS_PCR_TRANSFORM_SHORT; +} + diff --git a/src/libimcv/pts/components/pts_comp_evidence.h b/src/libimcv/pts/components/pts_comp_evidence.h new file mode 100644 index 000000000..55776ce8b --- /dev/null +++ b/src/libimcv/pts/components/pts_comp_evidence.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu, Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_comp_evidence pts_comp_evidence + * @{ @ingroup pts + */ + +#ifndef PTS_COMP_EVIDENCE_H_ +#define PTS_COMP_EVIDENCE_H_ + +typedef struct pts_comp_evidence_t pts_comp_evidence_t; +typedef enum pts_pcr_transform_t pts_pcr_transform_t; +typedef enum pts_comp_evid_validation_t pts_comp_evid_validation_t; + +#include "pts/pts_meas_algo.h" +#include "pts/components/pts_comp_func_name.h" + +#include <library.h> + +/** + * PTS PCR Transformations + */ +enum pts_pcr_transform_t { + /** No Transformation */ + PTS_PCR_TRANSFORM_NO = 0, + /** Hash Value matched PCR size */ + PTS_PCR_TRANSFORM_MATCH = 1, + /** Hash value shorter than PCR size */ + PTS_PCR_TRANSFORM_SHORT = 2, + /** Hash value longer than PCR size */ + PTS_PCR_TRANSFORM_LONG = 3, +}; + +/** + * PTS Component Evidence Validation Result Flags + */ +enum pts_comp_evid_validation_t { + /** No Validation was attempted */ + PTS_COMP_EVID_VALIDATION_NONE = 0x00, + /** Attempted validation, unable to verify */ + PTS_COMP_EVID_VALIDATION_UNABLE = 0x20, + /** Attempted validation, verification failed */ + PTS_COMP_EVID_VALIDATION_FAILED = 0x40, + /** Attempted validation, verification passed */ + PTS_COMP_EVID_VALIDATION_PASSED = 0x60, +}; + +/** + * PTS Functional Component Interface + */ +struct pts_comp_evidence_t { + + /** + * Gets the Component Functional Name and Sub-Component Depth + * + * @param depth Sub-Component Depth + * @result Component Functional Name + */ + pts_comp_func_name_t* (*get_comp_func_name)(pts_comp_evidence_t *this, + u_int32_t *depth); + + /** + * Gets the PCR the measurement was extended into + * + * @result PCR the measurement was extended into + */ + u_int32_t (*get_extended_pcr)(pts_comp_evidence_t *this); + + /** + * Gets the measurement and the algorithms used + * + * @param extended_pcr PCR the measurement was extended into + * @param algo Measurement hash algorithm + * @param transform Transformation used for PCR extension + * @param measurement_time Time the measurement was taken + * @result Measurement hash value + */ + chunk_t (*get_measurement)(pts_comp_evidence_t *this, + u_int32_t *extended_pcr, + pts_meas_algorithms_t *algo, + pts_pcr_transform_t *transform, + time_t *measurement_time); + + /** + * Gets the PCR information if available + * + * @param pcr_before PCR value before extension + * @param pcr_after PCR value after extension + * @result TRUE if PCR information is available + */ + bool (*get_pcr_info)(pts_comp_evidence_t *this, chunk_t *pcr_before, + chunk_t *pcr_after); + + /** + * Sets PCR information if available + * + * @param pcr_before PCR value before extension + * @param pcr_after PCR value after extension + */ + void (*set_pcr_info)(pts_comp_evidence_t *this, chunk_t pcr_before, + chunk_t pcr_after); + + /** + * Gets Validation Result if available + * + * @param uri Verification Policy URI + * @return validation Validation Result + */ + pts_comp_evid_validation_t (*get_validation)(pts_comp_evidence_t *this, + char **uri); + + /** + * Sets Validation Result if available + * + * @param validation Validation Result + * @param uri Verification Policy URI + */ + void (*set_validation)(pts_comp_evidence_t *this, + pts_comp_evid_validation_t validation, char* uri); + + /** + * Destroys a pts_comp_evidence_t object. + */ + void (*destroy)(pts_comp_evidence_t *this); + +}; + +/** + * Creates a pts_comp_evidence_t object + * + * @param name Component Functional Name + * @param depth Sub-component depth + * @param extended_pcr PCR the measurement was extended into + * @param algo Measurement hash algorithm + * @param transform Transformation used for PCR extension + * @param measurement_time Time the measurement was taken, 0 if unknown + * @param measurement Measurement hash value + */ +pts_comp_evidence_t* pts_comp_evidence_create(pts_comp_func_name_t *name, + u_int32_t depth, + u_int32_t extended_pcr, + pts_meas_algorithms_t algo, + pts_pcr_transform_t transform, + time_t measurement_time, + chunk_t measurement); + +/** + * Determine transform to fit measurement hash into PCR register + * + * @param algo Measurement hash algorithm + * @param pcr_len Length of the PCR registers in bytes + * @return PCR transform type + */ +pts_pcr_transform_t pts_meas_algo_to_pcr_transform(pts_meas_algorithms_t algo, + size_t pcr_len); + +#endif /** PTS_COMP_EVIDENCE_H_ @}*/ diff --git a/src/libimcv/pts/components/pts_comp_func_name.c b/src/libimcv/pts/components/pts_comp_func_name.c new file mode 100644 index 000000000..e12522ed1 --- /dev/null +++ b/src/libimcv/pts/components/pts_comp_func_name.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imcv.h" +#include "pts/components/pts_comp_func_name.h" + +#include <utils/debug.h> + +typedef struct private_pts_comp_func_name_t private_pts_comp_func_name_t; + +/** + * Private data of a pts_comp_func_name_t object. + * + */ +struct private_pts_comp_func_name_t { + + /** + * Public pts_comp_func_name_t interface. + */ + pts_comp_func_name_t public; + + /** + * PTS Component Functional Name Vendor ID + */ + u_int32_t vid; + + /** + * PTS Component Functional Name + */ + u_int32_t name; + + /** + * PTS Component Functional Name Qualifier + */ + u_int8_t qualifier; + +}; + +METHOD(pts_comp_func_name_t, get_vendor_id, u_int32_t, + private_pts_comp_func_name_t *this) +{ + return this->vid; +} + +METHOD(pts_comp_func_name_t, get_name, u_int32_t, + private_pts_comp_func_name_t *this) +{ + return this->name; +} + +METHOD(pts_comp_func_name_t, get_qualifier, u_int8_t, + private_pts_comp_func_name_t *this) +{ + return this->qualifier; +} + +METHOD(pts_comp_func_name_t, set_qualifier, void, + private_pts_comp_func_name_t *this, u_int8_t qualifier) +{ + this->qualifier = qualifier; +} + +static bool equals(private_pts_comp_func_name_t *this, + private_pts_comp_func_name_t *other) +{ + if (this->vid != other->vid || this->name != other->name) + { + return FALSE; + } + if (this->qualifier == PTS_QUALIFIER_UNKNOWN || + other->qualifier == PTS_QUALIFIER_UNKNOWN) + { + return TRUE; + } + /* TODO handle qualifier wildcards */ + + return this->qualifier == other->qualifier; +} + +METHOD(pts_comp_func_name_t, clone_, pts_comp_func_name_t*, + private_pts_comp_func_name_t *this) +{ + private_pts_comp_func_name_t *clone; + + clone = malloc_thing(private_pts_comp_func_name_t); + memcpy(clone, this, sizeof(private_pts_comp_func_name_t)); + + return &clone->public; +} + +METHOD(pts_comp_func_name_t, log_, void, + private_pts_comp_func_name_t *this, char *label) +{ + enum_name_t *names, *types; + char flags[8]; + int type; + + names = imcv_pts_components->get_comp_func_names(imcv_pts_components, + this->vid); + types = imcv_pts_components->get_qualifier_type_names(imcv_pts_components, + this->vid); + type = imcv_pts_components->get_qualifier(imcv_pts_components, + &this->public, flags); + + if (names && types) + { + DBG2(DBG_PTS, "%s%N functional component '%N' [%s] '%N'", + label, pen_names, this->vid, names, this->name, flags, types, type); + } + else + { + DBG2(DBG_PTS, "%s0x%06x functional component 0x%08x 0x%02x", + label, this->vid, this->name, this->qualifier); + } +} + +METHOD(pts_comp_func_name_t, destroy, void, + private_pts_comp_func_name_t *this) +{ + free(this); +} + +/** + * See header + */ +pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name, + u_int8_t qualifier) +{ + private_pts_comp_func_name_t *this; + + INIT(this, + .public = { + .get_vendor_id = _get_vendor_id, + .get_name = _get_name, + .get_qualifier = _get_qualifier, + .set_qualifier = _set_qualifier, + .equals = (bool(*)(pts_comp_func_name_t*,pts_comp_func_name_t*))equals, + .clone = _clone_, + .log = _log_, + .destroy = _destroy, + }, + .vid = vid, + .name = name, + .qualifier = qualifier, + ); + + return &this->public; +} + diff --git a/src/libimcv/pts/components/pts_comp_func_name.h b/src/libimcv/pts/components/pts_comp_func_name.h new file mode 100644 index 000000000..90ad7083f --- /dev/null +++ b/src/libimcv/pts/components/pts_comp_func_name.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_comp_func_name pts_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_FUNC_COMP_NAME_H_ +#define PTS_FUNC_COMP_NAME_H_ + +typedef struct pts_comp_func_name_t pts_comp_func_name_t; + +#include <library.h> + +#define PTS_QUALIFIER_UNKNOWN 0x00 +#define PTS_QUALIFIER_WILDCARD 0x3F + +/** + * PTS Component Functional Name object + */ +struct pts_comp_func_name_t { + + /** + * Get the PTS Component Functional Name Vendor ID + * + * @return PTS Component Functional Name Vendor ID + */ + u_int32_t (*get_vendor_id)(pts_comp_func_name_t *this); + + /** + * Get the PTS Component Functional Name + * + * @return PTS Component Functional Name + */ + u_int32_t (*get_name)(pts_comp_func_name_t *this); + + /** + * Get the PTS Component Functional Name Qualifier + * + * @return PTS Component Functional Name Qualifier + */ + u_int8_t (*get_qualifier)(pts_comp_func_name_t *this); + + /** + * Set the PTS Component Functional Name Qualifier + * + * @param qualifier PTS Component Functional Name Qualifier to be set + */ + void (*set_qualifier)(pts_comp_func_name_t *this, u_int8_t qualifier); + + /** + * Check to PTS Component Functional Names for equality + * + * @param other Other PTS Component Functional Name + * @return TRUE if equal + */ + bool (*equals)(pts_comp_func_name_t *this, pts_comp_func_name_t *other); + + /** + * Clone a PTS Component Functional Name + * + * @return Cloned PTS Component Functional Name + */ + pts_comp_func_name_t* (*clone)(pts_comp_func_name_t *this); + + /** + * Write PTS Component Functional Name information to the standard logfile + * + * @param label Label added to log output + */ + void (*log)(pts_comp_func_name_t *this, char *label); + + /** + * Destroys a pts_component_t object. + */ + void (*destroy)(pts_comp_func_name_t *this); + +}; + +/** + * Create a PTS Component Functional Name object + * + * @param vid PTS Component Functional Name Vendor ID + * @param name PTS Component Functional Name + * @param qualifier PTS Component Functional Name Qualifier + */ +pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name, + u_int8_t qualifier); + +#endif /** PTS_FUNC_COMP_NAME_H_ @}*/ diff --git a/src/libimcv/pts/components/pts_component.h b/src/libimcv/pts/components/pts_component.h new file mode 100644 index 000000000..71b1ad59c --- /dev/null +++ b/src/libimcv/pts/components/pts_component.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011-2012 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_component pts_component + * @{ @ingroup pts + */ + +#ifndef PTS_COMPONENT_H_ +#define PTS_COMPONENT_H_ + +typedef struct pts_component_t pts_component_t; + +#include "pts/pts.h" +#include "pts/pts_database.h" +#include "pts/pts_file_meas.h" +#include "pts/components/pts_comp_func_name.h" +#include "pts/components/pts_comp_evidence.h" + +#include <library.h> +#include <bio/bio_writer.h> + +/** + * PTS Functional Component Interface + */ +struct pts_component_t { + + /** + * Get the PTS Component Functional Name + * + * @return PTS Component Functional Name + */ + pts_comp_func_name_t* (*get_comp_func_name)(pts_component_t *this); + + /** + * Get the PTS Component Evidence Flags + * + * @return PTS Component Functional Name + */ + u_int8_t (*get_evidence_flags)(pts_component_t *this); + + /** + * Get the PTS Sub-component Depth + * + * @return PTS Sub-component Depth + */ + u_int32_t (*get_depth)(pts_component_t *this); + + /** + * Do evidence measurements on the PTS Functional Component + * + * @param qualifier PTS Component Functional Name Qualifier + * @param pts PTS interface + * @param evidence returns component evidence measureemt + * @param measurements additional file measurements (NULL if not present) + * @return status return code + */ + status_t (*measure)(pts_component_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t** evidence); + + /** + * Verify the evidence measurements of the PTS Functional Component + * + * @param qualifier PTS Component Functional Name Qualifier + * @param pts PTS interface + * @param evidence component evidence measurement to be verified + * @return status return code + */ + status_t (*verify)(pts_component_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t *evidence); + + /** + * Tell the PTS Functional Component to finalize pending registrations + * and check for missing measurements + * + * @param qualifier PTS Component Functional Name Qualifier + * @param result writer appending concise measurement result + * @return TRUE if finalization successful + */ + bool (*finalize)(pts_component_t *this, u_int8_t qualifier, + bio_writer_t *result); + + /** + * Get a new reference to the PTS Functional Component + * + * @return this, with an increased refcount + */ + pts_component_t* (*get_ref)(pts_component_t *this); + + /** + * Destroys a pts_component_t object. + */ + void (*destroy)(pts_component_t *this); + +}; + +#endif /** PTS_COMPONENT_H_ @}*/ diff --git a/src/libimcv/pts/components/pts_component_manager.c b/src/libimcv/pts/components/pts_component_manager.c new file mode 100644 index 000000000..9c1375b79 --- /dev/null +++ b/src/libimcv/pts/components/pts_component_manager.c @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2011-2012 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/components/pts_component_manager.h" + +#include <collections/linked_list.h> +#include <utils/debug.h> + +typedef struct private_pts_component_manager_t private_pts_component_manager_t; +typedef struct vendor_entry_t vendor_entry_t; +typedef struct component_entry_t component_entry_t; + +#define PTS_QUALIFIER_SIZE 6 + +/** + * Vendor-specific namespace information and list of registered components + */ +struct vendor_entry_t { + + /** + * Vendor ID + */ + pen_t vendor_id; + + /** + * Vendor-specific Component Functional names + */ + enum_name_t *comp_func_names; + + /** + * Vendor-specific Qualifier Type names + */ + enum_name_t *qualifier_type_names; + + /** + * Vendor-specific Qualifier Flag names + */ + char *qualifier_flag_names; + + /** + * Vendor-specific size of Qualfiier Type field + */ + int qualifier_type_size; + + /** + * List of vendor-specific registered Functional Components + */ + linked_list_t *components; +}; + +/** + * Destroy a vendor_entry_t object + */ +static void vendor_entry_destroy(vendor_entry_t *entry) +{ + entry->components->destroy_function(entry->components, free); + free(entry); +} + +/** + * Creation method for a vendor-specific Functional Component + */ +struct component_entry_t { + + /** + * Vendor-Specific Component Functional Name + */ + u_int32_t name; + + /** + * Functional Component creation method + */ + pts_component_create_t create; +}; + +/** + * Private data of a pts_component_manager_t object. + * + */ +struct private_pts_component_manager_t { + + /** + * Public pts_component_manager_t interface. + */ + pts_component_manager_t public; + + /** + * List of vendor-specific namespaces and registered components + */ + linked_list_t *list; +}; + +METHOD(pts_component_manager_t, add_vendor, void, + private_pts_component_manager_t *this, pen_t vendor_id, + enum_name_t *comp_func_names, int qualifier_type_size, + char *qualifier_flag_names, enum_name_t *qualifier_type_names) +{ + vendor_entry_t *entry; + + entry = malloc_thing(vendor_entry_t); + entry->vendor_id = vendor_id; + entry->comp_func_names = comp_func_names; + entry->qualifier_type_size = qualifier_type_size; + entry->qualifier_flag_names = qualifier_flag_names; + entry->qualifier_type_names = qualifier_type_names; + entry->components = linked_list_create(); + + this->list->insert_last(this->list, entry); + DBG2(DBG_PTS, "added %N functional component namespace", + pen_names, vendor_id); +} + +METHOD(pts_component_manager_t, get_comp_func_names, enum_name_t*, + private_pts_component_manager_t *this, pen_t vendor_id) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + enum_name_t *names = NULL; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + names = entry->comp_func_names; + break; + } + } + enumerator->destroy(enumerator); + + return names; +} + +METHOD(pts_component_manager_t, get_qualifier_type_names, enum_name_t*, + private_pts_component_manager_t *this, pen_t vendor_id) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + enum_name_t *names = NULL; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + names = entry->qualifier_type_names; + break; + } + } + enumerator->destroy(enumerator); + + return names; +} + +METHOD(pts_component_manager_t, add_component, void, + private_pts_component_manager_t *this, pen_t vendor_id, u_int32_t name, + pts_component_create_t create) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + component_entry_t *component; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + component = malloc_thing(component_entry_t); + component->name = name; + component->create = create; + + entry->components->insert_last(entry->components, component); + DBG2(DBG_PTS, "added %N functional component '%N'", + pen_names, vendor_id, + get_comp_func_names(this, vendor_id), name); + } + } + enumerator->destroy(enumerator); +} + +METHOD(pts_component_manager_t, remove_vendor, void, + private_pts_component_manager_t *this, pen_t vendor_id) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == vendor_id) + { + this->list->remove_at(this->list, enumerator); + vendor_entry_destroy(entry); + DBG2(DBG_PTS, "removed %N functional component namespace", + pen_names, vendor_id); + } + } + enumerator->destroy(enumerator); +} + +METHOD(pts_component_manager_t, get_qualifier, u_int8_t, + private_pts_component_manager_t *this, pts_comp_func_name_t *name, + char *flags) +{ + enumerator_t *enumerator; + vendor_entry_t *entry; + u_int8_t qualifier, size, flag, type = 0; + int i; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == name->get_vendor_id(name)) + { + qualifier = name->get_qualifier(name); + size = entry->qualifier_type_size; + + /* mask qualifier type field */ + type = qualifier & ((1 << size) - 1); + + /* determine flags */ + size = PTS_QUALIFIER_SIZE - size; + flag = (1 << (PTS_QUALIFIER_SIZE - 1)); + if (flags) + { + for (i = 0 ; i < size; i++) + { + flags[i] = (qualifier & flag) ? + entry->qualifier_flag_names[i] : '.'; + flag >>= 1; + } + flags[size] = '\0'; + } + } + } + enumerator->destroy(enumerator); + + return type; +} + +METHOD(pts_component_manager_t, create, pts_component_t*, + private_pts_component_manager_t *this, + pts_comp_func_name_t *name, u_int32_t depth, pts_database_t *pts_db) +{ + enumerator_t *enumerator, *e2; + vendor_entry_t *entry; + component_entry_t *entry2; + pts_component_t *component = NULL; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->vendor_id == name->get_vendor_id(name)) + { + e2 = entry->components->create_enumerator(entry->components); + while (e2->enumerate(e2, &entry2)) + { + if (entry2->name == name->get_name(name) && entry2->create) + { + component = entry2->create(depth, pts_db); + break; + } + } + e2->destroy(e2); + break; + } + } + enumerator->destroy(enumerator); + + return component; +} + +METHOD(pts_component_manager_t, destroy, void, + private_pts_component_manager_t *this) +{ + this->list->destroy_function(this->list, (void *)vendor_entry_destroy); + free(this); +} + +/** + * See header + */ +pts_component_manager_t *pts_component_manager_create(void) +{ + private_pts_component_manager_t *this; + + INIT(this, + .public = { + .add_vendor = _add_vendor, + .add_component = _add_component, + .remove_vendor = _remove_vendor, + .get_comp_func_names = _get_comp_func_names, + .get_qualifier_type_names = _get_qualifier_type_names, + .get_qualifier = _get_qualifier, + .create = _create, + .destroy = _destroy, + }, + .list = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/libimcv/pts/components/pts_component_manager.h b/src/libimcv/pts/components/pts_component_manager.h new file mode 100644 index 000000000..61055ec74 --- /dev/null +++ b/src/libimcv/pts/components/pts_component_manager.h @@ -0,0 +1,124 @@ +/* + * 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 pts_component_manager pts_component_manager + * @{ @ingroup pts + */ + +#ifndef PTS_COMPONENT_MANAGER_H_ +#define PTS_COMPONENT_MANAGER_H_ + +typedef struct pts_component_manager_t pts_component_manager_t; + +#include "pts/pts_database.h" +#include "pts/components/pts_component.h" +#include "pts/components/pts_comp_func_name.h" + +#include <library.h> +#include <pen/pen.h> + +typedef pts_component_t* (*pts_component_create_t)(u_int32_t depth, + pts_database_t *pts_db); + +/** + * Manages PTS Functional Components + */ +struct pts_component_manager_t { + + /** + * Add vendor-specific functional component names + * + * @param vendor_id Private Enterprise Number (PEN) + * @param comp_func_names Vendor-specific Component Functional names + * @param qualifier_type_size Vendor-specific Qualifier Type size + * @param qualifier_flag_names Vendor-specific Qualifier Flag names + * @param qualifier_type_names Vendor-specific Qualifier Type names + */ + void (*add_vendor)(pts_component_manager_t *this, pen_t vendor_id, + enum_name_t *comp_func_names, + int qualifier_type_size, + char *qualifier_flag_names, + enum_name_t *qualifier_type_names); + + /** + * Add vendor-specific functional component + * + * @param vendor_id Private Enterprise Number (PEN) + * @param names Component Functional Name + * @param create Functional Component creation method + */ + void (*add_component)(pts_component_manager_t *this, pen_t vendor_id, + u_int32_t name, pts_component_create_t create); + + /** + * Remove vendor-specific components and associated namespace + * + * @param vendor_id Private Enterprise Number (PEN) + */ + void (*remove_vendor)(pts_component_manager_t *this, pen_t vendor_id); + + /** + * Return the Functional Component names for a given vendor ID + * + * @param vendor_id Private Enterprise Number (PEN) + * @return Comp. Func. names if found, NULL else + */ + enum_name_t* (*get_comp_func_names)(pts_component_manager_t *this, + pen_t vendor_id); + + /** + * Return the Functional Component Qualifier Type names for a given vendor ID + * + * @param vendor_id Private Enterprise Number (PEN) + * @return Qualifier Type names if found, NULL else + */ + enum_name_t* (*get_qualifier_type_names)(pts_component_manager_t *this, + pen_t vendor_id); + + /** + * Return the Qualifier Type and Flags + * + * @param name Component Functional Name + * @param flags Qualifier Flags as a string in a char buffer + * @return Qualifier Type + */ + u_int8_t (*get_qualifier)(pts_component_manager_t *this, + pts_comp_func_name_t *name, char *flags); + + /** + * Create a PTS Component object from a Functional Component Name object + * + * @param name Component Functional Name + * @param depth Sub-component Depth + * @param pts_db PTS measurement database + * @return Component object if supported, NULL else + */ + pts_component_t* (*create)(pts_component_manager_t *this, + pts_comp_func_name_t *name, u_int32_t depth, + pts_database_t *pts_db); + + /** + * Destroys a pts_component_manager_t object. + */ + void (*destroy)(pts_component_manager_t *this); +}; + +/** + * Create a PA-TNC attribute manager + */ +pts_component_manager_t* pts_component_manager_create(void); + +#endif /** PTS_COMPONENT_MANAGER_H_ @}*/ diff --git a/src/libimcv/pts/components/tcg/tcg_comp_func_name.c b/src/libimcv/pts/components/tcg/tcg_comp_func_name.c new file mode 100644 index 000000000..a70c84e48 --- /dev/null +++ b/src/libimcv/pts/components/tcg/tcg_comp_func_name.c @@ -0,0 +1,48 @@ +/* + * 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 "tcg_comp_func_name.h" + +char pts_tcg_qualifier_flag_names[] = { 'K', 'S' }; + +ENUM_BEGIN(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_UNKNOWN, + PTS_TCG_QUALIFIER_TYPE_TNC, + "Unknown", + "Trusted Platform", + "Operating System", + "Graphical User Interface", + "Application", + "Networking", + "Library", + "TNC Defined Component" +); +ENUM_NEXT(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL, + PTS_TCG_QUALIFIER_TYPE_ALL, + PTS_TCG_QUALIFIER_TYPE_TNC, + "All Matching Components" +); +ENUM_END(pts_tcg_qualifier_type_names, PTS_TCG_QUALIFIER_TYPE_ALL); + +ENUM(pts_tcg_comp_func_names, PTS_TCG_COMP_FUNC_NAME_IGNORE, + PTS_TCG_COMP_FUNC_NAME_OPT_ROMS, + "Ignore", + "CRTM", + "BIOS", + "Platform Extensions", + "Motherboard Firmware", + "Initial Program Loader", + "Option ROMs" +); + diff --git a/src/libimcv/pts/components/tcg/tcg_comp_func_name.h b/src/libimcv/pts/components/tcg/tcg_comp_func_name.h new file mode 100644 index 000000000..9708ad09d --- /dev/null +++ b/src/libimcv/pts/components/tcg/tcg_comp_func_name.h @@ -0,0 +1,98 @@ +/* + * 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 pts_tcg_comp_func_name pts_tcg_comp_func_name + * @{ @ingroup pts + */ + +#ifndef PTS_TCG_COMP_FUNC_NAME_H_ +#define PTS_TCG_COMP_FUNC_NAME_H_ + +typedef enum pts_tcg_qualifier_type_t pts_tcg_qualifier_type_t; +typedef enum pts_tcg_comp_func_name_t pts_tcp_comp_func_name_t; + +#include <library.h> + +/** + * PTS Component Functional Name Qualifier Flags for the TCG namespace + * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification + * + * 0 1 2 3 4 5 + * +-+-+-+-+-+-+ + * |K|S| Type | + * +-+-+-+-+-+-+ + */ +#define PTS_TCG_QUALIFIER_FLAG_KERNEL (1<<5) +#define PTS_TCG_QUALIFIER_FLAG_SUB (1<<4) + +extern char pts_tcg_qualifier_flag_names[]; + +/** + * Size of the PTS Component Functional Name Qualifier Type field + */ +#define PTS_TCG_QUALIFIER_TYPE_SIZE 4 + +/** + * PTS Component Functional Name Qualifier Types for the TCG namespace + * see section 5.2 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_tcg_qualifier_type_t { + /** Unknown */ + PTS_TCG_QUALIFIER_TYPE_UNKNOWN = 0x0, + /** Trusted Platform */ + PTS_TCG_QUALIFIER_TYPE_TRUSTED = 0x1, + /** Operating System */ + PTS_TCG_QUALIFIER_TYPE_OS = 0x2, + /** Graphical User Interface */ + PTS_TCG_QUALIFIER_TYPE_GUI = 0x3, + /** Application */ + PTS_TCG_QUALIFIER_TYPE_APP = 0x4, + /** Networking */ + PTS_TCG_QUALIFIER_TYPE_NET = 0x5, + /** Library */ + PTS_TCG_QUALIFIER_TYPE_LIB = 0x6, + /** TNC Defined Component */ + PTS_TCG_QUALIFIER_TYPE_TNC = 0x7, + /** All matching Components */ + PTS_TCG_QUALIFIER_TYPE_ALL = 0xF, +}; + +extern enum_name_t *pts_tcg_qualifier_type_names; + +/** + * PTS Component Functional Name Binary Enumeration for the TCG namespace + * see section 5.3 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_tcg_comp_func_name_t { + /** Ignore */ + PTS_TCG_COMP_FUNC_NAME_IGNORE = 0x0000, + /** CRTM */ + PTS_TCG_COMP_FUNC_NAME_CRTM = 0x0001, + /** BIOS */ + PTS_TCG_COMP_FUNC_NAME_BIOS = 0x0002, + /** Platform Extensions */ + PTS_TCG_COMP_FUNC_NAME_PLATFORM_EXT = 0x0003, + /** Motherboard Firmware */ + PTS_TCG_COMP_FUNC_NAME_BOARD = 0x0004, + /** Initial Program Loader */ + PTS_TCG_COMP_FUNC_NAME_INIT_LOADER = 0x0005, + /** Option ROMs */ + PTS_TCG_COMP_FUNC_NAME_OPT_ROMS = 0x0006, +}; + +extern enum_name_t *pts_tcg_comp_func_names; + +#endif /** PTS_TCG_COMP_FUNC_NAME_H_ @}*/ diff --git a/src/libimcv/pts/pts.c b/src/libimcv/pts/pts.c new file mode 100644 index 000000000..2fff4c901 --- /dev/null +++ b/src/libimcv/pts/pts.c @@ -0,0 +1,1198 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2012-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pts.h" + +#include <utils/debug.h> +#include <crypto/hashers/hasher.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> + +#ifdef TSS_TROUSERS +#ifdef _BASETSD_H_ +/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */ +# define _BASETSD_H +#endif +#include <trousers/tss.h> +#include <trousers/trousers.h> +#else +#ifndef TPM_TAG_QUOTE_INFO2 +#define TPM_TAG_QUOTE_INFO2 0x0036 +#endif +#ifndef TPM_LOC_ZERO +#define TPM_LOC_ZERO 0x01 +#endif +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <libgen.h> +#include <unistd.h> +#include <errno.h> + +typedef struct private_pts_t private_pts_t; + +/** + * Private data of a pts_t object. + * + */ +struct private_pts_t { + + /** + * Public pts_t interface. + */ + pts_t public; + + /** + * PTS Protocol Capabilities + */ + pts_proto_caps_flag_t proto_caps; + + /** + * PTS Measurement Algorithm + */ + pts_meas_algorithms_t algorithm; + + /** + * DH Hash Algorithm + */ + pts_meas_algorithms_t dh_hash_algorithm; + + /** + * PTS Diffie-Hellman Secret + */ + diffie_hellman_t *dh; + + /** + * PTS Diffie-Hellman Initiator Nonce + */ + chunk_t initiator_nonce; + + /** + * PTS Diffie-Hellman Responder Nonce + */ + chunk_t responder_nonce; + + /** + * Secret assessment value to be used for TPM Quote as an external data + */ + chunk_t secret; + + /** + * Primary key of platform entry in database + */ + int platform_id; + + /** + * TRUE if IMC-PTS, FALSE if IMV-PTS + */ + bool is_imc; + + /** + * Do we have an activated TPM + */ + bool has_tpm; + + /** + * Contains a TPM_CAP_VERSION_INFO struct + */ + chunk_t tpm_version_info; + + /** + * Contains TSS Blob structure for AIK + */ + chunk_t aik_blob; + + /** + * Contains a Attestation Identity Key or Certificate + */ + certificate_t *aik; + + /** + * Primary key referening AIK in database + */ + int aik_id; + + /** + * Shadow PCR set + */ + pts_pcr_t *pcrs; + +}; + +METHOD(pts_t, get_proto_caps, pts_proto_caps_flag_t, + private_pts_t *this) +{ + return this->proto_caps; +} + +METHOD(pts_t, set_proto_caps, void, + private_pts_t *this, pts_proto_caps_flag_t flags) +{ + this->proto_caps = flags; + DBG2(DBG_PTS, "supported PTS protocol capabilities: %s%s%s%s%s", + flags & PTS_PROTO_CAPS_C ? "C" : ".", + flags & PTS_PROTO_CAPS_V ? "V" : ".", + flags & PTS_PROTO_CAPS_D ? "D" : ".", + flags & PTS_PROTO_CAPS_T ? "T" : ".", + flags & PTS_PROTO_CAPS_X ? "X" : "."); +} + +METHOD(pts_t, get_meas_algorithm, pts_meas_algorithms_t, + private_pts_t *this) +{ + return this->algorithm; +} + +METHOD(pts_t, set_meas_algorithm, void, + private_pts_t *this, pts_meas_algorithms_t algorithm) +{ + hash_algorithm_t hash_alg; + + hash_alg = pts_meas_algo_to_hash(algorithm); + DBG2(DBG_PTS, "selected PTS measurement algorithm is %N", + hash_algorithm_names, hash_alg); + if (hash_alg != HASH_UNKNOWN) + { + this->algorithm = algorithm; + } +} + +METHOD(pts_t, get_dh_hash_algorithm, pts_meas_algorithms_t, + private_pts_t *this) +{ + return this->dh_hash_algorithm; +} + +METHOD(pts_t, set_dh_hash_algorithm, void, + private_pts_t *this, pts_meas_algorithms_t algorithm) +{ + hash_algorithm_t hash_alg; + + hash_alg = pts_meas_algo_to_hash(algorithm); + DBG2(DBG_PTS, "selected DH hash algorithm is %N", + hash_algorithm_names, hash_alg); + if (hash_alg != HASH_UNKNOWN) + { + this->dh_hash_algorithm = algorithm; + } +} + + +METHOD(pts_t, create_dh_nonce, bool, + private_pts_t *this, pts_dh_group_t group, int nonce_len) +{ + diffie_hellman_group_t dh_group; + chunk_t *nonce; + rng_t *rng; + + dh_group = pts_dh_group_to_ike(group); + DBG2(DBG_PTS, "selected PTS DH group is %N", + diffie_hellman_group_names, dh_group); + DESTROY_IF(this->dh); + this->dh = lib->crypto->create_dh(lib->crypto, dh_group); + + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + if (!rng) + { + DBG1(DBG_PTS, "no rng available"); + return FALSE; + } + DBG2(DBG_PTS, "nonce length is %d", nonce_len); + nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce; + chunk_free(nonce); + if (!rng->allocate_bytes(rng, nonce_len, nonce)) + { + DBG1(DBG_PTS, "failed to allocate nonce"); + rng->destroy(rng); + return FALSE; + } + rng->destroy(rng); + return TRUE; +} + +METHOD(pts_t, get_my_public_value, void, + private_pts_t *this, chunk_t *value, chunk_t *nonce) +{ + this->dh->get_my_public_value(this->dh, value); + *nonce = this->is_imc ? this->responder_nonce : this->initiator_nonce; +} + +METHOD(pts_t, set_peer_public_value, void, + private_pts_t *this, chunk_t value, chunk_t nonce) +{ + this->dh->set_other_public_value(this->dh, value); + + nonce = chunk_clone(nonce); + if (this->is_imc) + { + this->initiator_nonce = nonce; + } + else + { + this->responder_nonce = nonce; + } +} + +METHOD(pts_t, calculate_secret, bool, + private_pts_t *this) +{ + hasher_t *hasher; + hash_algorithm_t hash_alg; + chunk_t shared_secret; + + /* Check presence of nonces */ + if (!this->initiator_nonce.len || !this->responder_nonce.len) + { + DBG1(DBG_PTS, "initiator and/or responder nonce is not available"); + return FALSE; + } + DBG3(DBG_PTS, "initiator nonce: %B", &this->initiator_nonce); + DBG3(DBG_PTS, "responder nonce: %B", &this->responder_nonce); + + /* Calculate the DH secret */ + if (this->dh->get_shared_secret(this->dh, &shared_secret) != SUCCESS) + { + DBG1(DBG_PTS, "shared DH secret computation failed"); + return FALSE; + } + DBG3(DBG_PTS, "shared DH secret: %B", &shared_secret); + + /* Calculate the secret assessment value */ + hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + + if (!hasher || + !hasher->get_hash(hasher, chunk_from_chars('1'), NULL) || + !hasher->get_hash(hasher, this->initiator_nonce, NULL) || + !hasher->get_hash(hasher, this->responder_nonce, NULL) || + !hasher->allocate_hash(hasher, shared_secret, &this->secret)) + { + DESTROY_IF(hasher); + return FALSE; + } + hasher->destroy(hasher); + + /* The DH secret must be destroyed */ + chunk_clear(&shared_secret); + + /* + * Truncate the hash to 20 bytes to fit the ExternalData + * argument of the TPM Quote command + */ + this->secret.len = min(this->secret.len, 20); + DBG3(DBG_PTS, "secret assessment value: %B", &this->secret); + return TRUE; +} + +#ifdef TSS_TROUSERS + +/** + * Print TPM 1.2 Version Info + */ +static void print_tpm_version_info(private_pts_t *this) +{ + TPM_CAP_VERSION_INFO *info; + + info = (TPM_CAP_VERSION_INFO*)this->tpm_version_info.ptr; + + if (this->tpm_version_info.len >= + sizeof(*info) - sizeof(info->vendorSpecific)) + { + DBG2(DBG_PTS, "TPM Version Info: Chip Version: %u.%u.%u.%u, " + "Spec Level: %u, Errata Rev: %u, Vendor ID: %.4s", + info->version.major, info->version.minor, + info->version.revMajor, info->version.revMinor, + untoh16(&info->specLevel), info->errataRev, info->tpmVendorID); + } + else + { + DBG1(DBG_PTS, "could not parse tpm version info"); + } +} + +#else + +static void print_tpm_version_info(private_pts_t *this) +{ + DBG1(DBG_PTS, "unknown TPM version: no TSS implementation available"); +} + +#endif /* TSS_TROUSERS */ + +METHOD(pts_t, get_platform_id, int, + private_pts_t *this) +{ + return this->platform_id; +} + +METHOD(pts_t, set_platform_id, void, + private_pts_t *this, int pid) +{ + this->platform_id = pid; +} + +METHOD(pts_t, get_tpm_version_info, bool, + private_pts_t *this, chunk_t *info) +{ + if (!this->has_tpm) + { + return FALSE; + } + *info = this->tpm_version_info; + print_tpm_version_info(this); + return TRUE; +} + +METHOD(pts_t, set_tpm_version_info, void, + private_pts_t *this, chunk_t info) +{ + this->tpm_version_info = chunk_clone(info); + print_tpm_version_info(this); +} + +/** + * Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute) + */ +static void load_aik_blob(private_pts_t *this) +{ + char *path; + chunk_t *map; + + path = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.aik_blob", NULL, lib->ns); + if (path) + { + map = chunk_map(path, FALSE); + if (map) + { + DBG2(DBG_PTS, "loaded AIK Blob from '%s'", path); + DBG3(DBG_PTS, "AIK Blob: %B", map); + this->aik_blob = chunk_clone(*map); + chunk_unmap(map); + } + else + { + DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s", + path, strerror(errno)); + } + } + else + { + DBG1(DBG_PTS, "AIK Blob is not available"); + } +} + +/** + * Load an AIK certificate or public key + * the certificate having precedence over the public key if both are present + */ +static void load_aik(private_pts_t *this) +{ + char *cert_path, *key_path; + + cert_path = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.aik_cert", NULL, lib->ns); + key_path = lib->settings->get_str(lib->settings, + "%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns); + + if (cert_path) + { + this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_X509, BUILD_FROM_FILE, + cert_path, BUILD_END); + if (this->aik) + { + DBG2(DBG_PTS, "loaded AIK certificate from '%s'", cert_path); + return; + } + } + if (key_path) + { + this->aik = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE, + key_path, BUILD_END); + if (this->aik) + { + DBG2(DBG_PTS, "loaded AIK public key from '%s'", key_path); + return; + } + } + + DBG1(DBG_PTS, "neither AIK certificate nor public key is available"); +} + +METHOD(pts_t, get_aik, certificate_t*, + private_pts_t *this) +{ + return this->aik; +} + +METHOD(pts_t, set_aik, void, + private_pts_t *this, certificate_t *aik, int aik_id) +{ + DESTROY_IF(this->aik); + this->aik = aik->get_ref(aik); + this->aik_id = aik_id; +} + +METHOD(pts_t, get_aik_id, int, + private_pts_t *this) +{ + return this->aik_id; +} + +METHOD(pts_t, is_path_valid, bool, + private_pts_t *this, char *path, pts_error_code_t *error_code) +{ + struct stat st; + + *error_code = 0; + + if (!stat(path, &st)) + { + return TRUE; + } + else if (errno == ENOENT || errno == ENOTDIR) + { + DBG1(DBG_PTS, "file/directory does not exist %s", path); + *error_code = TCG_PTS_FILE_NOT_FOUND; + } + else if (errno == EFAULT) + { + DBG1(DBG_PTS, "bad address %s", path); + *error_code = TCG_PTS_INVALID_PATH; + } + else + { + DBG1(DBG_PTS, "error: %s occurred while validating path: %s", + strerror(errno), path); + return FALSE; + } + + return TRUE; +} + +/** + * Obtain statistical information describing a file + */ +static bool file_metadata(char *pathname, pts_file_metadata_t **entry) +{ + struct stat st; + pts_file_metadata_t *this; + + this = malloc_thing(pts_file_metadata_t); + + if (stat(pathname, &st)) + { + DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname); + free(this); + return FALSE; + } + + if (S_ISREG(st.st_mode)) + { + this->type = PTS_FILE_REGULAR; + } + else if (S_ISDIR(st.st_mode)) + { + this->type = PTS_FILE_DIRECTORY; + } + else if (S_ISCHR(st.st_mode)) + { + this->type = PTS_FILE_CHAR_SPEC; + } + else if (S_ISBLK(st.st_mode)) + { + this->type = PTS_FILE_BLOCK_SPEC; + } + else if (S_ISFIFO(st.st_mode)) + { + this->type = PTS_FILE_FIFO; + } +#ifndef WIN32 + else if (S_ISLNK(st.st_mode)) + { + this->type = PTS_FILE_SYM_LINK; + } + else if (S_ISSOCK(st.st_mode)) + { + this->type = PTS_FILE_SOCKET; + } +#endif /* WIN32 */ + else + { + this->type = PTS_FILE_OTHER; + } + + this->filesize = st.st_size; + this->created = st.st_ctime; + this->modified = st.st_mtime; + this->accessed = st.st_atime; + this->owner = st.st_uid; + this->group = st.st_gid; + + *entry = this; + return TRUE; +} + +METHOD(pts_t, get_metadata, pts_file_meta_t*, + private_pts_t *this, char *pathname, bool is_directory) +{ + pts_file_meta_t *metadata; + pts_file_metadata_t *entry; + + /* Create a metadata object */ + metadata = pts_file_meta_create(); + + if (is_directory) + { + enumerator_t *enumerator; + char *rel_name, *abs_name; + struct stat st; + + enumerator = enumerator_create_directory(pathname); + if (!enumerator) + { + DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname, + strerror(errno)); + metadata->destroy(metadata); + return NULL; + } + while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st)) + { + /* measure regular files only */ + if (S_ISREG(st.st_mode) && *rel_name != '.') + { + if (!file_metadata(abs_name, &entry)) + { + enumerator->destroy(enumerator); + metadata->destroy(metadata); + return NULL; + } + entry->filename = strdup(rel_name); + metadata->add(metadata, entry); + } + } + enumerator->destroy(enumerator); + } + else + { + if (!file_metadata(pathname, &entry)) + { + metadata->destroy(metadata); + return NULL; + } + entry->filename = path_basename(pathname); + metadata->add(metadata, entry); + } + + return metadata; +} + + +#ifdef TSS_TROUSERS + +METHOD(pts_t, read_pcr, bool, + private_pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value) +{ + TSS_HCONTEXT hContext; + TSS_HTPM hTPM; + TSS_RESULT result; + BYTE *buf; + UINT32 len; + + bool success = FALSE; + + result = Tspi_Context_Create(&hContext); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", result); + return FALSE; + } + + result = Tspi_Context_Connect(hContext, NULL); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_Context_GetTpmObject (hContext, &hTPM); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_TPM_PcrRead(hTPM, pcr_num, &len, &buf); + if (result != TSS_SUCCESS) + { + goto err; + } + *pcr_value = chunk_clone(chunk_create(buf, len)); + DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, pcr_value); + success = TRUE; + +err: + if (!success) + { + DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + } + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + + return success; +} + +METHOD(pts_t, extend_pcr, bool, + private_pts_t *this, u_int32_t pcr_num, chunk_t input, chunk_t *output) +{ + TSS_HCONTEXT hContext; + TSS_HTPM hTPM; + TSS_RESULT result; + u_int32_t pcr_length; + chunk_t pcr_value = chunk_empty; + + result = Tspi_Context_Create(&hContext); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", + result); + return FALSE; + } + result = Tspi_Context_Connect(hContext, NULL); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_Context_GetTpmObject (hContext, &hTPM); + if (result != TSS_SUCCESS) + { + goto err; + } + + pcr_value = chunk_alloc(PTS_PCR_LEN); + result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PTS_PCR_LEN, input.ptr, + NULL, &pcr_length, &pcr_value.ptr); + if (result != TSS_SUCCESS) + { + goto err; + } + + *output = pcr_value; + *output = chunk_clone(*output); + + DBG3(DBG_PTS, "PCR %d extended with: %B", pcr_num, &input); + DBG3(DBG_PTS, "PCR %d value after extend: %B", pcr_num, output); + + chunk_clear(&pcr_value); + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + + return TRUE; + +err: + DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + + chunk_clear(&pcr_value); + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + + return FALSE; +} + +METHOD(pts_t, quote_tpm, bool, + private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig) +{ + TSS_HCONTEXT hContext; + TSS_HTPM hTPM; + TSS_HKEY hAIK; + TSS_HKEY hSRK; + TSS_HPOLICY srkUsagePolicy; + TSS_UUID SRK_UUID = TSS_UUID_SRK; + BYTE secret[] = TSS_WELL_KNOWN_SECRET; + TSS_HPCRS hPcrComposite; + TSS_VALIDATION valData; + TSS_RESULT result; + chunk_t quote_info; + BYTE* versionInfo; + u_int32_t versionInfoSize, pcr; + enumerator_t *enumerator; + bool success = FALSE; + + result = Tspi_Context_Create(&hContext); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", + result); + return FALSE; + } + result = Tspi_Context_Connect(hContext, NULL); + if (result != TSS_SUCCESS) + { + goto err1; + } + result = Tspi_Context_GetTpmObject (hContext, &hTPM); + if (result != TSS_SUCCESS) + { + goto err1; + } + + /* Retrieve SRK from TPM and set the authentication to well known secret*/ + result = Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, + SRK_UUID, &hSRK); + if (result != TSS_SUCCESS) + { + goto err1; + } + + result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy); + if (result != TSS_SUCCESS) + { + goto err1; + } + result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1, + 20, secret); + if (result != TSS_SUCCESS) + { + goto err1; + } + + result = Tspi_Context_LoadKeyByBlob (hContext, hSRK, this->aik_blob.len, + this->aik_blob.ptr, &hAIK); + if (result != TSS_SUCCESS) + { + goto err1; + } + + /* Create PCR composite object */ + result = use_quote2 ? + Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, + TSS_PCRS_STRUCT_INFO_SHORT, &hPcrComposite) : + Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, + TSS_PCRS_STRUCT_DEFAULT, &hPcrComposite); + if (result != TSS_SUCCESS) + { + goto err2; + } + + /* Select PCRs */ + enumerator = this->pcrs->create_enumerator(this->pcrs); + while (enumerator->enumerate(enumerator, &pcr)) + { + result = use_quote2 ? + Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr, + TSS_PCRS_DIRECTION_RELEASE) : + Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr); + if (result != TSS_SUCCESS) + { + break; + } + } + enumerator->destroy(enumerator); + + if (result != TSS_SUCCESS) + { + goto err3; + } + + /* Set the Validation Data */ + valData.ulExternalDataLength = this->secret.len; + valData.rgbExternalData = (BYTE *)this->secret.ptr; + + + /* TPM Quote */ + result = use_quote2 ? + Tspi_TPM_Quote2(hTPM, hAIK, FALSE, hPcrComposite, &valData, + &versionInfoSize, &versionInfo): + Tspi_TPM_Quote(hTPM, hAIK, hPcrComposite, &valData); + if (result != TSS_SUCCESS) + { + goto err4; + } + + /* Set output chunks */ + *pcr_comp = chunk_alloc(HASH_SIZE_SHA1); + + if (use_quote2) + { + /* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */ + memcpy(pcr_comp->ptr, valData.rgbData + valData.ulDataLength - HASH_SIZE_SHA1, + HASH_SIZE_SHA1); + } + else + { + /* TPM_Composite_Hash is 8-28th bytes of TPM_Quote_Info structure */ + memcpy(pcr_comp->ptr, valData.rgbData + 8, HASH_SIZE_SHA1); + } + DBG3(DBG_PTS, "Hash of PCR Composite: %#B", pcr_comp); + + quote_info = chunk_create(valData.rgbData, valData.ulDataLength); + DBG3(DBG_PTS, "TPM Quote Info: %B","e_info); + + *quote_sig = chunk_clone(chunk_create(valData.rgbValidationData, + valData.ulValidationDataLength)); + DBG3(DBG_PTS, "TPM Quote Signature: %B",quote_sig); + + success = TRUE; + + /* Cleanup */ +err4: + Tspi_Context_FreeMemory(hContext, NULL); + +err3: + Tspi_Context_CloseObject(hContext, hPcrComposite); + +err2: + Tspi_Context_CloseObject(hContext, hAIK); + +err1: + Tspi_Context_Close(hContext); + if (!success) + { + DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + } + return success; +} + +#else /* TSS_TROUSERS */ + +METHOD(pts_t, read_pcr, bool, + private_pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value) +{ + return FALSE; +} + +METHOD(pts_t, extend_pcr, bool, + private_pts_t *this, u_int32_t pcr_num, chunk_t input, chunk_t *output) +{ + return FALSE; +} + +METHOD(pts_t, quote_tpm, bool, + private_pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig) +{ + return FALSE; +} + +#endif /* TSS_TROUSERS */ + +/** + * TPM_QUOTE_INFO structure: + * 4 bytes of version + * 4 bytes 'Q' 'U' 'O' 'T' + * 20 byte SHA1 of TCPA_PCR_COMPOSITE + * 20 byte nonce + * + * TPM_QUOTE_INFO2 structure: + * 2 bytes Tag 0x0036 TPM_Tag_Quote_info2 + * 4 bytes 'Q' 'U' 'T' '2' + * 20 bytes nonce + * 26 bytes PCR_INFO_SHORT + */ + +METHOD(pts_t, get_quote_info, bool, + private_pts_t *this, bool use_quote2, bool use_ver_info, + pts_meas_algorithms_t comp_hash_algo, + chunk_t *out_pcr_comp, chunk_t *out_quote_info) +{ + chunk_t selection, pcr_comp, hash_pcr_comp; + bio_writer_t *writer; + hasher_t *hasher; + + if (!this->pcrs->get_count(this->pcrs)) + { + DBG1(DBG_PTS, "No extended PCR entries available, " + "unable to construct TPM Quote Info"); + return FALSE; + } + if (!this->secret.ptr) + { + DBG1(DBG_PTS, "Secret assessment value unavailable, ", + "unable to construct TPM Quote Info"); + return FALSE; + } + if (use_quote2 && use_ver_info && !this->tpm_version_info.ptr) + { + DBG1(DBG_PTS, "TPM Version Information unavailable, ", + "unable to construct TPM Quote Info2"); + return FALSE; + } + + pcr_comp = this->pcrs->get_composite(this->pcrs); + + + /* Output the TPM_PCR_COMPOSITE expected from IMC */ + if (comp_hash_algo) + { + hash_algorithm_t algo; + + algo = pts_meas_algo_to_hash(comp_hash_algo); + hasher = lib->crypto->create_hasher(lib->crypto, algo); + + /* Hash the PCR Composite Structure */ + if (!hasher || !hasher->allocate_hash(hasher, pcr_comp, out_pcr_comp)) + { + DESTROY_IF(hasher); + free(pcr_comp.ptr); + return FALSE; + } + DBG3(DBG_PTS, "constructed PCR Composite hash: %#B", out_pcr_comp); + hasher->destroy(hasher); + } + else + { + *out_pcr_comp = chunk_clone(pcr_comp); + } + + /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */ + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher || !hasher->allocate_hash(hasher, pcr_comp, &hash_pcr_comp)) + { + DESTROY_IF(hasher); + chunk_free(out_pcr_comp); + free(pcr_comp.ptr); + return FALSE; + } + hasher->destroy(hasher); + + /* Construct TPM_QUOTE_INFO/TPM_QUOTE_INFO2 structure */ + writer = bio_writer_create(TPM_QUOTE_INFO_LEN); + + if (use_quote2) + { + /* TPM Structure Tag */ + writer->write_uint16(writer, TPM_TAG_QUOTE_INFO2); + + /* Magic QUT2 value */ + writer->write_data(writer, chunk_create("QUT2", 4)); + + /* Secret assessment value 20 bytes (nonce) */ + writer->write_data(writer, this->secret); + + /* PCR selection */ + selection.ptr = pcr_comp.ptr; + selection.len = 2 + this->pcrs->get_selection_size(this->pcrs); + writer->write_data(writer, selection); + + /* TPM Locality Selection */ + writer->write_uint8(writer, TPM_LOC_ZERO); + + /* PCR Composite Hash */ + writer->write_data(writer, hash_pcr_comp); + + if (use_ver_info) + { + /* TPM version Info */ + writer->write_data(writer, this->tpm_version_info); + } + } + else + { + /* Version number */ + writer->write_data(writer, chunk_from_chars(1, 1, 0, 0)); + + /* Magic QUOT value */ + writer->write_data(writer, chunk_create("QUOT", 4)); + + /* PCR Composite Hash */ + writer->write_data(writer, hash_pcr_comp); + + /* Secret assessment value 20 bytes (nonce) */ + writer->write_data(writer, this->secret); + } + + /* TPM Quote Info */ + *out_quote_info = writer->extract_buf(writer); + DBG3(DBG_PTS, "constructed TPM Quote Info: %B", out_quote_info); + + writer->destroy(writer); + free(pcr_comp.ptr); + free(hash_pcr_comp.ptr); + + return TRUE; +} + +METHOD(pts_t, verify_quote_signature, bool, + private_pts_t *this, chunk_t data, chunk_t signature) +{ + public_key_t *aik_pub_key; + + aik_pub_key = this->aik->get_public_key(this->aik); + if (!aik_pub_key) + { + DBG1(DBG_PTS, "failed to get public key from AIK certificate"); + return FALSE; + } + + if (!aik_pub_key->verify(aik_pub_key, SIGN_RSA_EMSA_PKCS1_SHA1, + data, signature)) + { + DBG1(DBG_PTS, "signature verification failed for TPM Quote Info"); + DESTROY_IF(aik_pub_key); + return FALSE; + } + + aik_pub_key->destroy(aik_pub_key); + return TRUE; +} + +METHOD(pts_t, get_pcrs, pts_pcr_t*, + private_pts_t *this) +{ + return this->pcrs; +} + +METHOD(pts_t, destroy, void, + private_pts_t *this) +{ + DESTROY_IF(this->pcrs); + DESTROY_IF(this->aik); + DESTROY_IF(this->dh); + free(this->initiator_nonce.ptr); + free(this->responder_nonce.ptr); + free(this->secret.ptr); + free(this->aik_blob.ptr); + free(this->tpm_version_info.ptr); + free(this); +} + + +#ifdef TSS_TROUSERS + +/** + * Check for a TPM by querying for TPM Version Info + */ +static bool has_tpm(private_pts_t *this) +{ + TSS_HCONTEXT hContext; + TSS_HTPM hTPM; + TSS_RESULT result; + u_int32_t version_info_len; + + result = Tspi_Context_Create(&hContext); + if (result != TSS_SUCCESS) + { + DBG1(DBG_PTS, "TPM context could not be created: tss error 0x%x", + result); + return FALSE; + } + result = Tspi_Context_Connect(hContext, NULL); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_Context_GetTpmObject (hContext, &hTPM); + if (result != TSS_SUCCESS) + { + goto err; + } + result = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL, + &version_info_len, + &this->tpm_version_info.ptr); + this->tpm_version_info.len = version_info_len; + if (result != TSS_SUCCESS) + { + goto err; + } + this->tpm_version_info = chunk_clone(this->tpm_version_info); + + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + return TRUE; + + err: + DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); + Tspi_Context_FreeMemory(hContext, NULL); + Tspi_Context_Close(hContext); + return FALSE; +} + +#else /* TSS_TROUSERS */ + +static bool has_tpm(private_pts_t *this) +{ + return FALSE; +} + +#endif /* TSS_TROUSERS */ + + +/** + * See header + */ +pts_t *pts_create(bool is_imc) +{ + private_pts_t *this; + pts_pcr_t *pcrs; + + pcrs = pts_pcr_create(); + if (!pcrs) + { + DBG1(DBG_PTS, "shadow PCR set could not be created"); + return NULL; + } + + INIT(this, + .public = { + .get_proto_caps = _get_proto_caps, + .set_proto_caps = _set_proto_caps, + .get_meas_algorithm = _get_meas_algorithm, + .set_meas_algorithm = _set_meas_algorithm, + .get_dh_hash_algorithm = _get_dh_hash_algorithm, + .set_dh_hash_algorithm = _set_dh_hash_algorithm, + .create_dh_nonce = _create_dh_nonce, + .get_my_public_value = _get_my_public_value, + .set_peer_public_value = _set_peer_public_value, + .calculate_secret = _calculate_secret, + .get_platform_id = _get_platform_id, + .set_platform_id = _set_platform_id, + .get_tpm_version_info = _get_tpm_version_info, + .set_tpm_version_info = _set_tpm_version_info, + .get_aik = _get_aik, + .set_aik = _set_aik, + .get_aik_id = _get_aik_id, + .is_path_valid = _is_path_valid, + .get_metadata = _get_metadata, + .read_pcr = _read_pcr, + .extend_pcr = _extend_pcr, + .quote_tpm = _quote_tpm, + .get_pcrs = _get_pcrs, + .get_quote_info = _get_quote_info, + .verify_quote_signature = _verify_quote_signature, + .destroy = _destroy, + }, + .is_imc = is_imc, + .proto_caps = PTS_PROTO_CAPS_V, + .algorithm = PTS_MEAS_ALGO_SHA256, + .dh_hash_algorithm = PTS_MEAS_ALGO_SHA256, + .pcrs = pcrs, + ); + + if (is_imc) + { + if (has_tpm(this)) + { + this->has_tpm = TRUE; + this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D; + load_aik(this); + load_aik_blob(this); + } + } + else + { + this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D; + } + + return &this->public; +} diff --git a/src/libimcv/pts/pts.h b/src/libimcv/pts/pts.h new file mode 100644 index 000000000..be32a3464 --- /dev/null +++ b/src/libimcv/pts/pts.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2012-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts pts + * @{ @ingroup libimcv + */ + +#ifndef PTS_H_ +#define PTS_H_ + +typedef struct pts_t pts_t; + +#include "pts_error.h" +#include "pts_proto_caps.h" +#include "pts_meas_algo.h" +#include "pts_file_meas.h" +#include "pts_file_meta.h" +#include "pts_dh_group.h" +#include "pts_pcr.h" +#include "pts_req_func_comp_evid.h" +#include "pts_simple_evid_final.h" +#include "components/pts_comp_func_name.h" + +#include <library.h> +#include <collections/linked_list.h> + +/** + * UTF-8 encoding of the character used to delimiter the filename + */ +#define SOLIDUS_UTF 0x2F +#define REVERSE_SOLIDUS_UTF 0x5C + +/** + * PCR indices used for measurements of various functional components + */ +#define PCR_BIOS 0 +#define PCR_PLATFORM_EXT 1 +#define PCR_MOTHERBOARD 1 +#define PCR_OPTION_ROMS 2 +#define PCR_IPL 4 + +#define PCR_TBOOT_POLICY 17 +#define PCR_TBOOT_MLE 18 + +#define PCR_TGRUB_MBR_STAGE1 4 +#define PCR_TGRUB_STAGE2_PART1 8 +#define PCR_TGRUB_STAGE2_PART2 9 +#define PCR_TGRUB_CMD_LINE_ARGS 12 +#define PCR_TGRUB_CHECKFILE 13 +#define PCR_TGRUB_LOADED_FILES 14 + +#define PCR_DEBUG 16 + +/** + * Length of the generated nonce used for calculation of shared secret + */ +#define ASSESSMENT_SECRET_LEN 20 + +/** + * Length of the TPM_QUOTE_INFO structure, TPM Spec 1.2 + */ +#define TPM_QUOTE_INFO_LEN 48 + +/** + * Hashing algorithm used by tboot and trustedGRUB + */ +#define TRUSTED_HASH_ALGO PTS_MEAS_ALGO_SHA1 + +/** + * Class implementing the TCG Platform Trust Service (PTS) + * + */ +struct pts_t { + + /** + * Get PTS Protocol Capabilities + * + * @return Protocol capabilities flags + */ + pts_proto_caps_flag_t (*get_proto_caps)(pts_t *this); + + /** + * Set PTS Protocol Capabilities + * + * @param flags Protocol capabilities flags + */ + void (*set_proto_caps)(pts_t *this, pts_proto_caps_flag_t flags); + + /** + * Get PTS Measurement Algorithm + * + * @return PTS measurement algorithm + */ + pts_meas_algorithms_t (*get_meas_algorithm)(pts_t *this); + + /** + * Set PTS Measurement Algorithm + * + * @param algorithm PTS measurement algorithm + */ + void (*set_meas_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm); + + /** + * Get DH Hash Algorithm + * + * @return DH hash algorithm + */ + pts_meas_algorithms_t (*get_dh_hash_algorithm)(pts_t *this); + + /** + * Set DH Hash Algorithm + * + * @param algorithm DH hash algorithm + */ + void (*set_dh_hash_algorithm)(pts_t *this, pts_meas_algorithms_t algorithm); + + /** + * Create PTS Diffie-Hellman object and nonce + * + * @param group PTS DH group + * @param nonce_len Nonce length + * @return TRUE if creation was successful + * + */ + bool (*create_dh_nonce)(pts_t *this, pts_dh_group_t group, int nonce_len); + + /** + * Get my Diffie-Hellman public value + * + * @param value My public DH value + * @param nonce My DH nonce + */ + void (*get_my_public_value)(pts_t *this, chunk_t *value, chunk_t *nonce); + + /** + * Set peer Diffie.Hellman public value + * + * @param value Peer public DH value + * @param nonce Peer DH nonce + */ + void (*set_peer_public_value) (pts_t *this, chunk_t value, chunk_t nonce); + + /** + * Calculates assessment secret to be used for TPM Quote as ExternalData + * + * @return TRUE unless both DH public values + * and nonces are set + */ + bool (*calculate_secret) (pts_t *this); + + /** + * Get primary key of platform entry in database + * + * @return Platform and OS info + */ + int (*get_platform_id)(pts_t *this); + + /** + * Set primary key of platform entry in database + * + * @param pid Primary key of platform entry in database + */ + void (*set_platform_id)(pts_t *this, int pid); + + /** + * Get TPM 1.2 Version Info + * + * @param info chunk containing a TPM_CAP_VERSION_INFO struct + * @return TRUE if TPM Version Info available + */ + bool (*get_tpm_version_info)(pts_t *this, chunk_t *info); + + /** + * Set TPM 1.2 Version Info + * + * @param info chunk containing a TPM_CAP_VERSION_INFO struct + */ + void (*set_tpm_version_info)(pts_t *this, chunk_t info); + + /** + * Get Attestation Identity Certificate or Public Key + * + * @return AIK Certificate or Public Key + */ + certificate_t* (*get_aik)(pts_t *this); + + /** + * Set Attestation Identity Certificate or Public Key + * + * @param aik AIK Certificate or Public Key + * @param aik_id Primary key referencing AIK in database + */ + void (*set_aik)(pts_t *this, certificate_t *aik, int aik_id); + + /** + * Get primary key referencing AIK in database + * + * @return Primary key referencing AIK in database + */ + int (*get_aik_id)(pts_t *this); + + /** + * Check whether path is valid file/directory on filesystem + * + * @param path Absolute path + * @param error_code Output variable for PTS error code + * @return TRUE if path is valid or file/directory + * doesn't exist or path is invalid + * FALSE if local error occurred within stat function + */ + bool (*is_path_valid)(pts_t *this, char *path, pts_error_code_t *error_code); + + /** + * Obtain file metadata + * + * @param pathname Absolute pathname of file/directory + * @param is_dir TRUE if directory contents are requested + * @return PTS File Metadata or NULL if FAILED + */ + pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir); + + /** + * Reads given PCR value and returns it + * Expects owner secret to be WELL_KNOWN_SECRET + * + * @param pcr_num Number of PCR to read + * @param pcr_value Chunk to save pcr read output + * @return NULL in case of TSS error, PCR value otherwise + */ + bool (*read_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value); + + /** + * Extends given PCR with given value + * Expects owner secret to be WELL_KNOWN_SECRET + * + * @param pcr_num Number of PCR to extend + * @param input Value to extend + * @param output Chunk to save PCR value after extension + * @return FALSE in case of TSS error, TRUE otherwise + */ + bool (*extend_pcr)(pts_t *this, u_int32_t pcr_num, chunk_t input, + chunk_t *output); + + /** + * Quote over PCR's + * Expects owner and SRK secret to be WELL_KNOWN_SECRET and no password set for AIK + * + * @param use_quote2 Version of the Quote function to be used + * @param pcr_comp Chunk to save PCR composite structure + * @param quote_sig Chunk to save quote operation output + * without external data (anti-replay protection) + * @return FALSE in case of TSS error, TRUE otherwise + */ + bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp, + chunk_t *quote_sig); + + /** + * Get the shadow PCR set + * + * @return shadow PCR set + */ + pts_pcr_t* (*get_pcrs)(pts_t *this); + + /** + * Constructs and returns TPM Quote Info structure expected from IMC + * + * @param use_quote2 Version of the TPM_QUOTE_INFO to be constructed + * @param use_ver_info Version info is concatenated to TPM_QUOTE_INFO2 + * @param comp_hash_algo Composite Hash Algorithm + * @param pcr_comp Output variable to store PCR Composite + * @param quote_info Output variable to store TPM Quote Info + * @return FALSE in case of any error, TRUE otherwise + */ + bool (*get_quote_info)(pts_t *this, bool use_quote2, bool ver_info_included, + pts_meas_algorithms_t comp_hash_algo, + chunk_t *pcr_comp, chunk_t *quote_info); + + /** + * Constructs and returns PCR Quote Digest structure expected from IMC + * + * @param data Calculated TPM Quote Digest + * @param signature TPM Quote Signature received from IMC + * @return FALSE if signature is not verified + */ + bool (*verify_quote_signature)(pts_t *this, chunk_t data, chunk_t signature); + + /** + * Destroys a pts_t object. + */ + void (*destroy)(pts_t *this); + +}; + +/** + * Creates an pts_t object + * + * @param is_imc TRUE if running on an IMC + */ +pts_t* pts_create(bool is_imc); + +#endif /** PTS_H_ @}*/ diff --git a/src/libimcv/pts/pts_creds.c b/src/libimcv/pts/pts_creds.c new file mode 100644 index 000000000..bc483eb84 --- /dev/null +++ b/src/libimcv/pts/pts_creds.c @@ -0,0 +1,136 @@ +/* + * 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 "pts_creds.h" + +#include <utils/debug.h> +#include <credentials/certificates/x509.h> +#include <credentials/sets/mem_cred.h> + +#include <sys/stat.h> + +typedef struct private_pts_creds_t private_pts_creds_t; + +/** + * Private data of a pts_creds_t object. + * + */ +struct private_pts_creds_t { + + /** + * Public pts_creds_t interface. + */ + pts_creds_t public; + + /** + * Credential set + */ + mem_cred_t *creds; + +}; + +METHOD(pts_creds_t, get_set, credential_set_t*, + private_pts_creds_t *this) +{ + return &this->creds->set; +} + + +METHOD(pts_creds_t, destroy, void, + private_pts_creds_t *this) +{ + this->creds->destroy(this->creds); + free(this); +} + +/** + * Load trusted PTS CA certificates from a directory + */ +static void load_cacerts(private_pts_creds_t *this, char *path) +{ + enumerator_t *enumerator; + struct stat st; + char *file; + + DBG1(DBG_PTS, "loading PTS ca certificates from '%s'", path); + + enumerator = enumerator_create_directory(path); + if (!enumerator) + { + return; + } + + while (enumerator->enumerate(enumerator, NULL, &file, &st)) + { + certificate_t *cert; + + if (!S_ISREG(st.st_mode)) + { + /* skip special file */ + continue; + } + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, file, BUILD_END); + if (cert) + { + x509_t *x509 = (x509_t*)cert; + + if (!(x509->get_flags(x509) & X509_CA)) + { + DBG1(DBG_PTS, " ca certificate \"%Y\" lacks ca basic constraint" + ", discarded", cert->get_subject(cert)); + cert->destroy(cert); + } + else + { + DBG1(DBG_PTS, " loaded ca certificate \"%Y\" from '%s'", + cert->get_subject(cert), file); + this->creds->add_cert(this->creds, TRUE, cert); + } + } + else + { + DBG1(DBG_PTS, " loading ca certificate from '%s' failed", file); + } + } + enumerator->destroy(enumerator); +} + +/** + * See header + */ +pts_creds_t *pts_creds_create(char *path) +{ + private_pts_creds_t *this; + + if (!path) + { + DBG1(DBG_PTS, "no PTS cacerts directory defined"); + return NULL; + } + + INIT(this, + .public = { + .get_set = _get_set, + .destroy = _destroy, + }, + .creds = mem_cred_create(), + ); + + load_cacerts(this, path); + + return &this->public; +} + diff --git a/src/libimcv/pts/pts_creds.h b/src/libimcv/pts/pts_creds.h new file mode 100644 index 000000000..eb9c39537 --- /dev/null +++ b/src/libimcv/pts/pts_creds.h @@ -0,0 +1,55 @@ +/* + * 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 pts_creds pts_creds + * @{ @ingroup pts + */ + +#ifndef PTS_CREDS_H_ +#define PTS_CREDS_H_ + +typedef struct pts_creds_t pts_creds_t; + +#include <library.h> +#include <credentials/credential_set.h> + +/** + * Class implementing a PTS credentials set + */ +struct pts_creds_t { + + /** + * Get the credential set + * + * @return credential set + */ + credential_set_t* (*get_set)(pts_creds_t *this); + + /** + * Destroys a pts_creds_t object. + */ + void (*destroy)(pts_creds_t *this); + +}; + +/** + * Creates an pts_creds_t object + * + * @param path path to the PTS cacerts directory + */ +pts_creds_t* pts_creds_create(char *path); + +#endif /** PTS_CREDS_H_ @}*/ diff --git a/src/libimcv/pts/pts_database.c b/src/libimcv/pts/pts_database.c new file mode 100644 index 000000000..d7b85c138 --- /dev/null +++ b/src/libimcv/pts/pts_database.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2011-2012 Sansar Choinyambuu + * Copyright (C) 2012-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <libgen.h> + +#include "pts_database.h" + +#include <utils/debug.h> +#include <crypto/hashers/hasher.h> + + +typedef struct private_pts_database_t private_pts_database_t; + +/** + * Private data of a pts_database_t object. + * + */ +struct private_pts_database_t { + + /** + * Public pts_database_t interface. + */ + pts_database_t public; + + /** + * database instance + */ + database_t *db; + +}; + +METHOD(pts_database_t, get_pathname, char*, + private_pts_database_t *this, bool is_dir, int id) +{ + enumerator_t *e; + char *path, *name, *sep, *pathname = NULL; + + if (is_dir) + { + e = this->db->query(this->db, + "SELECT path FROM directories WHERE id = ?", + DB_INT, id, DB_TEXT); + if (!e || !e->enumerate(e, &path)) + { + pathname = NULL; + } + else + { + pathname = strdup(path); + } + } + else + { + e = this->db->query(this->db, + "SELECT d.path, f.name FROM files AS f " + "JOIN directories AS d ON d.id = f.dir WHERE f.id = ?", + DB_INT, id, DB_TEXT, DB_TEXT); + if (e && e->enumerate(e, &path, &name)) + { + if (path[0] == '/') + { /* Unix style absolute path */ + sep = "/"; + } + else + { /* Windows absolute path */ + sep = "\\"; + } + if (asprintf(&pathname, "%s%s%s", + path, streq(path, "/") ? "" : sep, name) == -1) + { + pathname = NULL; + } + } + } + DESTROY_IF(e); + + return pathname; +} + +METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, + private_pts_database_t *this, int pid, pts_meas_algorithms_t algo, + bool is_dir, int id) +{ + enumerator_t *e; + + if (is_dir) + { + e = this->db->query(this->db, + "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "JOIN directories as d ON d.id = f.dir " + "WHERE fh.product = ? AND fh.algo = ? AND d.id = ? " + "ORDER BY f.name", + DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB); + } + else + { + e = this->db->query(this->db, + "SELECT f.id, f.name, fh.hash FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?", + DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB); + } + return e; +} + +METHOD(pts_database_t, add_file_measurement, status_t, + private_pts_database_t *this, int pid, pts_meas_algorithms_t algo, + chunk_t measurement, char *filename, bool is_dir, int id) +{ + enumerator_t *e; + char *name; + chunk_t hash_value; + int hash_id, fid; + status_t status = SUCCESS; + + if (is_dir) + { + /* does filename entry already exist? */ + e = this->db->query(this->db, + "SELECT id FROM files WHERE name = ? AND dir = ?", + DB_TEXT, filename, DB_INT, id, DB_INT); + if (!e) + { + return FAILED; + } + if (!e->enumerate(e, &fid)) + { + /* create filename entry */ + if (this->db->execute(this->db, &fid, + "INSERT INTO files (name, dir) VALUES (?, ?)", + DB_TEXT, filename, DB_INT, id) != 1) + { + DBG1(DBG_PTS, "could not insert filename into database"); + status = FAILED; + } + } + e->destroy(e); + } + else + { + fid = id; + + /* verify filename */ + e = this->db->query(this->db, + "SELECT name FROM files WHERE id = ?", DB_INT, fid, DB_TEXT); + if (!e) + { + return FAILED; + } + if (!e->enumerate(e, &name) || !streq(name, filename)) + { + DBG1(DBG_PTS, "filename of reference measurement does not match"); + status = FAILED; + } + e->destroy(e); + } + + if (status != SUCCESS) + { + return status; + } + + /* does hash measurement value already exist? */ + e = this->db->query(this->db, + "SELECT fh.id, fh.hash FROM file_hashes AS fh " + "WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?", + DB_INT, pid, DB_INT, algo, DB_INT, fid, DB_INT, DB_BLOB); + if (!e) + { + return FAILED; + } + if (e->enumerate(e, &hash_id, &hash_value)) + { + if (!chunk_equals(measurement, hash_value)) + { + /* update hash measurement value */ + if (this->db->execute(this->db, &hash_id, + "UPDATE file_hashes SET hash = ? WHERE id = ?", + DB_BLOB, measurement, DB_INT, hash_id) != 1) + { + status = FAILED; + } + } + } + else + { + /* insert hash measurement value */ + if (this->db->execute(this->db, &hash_id, + "INSERT INTO file_hashes (file, product, algo, hash) " + "VALUES (?, ?, ?, ?)", DB_INT, fid, DB_INT, pid, + DB_INT, algo, DB_BLOB, measurement) != 1) + { + status = FAILED; + } + } + e->destroy(e); + + return status; +} + +METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*, + private_pts_database_t *this, int pid, pts_meas_algorithms_t algo, + char *filename) +{ + enumerator_t *e; + char *dir, *file; + + if (strlen(filename) < 1) + { + return NULL; + } + + /* separate filename into directory and basename components */ + dir = path_dirname(filename); + file = path_basename(filename); + + if (*dir == '.') + { /* relative pathname */ + e = this->db->query(this->db, + "SELECT fh.hash FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "WHERE fh.product = ? AND f.name = ? AND fh.algo = ?", + DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_BLOB); + } + else + { /* absolute pathname */ + int did; + + /* find directory entry first */ + e = this->db->query(this->db, + "SELECT id FROM directories WHERE path = ?", + DB_TEXT, dir, DB_INT); + + if (!e || !e->enumerate(e, &did)) + { + goto err; + } + e->destroy(e); + + e = this->db->query(this->db, + "SELECT fh.hash FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "WHERE fh.product = ? AND f.dir = ? AND f.name = ? AND fh.algo = ?", + DB_INT, pid, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_BLOB); + } + +err: + free(file); + free(dir); + + return e; +} + +METHOD(pts_database_t, check_comp_measurement, status_t, + private_pts_database_t *this, chunk_t measurement, int cid, int aik_id, + int seq_no, int pcr, pts_meas_algorithms_t algo) +{ + enumerator_t *e; + chunk_t hash; + status_t status = NOT_FOUND; + + e = this->db->query(this->db, + "SELECT hash FROM component_hashes " + "WHERE component = ? AND key = ? " + "AND seq_no = ? AND pcr = ? AND algo = ? ", + DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, + DB_INT, pcr, DB_INT, algo, DB_BLOB); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FAILED; + } + + while (e->enumerate(e, &hash)) + { + if (chunk_equals(hash, measurement)) + { + status = SUCCESS; + break; + } + else + { + DBG1(DBG_PTS, "PCR %2d no matching component measurement #%d " + "found in database", pcr, seq_no); + DBG1(DBG_PTS, " expected: %#B", &hash); + DBG1(DBG_PTS, " received: %#B", &measurement); + status = VERIFY_ERROR; + break; + } + } + e->destroy(e); + + if (status == NOT_FOUND) + { + DBG1(DBG_PTS, "PCR %2d no measurement #%d " + "found in database", pcr, seq_no); + } + + return status; +} + +METHOD(pts_database_t, insert_comp_measurement, status_t, + private_pts_database_t *this, chunk_t measurement, int cid, int aik_id, + int seq_no, int pcr, pts_meas_algorithms_t algo) +{ + int id; + + if (this->db->execute(this->db, &id, + "INSERT INTO component_hashes " + "(component, key, seq_no, pcr, algo, hash) " + "VALUES (?, ?, ?, ?, ?, ?)", + DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, DB_INT, pcr, + DB_INT, algo, DB_BLOB, measurement) == 1) + { + return SUCCESS; + } + + DBG1(DBG_PTS, "could not insert component measurement into database"); + return FAILED; +} + +METHOD(pts_database_t, delete_comp_measurements, int, + private_pts_database_t *this, int cid, int aik_id) +{ + return this->db->execute(this->db, NULL, + "DELETE FROM component_hashes " + "WHERE component = ? AND key = ?", + DB_INT, cid, DB_INT, aik_id); +} + +METHOD(pts_database_t, get_comp_measurement_count, status_t, + private_pts_database_t *this, pts_comp_func_name_t *comp_name, + int aik_id, pts_meas_algorithms_t algo, int *cid, int *count) +{ + enumerator_t *e; + status_t status = SUCCESS; + + /* Initialize count */ + *count = 0; + + /* Get the primary key of the Component Functional Name */ + e = this->db->query(this->db, + "SELECT id FROM components " + " WHERE vendor_id = ? AND name = ? AND qualifier = ?", + DB_INT, comp_name->get_vendor_id(comp_name), + DB_INT, comp_name->get_name(comp_name), + DB_INT, comp_name->get_qualifier(comp_name), + DB_INT); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FAILED; + } + if (!e->enumerate(e, cid)) + { + DBG1(DBG_PTS, "component functional name not found in database"); + e->destroy(e); + return FAILED; + } + e->destroy(e); + + /* Get the number of stored measurements for a given AIK and component */ + e = this->db->query(this->db, + "SELECT COUNT(*) FROM component_hashes AS ch " + "WHERE component = ? AND key = ? AND algo = ?", + DB_INT, *cid, DB_INT, aik_id, DB_INT, algo, DB_INT); + if (!e) + { + DBG1(DBG_PTS, "no database query enumerator returned"); + return FAILED; + } + if (!e->enumerate(e, count)) + { + DBG1(DBG_PTS, "no component measurement count returned from database"); + status = FAILED; + } + e->destroy(e); + + return status; +} + +METHOD(pts_database_t, destroy, void, + private_pts_database_t *this) +{ + free(this); +} + +/** + * See header + */ +pts_database_t *pts_database_create(imv_database_t *imv_db) +{ + private_pts_database_t *this; + + if (!imv_db) + { + return NULL; + } + + INIT(this, + .public = { + .get_pathname = _get_pathname, + .create_file_hash_enumerator = _create_file_hash_enumerator, + .add_file_measurement = _add_file_measurement, + .create_file_meas_enumerator = _create_file_meas_enumerator, + .check_comp_measurement = _check_comp_measurement, + .insert_comp_measurement = _insert_comp_measurement, + .delete_comp_measurements = _delete_comp_measurements, + .get_comp_measurement_count = _get_comp_measurement_count, + .destroy = _destroy, + }, + .db = imv_db->get_database(imv_db), + ); + + return &this->public; +} diff --git a/src/libimcv/pts/pts_database.h b/src/libimcv/pts/pts_database.h new file mode 100644 index 000000000..a6c9fb3b6 --- /dev/null +++ b/src/libimcv/pts/pts_database.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_database pts_database + * @{ @ingroup pts + */ + +#ifndef PTS_DATABASE_H_ +#define PTS_DATABASE_H_ + +typedef struct pts_database_t pts_database_t; + +#include "pts_meas_algo.h" +#include "components/pts_comp_func_name.h" + +#include <imv/imv_database.h> +#include <library.h> + +/** + * Class implementing the PTS File Measurement database + * + */ +struct pts_database_t { + + /** + * Get absolute pathname for file or directory measurement + * + * @param is_dir TRUE if dir, FALSE if file + * @param id Primary key into directories or files table + * @return Absolute pathname as a text string + */ + char* (*get_pathname)(pts_database_t *this, bool is_dir, int id); + + /** + * Get stored measurement hash for single file or directory entries + * + * @param pid Primary key of software product in database + * @param algo Hash algorithm used for measurement + * @param is_dir TRUE if directory was measured + * @param id Primary key of measured file/directory + * @return Enumerator over all matching measurement hashes + */ + enumerator_t* (*create_file_hash_enumerator)(pts_database_t *this, + int pid, pts_meas_algorithms_t algo, + bool is_dir, int id); + + /** + * Add PTS file measurement reference value + * + * @param pid Primary key of software product in database + * @param algo File measurement hash algorithm used + * @param measurement File measurement hash + * @param filename Optional name of the file to be checked + * @param is_dir TRUE if part of directory measurement + * @param id Primary key into direcories/files table + * @return Status + */ + status_t (*add_file_measurement)(pts_database_t *this, int pid, + pts_meas_algorithms_t algo, + chunk_t measurement, char *filename, + bool is_dir, int id); + + /** + * Get PTS measurement[s] for a given filename stored in database + * + * @param pid Primary key of software product in database + * @param algo File measurement hash algorithm used + * @param filename Name of the file to be checked + * @return Enumerator over all matching measurement hashes + */ + enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this, int pid, + pts_meas_algorithms_t algo, + char *filename); + + /** + * Check a functional component measurement against value stored in database + * + * @param measurement measurement hash + * @param cid Primary key of Component Functional Name entry + * @param aik_id Primary key of AIK entry in database + * @param seq_no Measurement sequence number + * @param prc Number of the PCR the measurement was extended into + * @param algo Hash algorithm used for measurement + * @return SUCCESS if check was successful + */ + status_t (*check_comp_measurement)(pts_database_t *this, chunk_t measurement, + int cid, int aik_id, int seq_no, int pcr, + pts_meas_algorithms_t algo); + + /** + * Insert a functional component measurement into the database + * + * @param measurement Measurement hash + * @param cid Primary key of Component Functional Name entry + * @param aik_id Primary key of AIK entry in database + * @param seq_no Measurement sequence number + * @param prc Number of the PCR the measurement was extended into + * @param algo Hash algorithm used for measurement + * @return SUCCESS if INSERT was successful + */ + status_t (*insert_comp_measurement)(pts_database_t *this, chunk_t measurement, + int cid, int aik_id, int seq_no, int pcr, + pts_meas_algorithms_t algo); + + /** + * Delete functional component measurements from the database + * + * @param cid Primary key of Component Functional Name entry + * @param aik_id Primary key of AIK entry in database + * @return number of deleted measurement entries + */ + int (*delete_comp_measurements)(pts_database_t *this, int cid, int aik_id); + + /** + * Get the number of measurements for a functional component and AIK + * + * @param comp_name Component Functional Name + * @param aik_id Primary key of AIK entry in database + * @param algo Hash algorithm used for measurement + * @param cid Primary key of Component Functional Name entry + * @param count measurement count + * @return SUCCESS if COUNT was successful + */ + status_t (*get_comp_measurement_count)(pts_database_t *this, + pts_comp_func_name_t *comp_name, int aik_id, + pts_meas_algorithms_t algo, int *cid, int *count); + + /** + * Destroys a pts_database_t object. + */ + void (*destroy)(pts_database_t *this); + +}; + +/** + * Creates an pts_database_t object + * + * @param imv_db Already attached IMV database + */ +pts_database_t* pts_database_create(imv_database_t *imv_db); + +#endif /** PTS_DATABASE_H_ @}*/ diff --git a/src/libimcv/pts/pts_dh_group.c b/src/libimcv/pts/pts_dh_group.c new file mode 100644 index 000000000..305b4ec4f --- /dev/null +++ b/src/libimcv/pts/pts_dh_group.c @@ -0,0 +1,184 @@ +/* + * 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 "pts_dh_group.h" + +#include <utils/debug.h> + +/** + * Described in header. + */ +bool pts_dh_group_probe(pts_dh_group_t *dh_groups, bool mandatory_dh_groups) +{ + enumerator_t *enumerator; + diffie_hellman_group_t dh_group; + const char *plugin_name; + char format1[] = " %s PTS DH group %N[%s] available"; + char format2[] = " %s PTS DH group %N not available"; + + *dh_groups = PTS_DH_GROUP_NONE; + + enumerator = lib->crypto->create_dh_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &dh_group, &plugin_name)) + { + if (dh_group == MODP_1024_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE2; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == MODP_1536_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE5; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == MODP_2048_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE14; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == ECP_256_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE19; + DBG2(DBG_PTS, format1, "mandatory", diffie_hellman_group_names, + dh_group, plugin_name); + } + else if (dh_group == ECP_384_BIT) + { + *dh_groups |= PTS_DH_GROUP_IKE20; + DBG2(DBG_PTS, format1, "optional ", diffie_hellman_group_names, + dh_group, plugin_name); + } + } + enumerator->destroy(enumerator); + + if (*dh_groups & PTS_DH_GROUP_IKE19) + { + /* mandatory PTS DH group is available */ + return TRUE; + } + if (*dh_groups == PTS_DH_GROUP_NONE) + { + DBG1(DBG_PTS, "no PTS DH group available"); + return FALSE; + } + if (mandatory_dh_groups) + { + DBG1(DBG_PTS, format2, "mandatory", diffie_hellman_group_names, + ECP_256_BIT); + return FALSE; + } + + /* at least one optional PTS DH group is available */ + return TRUE; +} + +/** + * Described in header. + */ +bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups) +{ + if (strcaseeq(dh_group, "ecp384")) + { + /* nothing to update, all groups are supported */ + return TRUE; + } + if (strcaseeq(dh_group, "ecp256")) + { + /* remove DH group 20 */ + *dh_groups &= ~PTS_DH_GROUP_IKE20; + return TRUE; + } + if (strcaseeq(dh_group, "modp2048")) + { + /* remove DH groups 19 and 20 */ + *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19); + return TRUE; + } + if (strcaseeq(dh_group, "modp1536")) + { + /* remove DH groups 14, 19 and 20 */ + *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 | + PTS_DH_GROUP_IKE14); + return TRUE; + } + if (strcaseeq(dh_group, "modp1024")) + { + /* remove DH groups 5, 14, 19 and 20 */ + *dh_groups &= ~(PTS_DH_GROUP_IKE20 | PTS_DH_GROUP_IKE19 | + PTS_DH_GROUP_IKE14 | PTS_DH_GROUP_IKE5); + return TRUE; + } + DBG1(DBG_PTS, "unknown DH group '%s' configured", dh_group); + return FALSE; +} + +/** + * Described in header. + */ +pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_dh_groups, + pts_dh_group_t offered_dh_groups) +{ + if ((supported_dh_groups & PTS_DH_GROUP_IKE20) && + (offered_dh_groups & PTS_DH_GROUP_IKE20)) + { + return PTS_DH_GROUP_IKE20; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE19) && + (offered_dh_groups & PTS_DH_GROUP_IKE19)) + { + return PTS_DH_GROUP_IKE19; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE14) && + (offered_dh_groups & PTS_DH_GROUP_IKE14)) + { + return PTS_DH_GROUP_IKE14; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE5) && + (offered_dh_groups & PTS_DH_GROUP_IKE5)) + { + return PTS_DH_GROUP_IKE5; + } + if ((supported_dh_groups & PTS_DH_GROUP_IKE2) && + (offered_dh_groups & PTS_DH_GROUP_IKE2)) + { + return PTS_DH_GROUP_IKE2; + } + return PTS_DH_GROUP_NONE; +} + +/** + * Described in header. + */ +diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group) +{ + switch (dh_group) + { + case PTS_DH_GROUP_IKE2: + return MODP_1024_BIT; + case PTS_DH_GROUP_IKE5: + return MODP_1536_BIT; + case PTS_DH_GROUP_IKE14: + return MODP_2048_BIT; + case PTS_DH_GROUP_IKE19: + return ECP_256_BIT; + case PTS_DH_GROUP_IKE20: + return ECP_384_BIT; + default: + return MODP_NONE; + } +} diff --git a/src/libimcv/pts/pts_dh_group.h b/src/libimcv/pts/pts_dh_group.h new file mode 100644 index 000000000..f5d951e9a --- /dev/null +++ b/src/libimcv/pts/pts_dh_group.h @@ -0,0 +1,107 @@ +/* + * 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 pts_dh_group pts_dh_group + * @{ @ingroup pts + */ + +#ifndef PTS_DH_GROUP_H_ +#define PTS_DH_GROUP_H_ + +#include <library.h> +#include <crypto/diffie_hellman.h> + +typedef enum pts_dh_group_t pts_dh_group_t; + +/** + * PTS Diffie Hellman Group Values + */ +enum pts_dh_group_t { + /** No DH Group */ + PTS_DH_GROUP_NONE = 0, + /** IKE Group 2 */ + PTS_DH_GROUP_IKE2 = (1<<15), + /** IKE Group 5 */ + PTS_DH_GROUP_IKE5 = (1<<14), + /** IKE Group 14 */ + PTS_DH_GROUP_IKE14 = (1<<13), + /** IKE Group 19 */ + PTS_DH_GROUP_IKE19 = (1<<12), + /** IKE Group 20 */ + PTS_DH_GROUP_IKE20 = (1<<11), +}; + +/** + * Diffie-Hellman Group Values + * see section 3.8.6 of PTS Protocol: Binding to TNC IF-M Specification + * + * 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1|2|3|4|5|R|R|R|R|R|R|R|R|R|R|R| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +/** + * Probe available PTS Diffie-Hellman groups + * + * @param dh_groups returns set of available DH groups + * @param mandatory_dh_groups if TRUE enforce mandatory PTS DH groups + * @return TRUE if mandatory DH groups are available + * or at least one optional DH group if + * mandatory_dh_groups is set to FALSE. + */ +bool pts_dh_group_probe(pts_dh_group_t *dh_groups, bool mandatory_dh_groups); + +/** + * Update supported Diffie-Hellman groups according to configuration + * + * 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 + * + * The PTS-IMC is expected to select the strongest supported group + * + * @param dh_group configured DH group + * @param dh_groups returns set of available DH groups + */ +bool pts_dh_group_update(char *dh_group, pts_dh_group_t *dh_groups); + +/** + * Select the strongest supported Diffie-Hellman group + * among a set of offered DH groups + * + * @param supported_groups set of supported DH groups + * @param offered_groups set of offered DH groups + * @return selected DH group + */ +pts_dh_group_t pts_dh_group_select(pts_dh_group_t supported_groups, + pts_dh_group_t offered_groups); + +/** + * Convert pts_dh_group_t to diffie_hellman_group_t + * + * @param dh_group PTS DH group type + * @return IKE DH group type + */ +diffie_hellman_group_t pts_dh_group_to_ike(pts_dh_group_t dh_group); + +#endif /** PTS_DH_GROUP_H_ @}*/ diff --git a/src/libimcv/pts/pts_error.c b/src/libimcv/pts/pts_error.c new file mode 100644 index 000000000..1e79689f9 --- /dev/null +++ b/src/libimcv/pts/pts_error.c @@ -0,0 +1,99 @@ +/* + * 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 "pts_error.h" + +#include <bio/bio_writer.h> +#include <ietf/ietf_attr_pa_tnc_error.h> + +ENUM(pts_error_code_names, TCG_PTS_RESERVED_ERROR, TCG_PTS_UNABLE_DET_PCR, + "Reserved Error", + "Hash Algorithm Not Supported", + "Invalid Path", + "File Not Found", + "Registry Not Supported", + "Registry Key Not Found", + "D-H Group Not Supported", + "DH-PN Nonce Not Acceptable", + "Invalid Functional Name Family", + "TPM Version Information Unavailable", + "Invalid File Pathname Delimiter", + "PTS Operation Not Supported", + "Unable To Update Reference Manifest", + "Unable To Perform Local Validation", + "Unable To Collect Current Evidence", + "Unable To Determine Transitive Trust Chain", + "Unable To Determine PCR" +); + +/** + * Described in header. + */ +pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms) +{ + bio_writer_t *writer; + chunk_t msg_info; + pa_tnc_attr_t *attr; + pen_type_t error_code = { PEN_TCG, TCG_PTS_HASH_ALG_NOT_SUPPORTED }; + + writer = bio_writer_create(4); + writer->write_uint16(writer, 0x0000); + writer->write_uint16(writer, algorithms); + msg_info = writer->get_buf(writer); + attr = ietf_attr_pa_tnc_error_create(error_code, msg_info); + writer->destroy(writer); + + return attr; +} + +/** + * Described in header. + */ +pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups) +{ + bio_writer_t *writer; + chunk_t msg_info; + pa_tnc_attr_t *attr; + pen_type_t error_code = { PEN_TCG, TCG_PTS_DH_GRPS_NOT_SUPPORTED }; + + writer = bio_writer_create(4); + writer->write_uint16(writer, 0x0000); + writer->write_uint16(writer, dh_groups); + msg_info = writer->get_buf(writer); + attr = ietf_attr_pa_tnc_error_create(error_code, msg_info); + writer->destroy(writer); + + return attr; +} + +/** + * Described in header. + */ +pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len) +{ + bio_writer_t *writer; + chunk_t msg_info; + pa_tnc_attr_t *attr; + pen_type_t error_code = { PEN_TCG, TCG_PTS_BAD_NONCE_LENGTH }; + + writer = bio_writer_create(4); + writer->write_uint16(writer, min_nonce_len); + writer->write_uint16(writer, max_nonce_len); + msg_info = writer->get_buf(writer); + attr = ietf_attr_pa_tnc_error_create(error_code, msg_info); + writer->destroy(writer); + + return attr; +} diff --git a/src/libimcv/pts/pts_error.h b/src/libimcv/pts/pts_error.h new file mode 100644 index 000000000..9a53abd98 --- /dev/null +++ b/src/libimcv/pts/pts_error.h @@ -0,0 +1,89 @@ +/* + * 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 pts_error pts_error + * @{ @ingroup pts + */ + +#ifndef PTS_ERROR_H_ +#define PTS_ERROR_H_ + +typedef enum pts_error_code_t pts_error_code_t; + +#include "pts_meas_algo.h" +#include "pts_dh_group.h" +#include "pa_tnc/pa_tnc_attr.h" + +#include <library.h> + +#define PTS_MIN_NONCE_LEN 17 +#define PTS_MAX_NONCE_LEN 0xffff + +/** + * PTS Attestation Error Codes + * see section 3.14.2 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_error_code_t { + TCG_PTS_RESERVED_ERROR = 0, + TCG_PTS_HASH_ALG_NOT_SUPPORTED = 1, + TCG_PTS_INVALID_PATH = 2, + TCG_PTS_FILE_NOT_FOUND = 3, + TCG_PTS_REG_NOT_SUPPORTED = 4, + TCG_PTS_REG_KEY_NOT_FOUND = 5, + TCG_PTS_DH_GRPS_NOT_SUPPORTED = 6, + TCG_PTS_BAD_NONCE_LENGTH = 7, + TCG_PTS_INVALID_NAME_FAM = 8, + TCG_PTS_TPM_VERS_NOT_SUPPORTED = 9, + TCG_PTS_INVALID_DELIMITER = 10, + TCG_PTS_OPERATION_NOT_SUPPORTED = 11, + TCG_PTS_RM_ERROR = 12, + TCG_PTS_UNABLE_LOCAL_VAL = 13, + TCG_PTS_UNABLE_CUR_EVID = 14, + TCG_PTS_UNABLE_DET_TTC = 15, + TCG_PTS_UNABLE_DET_PCR = 16, +}; + +/** + * enum name for pts_error_code_t. + */ +extern enum_name_t *pts_error_code_names; + +/** + * Creates a PTS Hash Algorithm Not Supported Error Attribute + * see section 4.2.2 of PTS Protocol: Binding to TNC IF-M Specification + * + * @param algorithms supported measurement hash algorithms + */ +pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms); + +/** + * Creates a PTS DH Group Not Supported Error Attribute + * see section 4.2.4 of PTS Protocol: Binding to TNC IF-M Specification + * + * @param dh_groups supported DH groups + */ +pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups); + +/** + * Creates a PTS DH PN Nonce Not Supported Error Attribute + * see section 4.2.5 of PTS Protocol: Binding to TNC IF-M Specification + * + * @param min_nonce_len minimum nonce length + * @param max_nonce_len maximum nonce length + */ +pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len); + +#endif /** PTS_ERROR_H_ @}*/ diff --git a/src/libimcv/pts/pts_file_meas.c b/src/libimcv/pts/pts_file_meas.c new file mode 100644 index 000000000..478892aea --- /dev/null +++ b/src/libimcv/pts/pts_file_meas.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pts_file_meas.h" + +#include <collections/linked_list.h> +#include <utils/debug.h> + +#include <sys/stat.h> +#include <libgen.h> +#include <errno.h> + +typedef struct private_pts_file_meas_t private_pts_file_meas_t; + +/** + * Private data of a pts_file_meas_t object. + * + */ +struct private_pts_file_meas_t { + + /** + * Public pts_file_meas_t interface. + */ + pts_file_meas_t public; + + /** + * ID of PTS File Measurement Request + */ + u_int16_t request_id; + + /** + * List of File Measurements + */ + linked_list_t *list; +}; + +typedef struct entry_t entry_t; + +/** + * PTS File Measurement entry + */ +struct entry_t { + char *filename; + chunk_t measurement; +}; + +/** + * Free an entry_t object + */ +static void free_entry(entry_t *entry) +{ + if (entry) + { + free(entry->filename); + free(entry->measurement.ptr); + free(entry); + } +} + +METHOD(pts_file_meas_t, get_request_id, u_int16_t, + private_pts_file_meas_t *this) +{ + return this->request_id; +} + +METHOD(pts_file_meas_t, get_file_count, int, + private_pts_file_meas_t *this) +{ + return this->list->get_count(this->list); +} + +METHOD(pts_file_meas_t, add, void, + private_pts_file_meas_t *this, char *filename, chunk_t measurement) +{ + entry_t *entry; + + entry = malloc_thing(entry_t); + entry->filename = strdup(filename); + entry->measurement = chunk_clone(measurement); + + this->list->insert_last(this->list, entry); +} + +/** + * Enumerate file measurement entries + */ +static bool entry_filter(void *null, entry_t **entry, char **filename, + void *i2, chunk_t *measurement) +{ + *filename = (*entry)->filename; + *measurement = (*entry)->measurement; + return TRUE; +} + +METHOD(pts_file_meas_t, create_enumerator, enumerator_t*, + private_pts_file_meas_t *this) +{ + return enumerator_create_filter(this->list->create_enumerator(this->list), + (void*)entry_filter, NULL, NULL); +} + +METHOD(pts_file_meas_t, check, bool, + private_pts_file_meas_t *this, pts_database_t *pts_db, int pid, + pts_meas_algorithms_t algo) +{ + enumerator_t *enumerator, *e; + entry_t *entry; + chunk_t hash; + int count_ok = 0, count_not_found = 0, count_differ = 0; + status_t status; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + status = NOT_FOUND; + + e = pts_db->create_file_meas_enumerator(pts_db, pid, algo, + entry->filename); + if (e) + { + while (e->enumerate(e, &hash)) + { + if (chunk_equals(entry->measurement, hash)) + { + status = SUCCESS; + break; + } + else + { + status = VERIFY_ERROR; + } + } + e->destroy(e); + } + else + { + status = FAILED; + } + + switch (status) + { + case SUCCESS: + DBG3(DBG_PTS, " %#B for '%s' is ok", &entry->measurement, + entry->filename); + count_ok++; + break; + case NOT_FOUND: + DBG2(DBG_PTS, " %#B for '%s' not found", &entry->measurement, + entry->filename); + count_not_found++; + break; + case VERIFY_ERROR: + DBG1(DBG_PTS, " %#B for '%s' differs", &entry->measurement, + entry->filename); + count_differ++; + break; + case FAILED: + default: + DBG1(DBG_PTS, " %#B for '%s' failed", &entry->measurement, + entry->filename); + } + } + enumerator->destroy(enumerator); + + DBG1(DBG_PTS, "%d measurements, %d ok, %d not found, %d differ", + this->list->get_count(this->list), + count_ok, count_not_found, count_differ); + return TRUE; +} + +METHOD(pts_file_meas_t, verify, bool, + private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir) +{ + int fid, fid_last = 0; + char *filename; + chunk_t measurement; + entry_t *entry; + enumerator_t *enumerator = NULL; + bool found = FALSE, match = FALSE, success = TRUE; + + while (e_hash->enumerate(e_hash, &fid, &filename, &measurement)) + { + if (fid != fid_last) + { + if (found && !match) + { + /* no matching hash value found for last filename */ + success = FALSE; + DBG1(DBG_PTS, " %#B for '%s' is incorrect", + &entry->measurement, entry->filename); + enumerator->destroy(enumerator); + } + + /* get a new filename from the database */ + found = FALSE; + match = FALSE; + fid_last = fid; + + /** + * check if we find an entry for this filename + * in the PTS measurement list + */ + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + if (!is_dir || streq(filename, entry->filename)) + { + found = TRUE; + break; + } + } + + /* no PTS measurement returned for this filename */ + if (!found) + { + success = FALSE; + DBG1(DBG_PTS, " no measurement found for '%s'", filename); + enumerator->destroy(enumerator); + } + } + + if (found && !match) + { + if (chunk_equals(measurement, entry->measurement)) + { + match = TRUE; + DBG2(DBG_PTS, " %#B for '%s' is ok", + &entry->measurement, entry->filename); + enumerator->destroy(enumerator); + } + } + } + + if (found && !match) + { + /* no matching hash value found for the very last filename */ + success = FALSE; + DBG1(DBG_PTS, " %#B for '%s' is incorrect", + &entry->measurement, entry->filename); + enumerator->destroy(enumerator); + } + + return success; +} + +METHOD(pts_file_meas_t, destroy, void, + private_pts_file_meas_t *this) +{ + this->list->destroy_function(this->list, (void *)free_entry); + free(this); +} + +/** + * See header + */ +pts_file_meas_t *pts_file_meas_create(u_int16_t request_id) +{ + private_pts_file_meas_t *this; + + INIT(this, + .public = { + .get_request_id = _get_request_id, + .get_file_count = _get_file_count, + .add = _add, + .create_enumerator = _create_enumerator, + .check = _check, + .verify = _verify, + .destroy = _destroy, + }, + .request_id = request_id, + .list = linked_list_create(), + ); + + return &this->public; +} + +/** + * Hash a file with a given absolute pathname + */ +static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash) +{ + u_char buffer[4096]; + size_t bytes_read; + bool success = TRUE; + FILE *file; + + file = fopen(pathname, "rb"); + if (!file) + { + DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname, + strerror(errno)); + return FALSE; + } + while (TRUE) + { + bytes_read = fread(buffer, 1, sizeof(buffer), file); + if (bytes_read > 0) + { + if (!hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL)) + { + DBG1(DBG_PTS, " hasher increment error"); + success = FALSE; + break; + } + } + else + { + if (!hasher->get_hash(hasher, chunk_empty, hash)) + { + DBG1(DBG_PTS, " hasher finalize error"); + success = FALSE; + } + break; + } + } + fclose(file); + + return success; +} + +/** + * See header + */ +pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id, + char *pathname, bool is_dir, bool use_rel_name, + pts_meas_algorithms_t alg) +{ + private_pts_file_meas_t *this; + hash_algorithm_t hash_alg; + hasher_t *hasher; + u_char hash[HASH_SIZE_SHA384]; + chunk_t measurement; + char* filename; + bool success = TRUE; + + /* Create a hasher and a hash measurement buffer */ + hash_alg = pts_meas_algo_to_hash(alg); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + if (!hasher) + { + DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg); + return NULL; + } + measurement = chunk_create(hash, hasher->get_hash_size(hasher)); + this = (private_pts_file_meas_t*)pts_file_meas_create(request_id); + + if (is_dir) + { + enumerator_t *enumerator; + char *rel_name, *abs_name; + struct stat st; + + enumerator = enumerator_create_directory(pathname); + if (!enumerator) + { + DBG1(DBG_PTS, " directory '%s' can not be opened, %s", pathname, + strerror(errno)); + success = FALSE; + goto end; + } + while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st)) + { + /* measure regular files only */ + if (S_ISREG(st.st_mode) && *rel_name != '.') + { + if (!hash_file(hasher, abs_name, hash)) + { + continue; + } + filename = use_rel_name ? rel_name : abs_name; + DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); + add(this, filename, measurement); + } + } + enumerator->destroy(enumerator); + } + else + { + if (!hash_file(hasher, pathname, hash)) + { + success = FALSE; + goto end; + } + filename = use_rel_name ? path_basename(pathname) : strdup(pathname); + DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); + add(this, filename, measurement); + free(filename); + } + +end: + hasher->destroy(hasher); + if (success) + { + return &this->public; + } + else + { + destroy(this); + return NULL; + } +} diff --git a/src/libimcv/pts/pts_file_meas.h b/src/libimcv/pts/pts_file_meas.h new file mode 100644 index 000000000..4bf28e280 --- /dev/null +++ b/src/libimcv/pts/pts_file_meas.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_file_meas pts_file_meas + * @{ @ingroup pts + */ + +#ifndef PTS_FILE_MEAS_H_ +#define PTS_FILE_MEAS_H_ + +#include "pts/pts_database.h" + +#include <library.h> + +typedef struct pts_file_meas_t pts_file_meas_t; + +/** + * Class storing PTS File Measurements + */ +struct pts_file_meas_t { + + /** + * Get the ID of the PTS File Measurement Request + * + * @return ID of PTS File Measurement Request + */ + u_int16_t (*get_request_id)(pts_file_meas_t *this); + + /** + * Get the number of measured files + * + * @return Number of measured files + */ + int (*get_file_count)(pts_file_meas_t *this); + + /** + * Add a PTS File Measurement + * + * @param filename Name of measured file or directory + * @param measurement PTS Measurement hash + */ + void (*add)(pts_file_meas_t *this, char *filename, chunk_t measurement); + + /** + * Create a PTS File Measurement enumerator + * + * @return Enumerator returning filename and measurement + */ + enumerator_t* (*create_enumerator)(pts_file_meas_t *this); + + /** + * Check PTS File Measurements against reference value in the database + * + * @param db PTS Measurement database + * @param pid Primary key of software product in database + * @param algo PTS Measurement algorithm used + * @return TRUE if all measurements agreed + */ + bool (*check)(pts_file_meas_t *this, pts_database_t *db, int pid, + pts_meas_algorithms_t algo); + + /** + * Verify stored hashes against PTS File Measurements + * + * @param e_hash Hash enumerator + * @param is_dir TRUE for directory contents hashes + * @return TRUE if all hashes match a measurement + */ + bool (*verify)(pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir); + + /** + * Destroys a pts_file_meas_t object. + */ + void (*destroy)(pts_file_meas_t *this); + +}; + +/** + * Creates a pts_file_meas_t object + * + * @param request_id ID of PTS File Measurement Request + */ +pts_file_meas_t* pts_file_meas_create(u_int16_t request_id); + +/** + * Creates a pts_file_meas_t object measuring a file/directory + * + * @param request_id ID of PTS File Measurement Request + * @param pathname Absolute file or directory pathname + * @param is_dir TRUE if directory path + * @param use_rel_name TRUE if relative filenames are to be used + * @param alg PTS hash measurement algorithm to be used + */ +pts_file_meas_t* pts_file_meas_create_from_path(u_int16_t request_id, + char* pathname, bool is_dir, bool use_rel_name, + pts_meas_algorithms_t alg); + +#endif /** PTS_FILE_MEAS_H_ @}*/ diff --git a/src/libimcv/pts/pts_file_meta.c b/src/libimcv/pts/pts_file_meta.c new file mode 100644 index 000000000..9cca0a5a5 --- /dev/null +++ b/src/libimcv/pts/pts_file_meta.c @@ -0,0 +1,96 @@ +/* + * 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 "pts_file_meta.h" + +#include <collections/linked_list.h> +#include <utils/debug.h> + +typedef struct private_pts_file_meta_t private_pts_file_meta_t; + +/** + * Private data of a pts_file_meta_t object. + * + */ +struct private_pts_file_meta_t { + + /** + * Public pts_file_meta_t interface. + */ + pts_file_meta_t public; + + /** + * List of File Metadata + */ + linked_list_t *list; +}; + +/** + * Free an pts_file_metadata_t object + */ +static void free_entry(pts_file_metadata_t *entry) +{ + if (entry) + { + free(entry->filename); + free(entry); + } +} + +METHOD(pts_file_meta_t, get_file_count, int, + private_pts_file_meta_t *this) +{ + return this->list->get_count(this->list); +} + +METHOD(pts_file_meta_t, add, void, + private_pts_file_meta_t *this, pts_file_metadata_t *metadata) +{ + this->list->insert_last(this->list, metadata); +} + +METHOD(pts_file_meta_t, create_enumerator, enumerator_t*, + private_pts_file_meta_t *this) +{ + return this->list->create_enumerator(this->list); +} + +METHOD(pts_file_meta_t, destroy, void, + private_pts_file_meta_t *this) +{ + this->list->destroy_function(this->list, (void *)free_entry); + free(this); +} + +/** + * See header + */ +pts_file_meta_t *pts_file_meta_create() +{ + private_pts_file_meta_t *this; + + INIT(this, + .public = { + .get_file_count = _get_file_count, + .add = _add, + .create_enumerator = _create_enumerator, + .destroy = _destroy, + }, + .list = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/libimcv/pts/pts_file_meta.h b/src/libimcv/pts/pts_file_meta.h new file mode 100644 index 000000000..3f1813306 --- /dev/null +++ b/src/libimcv/pts/pts_file_meta.h @@ -0,0 +1,85 @@ +/* + * 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 pts_file_meta pts_file_meta + * @{ @ingroup pts + */ + +#ifndef PTS_FILE_META_H_ +#define PTS_FILE_META_H_ + +#include "pts_file_type.h" + +#include <time.h> +#include <library.h> + +typedef struct pts_file_meta_t pts_file_meta_t; +typedef struct pts_file_metadata_t pts_file_metadata_t; + +/** + * Structure holding file metadata + */ +struct pts_file_metadata_t { + pts_file_type_t type; + u_int64_t filesize; + u_int64_t created; + u_int64_t modified; + u_int64_t accessed; + u_int64_t owner; + u_int64_t group; + char *filename; +}; + +/** + * Class storing PTS File Metadata + */ +struct pts_file_meta_t { + + /** + * Get the number of files + * + * @return Number of files + */ + int (*get_file_count)(pts_file_meta_t *this); + + /** + * Add PTS File Metadata + * + * @param filename Name of measured file or directory + * @param metadata File metadata + */ + void (*add)(pts_file_meta_t *this, pts_file_metadata_t *metadata); + + /** + * Create a PTS File Metadata enumerator + * + * @return Enumerator returning file metadata + */ + enumerator_t* (*create_enumerator)(pts_file_meta_t *this); + + /** + * Destroys a pts_file_meta_t object. + */ + void (*destroy)(pts_file_meta_t *this); + +}; + +/** + * Creates a pts_file_meta_t object + */ +pts_file_meta_t* pts_file_meta_create(); + +#endif /** PTS_FILE_MEAS_H_ @}*/ diff --git a/src/libimcv/pts/pts_file_type.c b/src/libimcv/pts/pts_file_type.c new file mode 100644 index 000000000..fe849dea4 --- /dev/null +++ b/src/libimcv/pts/pts_file_type.c @@ -0,0 +1,33 @@ +/* + * 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 "pts_file_type.h" + +ENUM(pts_file_type_names, PTS_FILE_OTHER, PTS_FILE_SOCKET, + "Other", + "FIFO", + "Character-Special", + "Reserved-3", + "Directory", + "Reserved-5", + "Block-Special", + "Reserved-7", + "Regular", + "Reserved-9", + "Symbolic-Link", + "Reserved-11", + "Socket" +); + diff --git a/src/libimcv/pts/pts_file_type.h b/src/libimcv/pts/pts_file_type.h new file mode 100644 index 000000000..c1d236888 --- /dev/null +++ b/src/libimcv/pts/pts_file_type.h @@ -0,0 +1,63 @@ +/* + * 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 pts_file_type pts_file_type + * @{ @ingroup pts + */ + +#ifndef PTS_FILE_TYPE_H_ +#define PTS_FILE_TYPE_H_ + +#include <library.h> + +typedef enum pts_file_type_t pts_file_type_t; + +/** + * PTS File Type + * see section 3.17.3 of PTS Protocol: Binding to TNC IF-M Specification + */ +enum pts_file_type_t { + /** Either unknown or different from standardized types */ + PTS_FILE_OTHER = 0x0000, + /** Pipe communication file */ + PTS_FILE_FIFO = 0x0001, + /** Character special file */ + PTS_FILE_CHAR_SPEC = 0x0002, + /** Reserved */ + PTS_FILE_RESERVED_3 = 0x0003, + /** Directory */ + PTS_FILE_DIRECTORY = 0x0004, + /** Reserved */ + PTS_FILE_RESERVED_5 = 0x0005, + /** Block special file */ + PTS_FILE_BLOCK_SPEC = 0x0006, + /** Reserved */ + PTS_FILE_RESERVED_7 = 0x0007, + /** Regular file */ + PTS_FILE_REGULAR = 0x0008, + /** Reserved */ + PTS_FILE_RESERVED_9 = 0x0009, + /** Symbolic link */ + PTS_FILE_SYM_LINK = 0x000A, + /** Reserved */ + PTS_FILE_RESERVED_11 = 0x000B, + /** Socket communication special file */ + PTS_FILE_SOCKET = 0x000C, +}; + +extern enum_name_t *pts_file_type_names; + +#endif /** PTS_FILE_TYPE_H_ @}*/ diff --git a/src/libimcv/pts/pts_ima_bios_list.c b/src/libimcv/pts/pts_ima_bios_list.c new file mode 100644 index 000000000..5051b6c2d --- /dev/null +++ b/src/libimcv/pts/pts_ima_bios_list.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pts_ima_bios_list.h" + +#include <utils/debug.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +typedef struct private_pts_ima_bios_list_t private_pts_ima_bios_list_t; +typedef struct bios_entry_t bios_entry_t; +typedef enum event_type_t event_type_t; + +enum event_type_t { + /* BIOS Events (TCG PC Client Specification for Conventional BIOS 1.21) */ + EV_PREBOOT_CERT = 0x00000000, + EV_POST_CODE = 0x00000001, + EV_UNUSED = 0x00000002, + EV_NO_ACTION = 0x00000003, + EV_SEPARATOR = 0x00000004, + EV_ACTION = 0x00000005, + EV_EVENT_TAG = 0x00000006, + EV_S_CRTM_CONTENTS = 0x00000007, + EV_S_CRTM_VERSION = 0x00000008, + EV_CPU_MICROCODE = 0x00000009, + EV_PLATFORM_CONFIG_FLAGS = 0x0000000A, + EV_TABLE_OF_DEVICES = 0x0000000B, + EV_COMPACT_HASH = 0x0000000C, + EV_IPL = 0x0000000D, + EV_IPL_PARTITION_DATA = 0x0000000E, + EV_NONHOST_CODE = 0x0000000F, + EV_NONHOST_CONFIG = 0x00000010, + EV_NONHOST_INFO = 0x00000011, + EV_OMIT_BOOT_DEVICE_EVENTS = 0x00000012, + + /* EFI Events (TCG EFI Platform Specification 1.22) */ + EV_EFI_EVENT_BASE = 0x80000000, + EV_EFI_VARIABLE_DRIVER_CONFIG = 0x80000001, + EV_EFI_VARIABLE_BOOT = 0x80000002, + EV_EFI_BOOT_SERVICES_APPLICATION = 0x80000003, + EV_EFI_BOOT_SERVICES_DRIVER = 0x80000004, + EV_EFI_RUNTIME_SERVICES_DRIVER = 0x80000005, + EV_EFI_GPT_EVENT = 0x80000006, + EV_EFI_ACTION = 0x80000007, + EV_EFI_PLATFORM_FIRMWARE_BLOB = 0x80000008, + EV_EFI_HANDOFF_TABLES = 0x80000009, + + EV_EFI_VARIABLE_AUTHORITY = 0x800000E0 +}; + +ENUM_BEGIN(event_type_names, EV_PREBOOT_CERT, EV_OMIT_BOOT_DEVICE_EVENTS, + "Preboot Cert", + "POST Code", + "Unused", + "No Action", + "Separator", + "Action", + "Event Tag", + "S-CRTM Contents", + "S-CRTM Version", + "CPU Microcode", + "Platform Config Flags", + "Table of Devices", + "Compact Hash", + "IPL", + "IPL Partition Data", + "Nonhost Code", + "Nonhost Config", + "Nonhost Info", + "Omit Boot Device Events" +); + +ENUM_NEXT(event_type_names, EV_EFI_EVENT_BASE, EV_EFI_HANDOFF_TABLES, + EV_OMIT_BOOT_DEVICE_EVENTS, + "EFI Event Base", + "EFI Variable Driver Config", + "EFI Variable Boot", + "EFI Boot Services Application", + "EFI Boot Services Driver", + "EFI Runtime Services Driver", + "EFI GPT Event", + "EFI Action", + "EFI Platform Firmware Blob", + "EFI Handoff Tables" +); +ENUM_NEXT(event_type_names, EV_EFI_VARIABLE_AUTHORITY, EV_EFI_VARIABLE_AUTHORITY, + EV_EFI_HANDOFF_TABLES, + "EFI Variable Authority" +); +ENUM_END(event_type_names, EV_EFI_VARIABLE_AUTHORITY); + +/** + * Private data of a pts_ima_bios_list_t object. + * + */ +struct private_pts_ima_bios_list_t { + + /** + * Public pts_ima_bios_list_t interface. + */ + pts_ima_bios_list_t public; + + /** + * List of BIOS measurement entries + */ + linked_list_t *list; + + /** + * Time when BIOS measurements were taken + */ + time_t creation_time; + +}; + +/** + * Linux IMA BIOS measurement entry + */ +struct bios_entry_t { + + /** + * PCR register + */ + uint32_t pcr; + + /** + * SHA1 measurement hash + */ + chunk_t measurement; +}; + +/** + * Free a bios_entry_t object + */ +static void free_bios_entry(bios_entry_t *this) +{ + free(this->measurement.ptr); + free(this); +} + +METHOD(pts_ima_bios_list_t, get_time, time_t, + private_pts_ima_bios_list_t *this) +{ + return this->creation_time; +} + +METHOD(pts_ima_bios_list_t, get_count, int, + private_pts_ima_bios_list_t *this) +{ + return this->list->get_count(this->list); +} + +METHOD(pts_ima_bios_list_t, get_next, status_t, + private_pts_ima_bios_list_t *this, uint32_t *pcr, chunk_t *measurement) +{ + bios_entry_t *entry; + status_t status; + + status = this->list->remove_first(this->list, (void**)&entry); + *pcr = entry->pcr; + *measurement = entry->measurement; + free(entry); + + return status; +} + +METHOD(pts_ima_bios_list_t, destroy, void, + private_pts_ima_bios_list_t *this) +{ + this->list->destroy_function(this->list, (void *)free_bios_entry); + free(this); +} + +/** + * See header + */ +pts_ima_bios_list_t* pts_ima_bios_list_create(char *file) +{ + private_pts_ima_bios_list_t *this; + uint32_t pcr, event_type, event_len, seek_len; + uint32_t buf_len = 2048; + uint8_t event_buf[buf_len]; + chunk_t event; + bios_entry_t *entry; + struct stat st; + ssize_t res; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) + { + DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno)); + return NULL; + } + + if (fstat(fd, &st) == -1) + { + DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file, + strerror(errno)); + close(fd); + return FALSE; + } + + INIT(this, + .public = { + .get_time = _get_time, + .get_count = _get_count, + .get_next = _get_next, + .destroy = _destroy, + }, + .creation_time = st.st_ctime, + .list = linked_list_create(), + ); + + DBG2(DBG_PTS, "PCR Event Type (Size)"); + while (TRUE) + { + res = read(fd, &pcr, 4); + if (res == 0) + { + DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)", + file, this->list->get_count(this->list)); + close(fd); + return &this->public; + } + + entry = malloc_thing(bios_entry_t); + entry->pcr = pcr; + entry->measurement = chunk_alloc(HASH_SIZE_SHA1); + + if (res != 4) + { + break; + } + if (read(fd, &event_type, 4) != 4) + { + break; + } + if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1) + { + break; + } + if (read(fd, &event_len, 4) != 4) + { + break; + } + DBG2(DBG_PTS, "%2u %N (%u bytes)", pcr, event_type_names, event_type, + event_len); + + seek_len = (event_len > buf_len) ? event_len - buf_len : 0; + event_len -= seek_len; + + if (read(fd, event_buf, event_len) != event_len) + { + break; + } + event = chunk_create(event_buf, event_len); + DBG3(DBG_PTS,"%B", &event); + + if (event_type == EV_ACTION || event_type == EV_EFI_ACTION) + { + DBG2(DBG_PTS, " '%.*s'", event_len, event_buf); + } + + if (seek_len > 0 && lseek(fd, seek_len, SEEK_CUR) == -1) + { + break; + } + this->list->insert_last(this->list, entry); + } + + DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file, + strerror(errno)); + free_bios_entry(entry); + close(fd); + destroy(this); + + return NULL; +} diff --git a/src/libimcv/pts/pts_ima_bios_list.h b/src/libimcv/pts/pts_ima_bios_list.h new file mode 100644 index 000000000..ad162e15a --- /dev/null +++ b/src/libimcv/pts/pts_ima_bios_list.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_ima_bios_list pts_ima_bios_list + * @{ @ingroup pts + */ + +#ifndef PTS_IMA_BIOS_LIST_H_ +#define PTS_IMA_BIOS_LIST_H_ + +#include <time.h> + +#include <library.h> + +typedef struct pts_ima_bios_list_t pts_ima_bios_list_t; + +/** + * Class retrieving Linux IMA BIOS measurements + * + */ +struct pts_ima_bios_list_t { + + /** + * Get the time the BIOS measurements were taken + * + * @return Measurement time + */ + time_t (*get_time)(pts_ima_bios_list_t *this); + + /** + * Get the number of non-processed BIOS measurements + * + * @return Number of measurements left + */ + int (*get_count)(pts_ima_bios_list_t *this); + + /** + * Get the next BIOS measurement and remove it from the list + * + * @param pcr PCR where the measurement was extended into + * @param measurement Measurement hash + * @return Return code + */ + status_t (*get_next)(pts_ima_bios_list_t *this, uint32_t *pcr, + chunk_t *measurement); + + /** + * Destroys a pts_ima_bios_list_t object. + */ + void (*destroy)(pts_ima_bios_list_t *this); + +}; + +/** + * Create a PTS IMA BIOS measurement object + * + * @param file Pathname pointing to the BIOS measurements + */ +pts_ima_bios_list_t* pts_ima_bios_list_create(char *file); + +#endif /** PTS_IMA_BIOS_LIST_H_ @}*/ diff --git a/src/libimcv/pts/pts_ima_event_list.c b/src/libimcv/pts/pts_ima_event_list.c new file mode 100644 index 000000000..9bff4654b --- /dev/null +++ b/src/libimcv/pts/pts_ima_event_list.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pts_ima_event_list.h" + +#include <utils/debug.h> +#include <crypto/hashers/hasher.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +typedef struct private_pts_ima_event_list_t private_pts_ima_event_list_t; +typedef struct event_entry_t event_entry_t; + +#define IMA_TYPE_LEN 3 +#define IMA_NG_TYPE_LEN 6 +#define IMA_TYPE_LEN_MAX 10 +#define IMA_ALGO_DIGEST_LEN_MAX IMA_ALGO_LEN_MAX + HASH_SIZE_SHA512 + +/** + * Private data of a pts_ima_event_list_t object. + * + */ +struct private_pts_ima_event_list_t { + + /** + * Public pts_ima_event_list_t interface. + */ + pts_ima_event_list_t public; + + /** + * List of BIOS measurement entries + */ + linked_list_t *list; + + /** + * Time when IMA runtime file measurements were taken + */ + time_t creation_time; + +}; + +/** + * Linux IMA runtime file measurement entry + */ +struct event_entry_t { + + /** + * SHA1 measurement hash + */ + chunk_t measurement; + + /** + * IMA-NG hash algorithm name or NULL + */ + char *algo; + + /** + * IMA-NG eventname or IMA filename + */ + char *name; +}; + +/** + * Free an ima_event_t object + */ +static void free_event_entry(event_entry_t *this) +{ + free(this->measurement.ptr); + free(this->algo); + free(this->name); + free(this); +} + +METHOD(pts_ima_event_list_t, get_time, time_t, + private_pts_ima_event_list_t *this) +{ + return this->creation_time; +} + +METHOD(pts_ima_event_list_t, get_count, int, + private_pts_ima_event_list_t *this) +{ + return this->list->get_count(this->list); +} + +METHOD(pts_ima_event_list_t, get_next, status_t, + private_pts_ima_event_list_t *this, chunk_t *measurement, char **algo, + char **name) +{ + event_entry_t *entry; + status_t status; + + status = this->list->remove_first(this->list, (void**)&entry); + *measurement = entry->measurement; + *algo = entry->algo; + *name = entry->name; + free(entry); + + return status; +} + +METHOD(pts_ima_event_list_t, destroy, void, + private_pts_ima_event_list_t *this) +{ + this->list->destroy_function(this->list, (void *)free_event_entry); + free(this); +} + +/** + * See header + */ +pts_ima_event_list_t* pts_ima_event_list_create(char *file) +{ + private_pts_ima_event_list_t *this; + event_entry_t *entry; + uint32_t pcr, type_len, name_len, eventdata_len, algo_digest_len, algo_len; + char type[IMA_TYPE_LEN_MAX]; + char algo_digest[IMA_ALGO_DIGEST_LEN_MAX]; + char *pos, *error = ""; + struct stat st; + ssize_t res; + bool ima_ng; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) + { + DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno)); + return NULL; + } + + if (fstat(fd, &st) == -1) + { + DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file, + strerror(errno)); + close(fd); + return NULL; + } + + INIT(this, + .public = { + .get_time = _get_time, + .get_count = _get_count, + .get_next = _get_next, + .destroy = _destroy, + }, + .creation_time = st.st_ctime, + .list = linked_list_create(), + ); + + while (TRUE) + { + /* read 32 bit PCR number in host order */ + res = read(fd, &pcr, 4); + + /* exit if no more measurement data is available */ + if (res == 0) + { + DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)", + file, this->list->get_count(this->list)); + close(fd); + return &this->public; + } + + /* create and initialize new IMA entry */ + entry = malloc_thing(event_entry_t); + entry->measurement = chunk_alloc(HASH_SIZE_SHA1); + entry->algo = NULL; + entry->name = NULL; + + if (res != 4 || pcr != IMA_PCR) + { + error = "invalid IMA PCR field"; + break; + } + + /* read 20 byte SHA-1 measurement digest */ + if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1) + { + error = "invalid SHA-1 digest field"; + break; + } + + /* read 32 bit length of IMA type string in host order */ + if (read(fd, &type_len, 4) != 4 || type_len > IMA_TYPE_LEN_MAX) + { + error = "invalid IMA type field length"; + break; + } + + /* read and interpret IMA type string */ + if (read(fd, type, type_len) != type_len) + { + error = "invalid IMA type field"; + break; + } + if (type_len == IMA_NG_TYPE_LEN && + memeq(type, "ima-ng", IMA_NG_TYPE_LEN)) + { + ima_ng = TRUE; + } + else if (type_len == IMA_TYPE_LEN && + memeq(type, "ima", IMA_TYPE_LEN)) + { + ima_ng = FALSE; + } + else + { + error = "unknown IMA type"; + break; + } + + if (ima_ng) + { + /* read the 32 bit length of the event data in host order */ + if (read(fd, &eventdata_len, 4) != 4 || eventdata_len < 4) + { + error = "invalid event data field length"; + break; + } + + /* read the 32 bit length of the algo_digest string in host order */ + if (read(fd, &algo_digest_len, 4) != 4 || + algo_digest_len > IMA_ALGO_DIGEST_LEN_MAX || + eventdata_len < 4 + algo_digest_len + 4) + { + error = "invalid digest_with_algo field length"; + break; + } + + /* read the IMA algo_digest string */ + if (read(fd, algo_digest, algo_digest_len) != algo_digest_len) + { + error = "invalid digest_with_algo field"; + break; + } + + /* extract the hash algorithm name */ + pos = memchr(algo_digest, '\0', algo_digest_len); + if (!pos) + { + error = "no algo field"; + break; + } + algo_len = pos - algo_digest + 1; + + if (algo_len > IMA_ALGO_LEN_MAX || + algo_len < IMA_ALGO_LEN_MIN || *(pos - 1) != ':') + { + error = "invalid algo field"; + break; + } + + /* copy and store the hash algorithm name */ + entry->algo = malloc(algo_len); + memcpy(entry->algo, algo_digest, algo_len); + + /* read the 32 bit length of the event name in host order */ + if (read(fd, &name_len, 4) != 4 || + eventdata_len != 4 + algo_digest_len + 4 + name_len) + { + error = "invalid filename field length"; + break; + } + + /* allocate memory for the file name */ + entry->name = malloc(name_len); + + /* read file name */ + if (read(fd, entry->name, name_len) != name_len) + { + error = "invalid filename field"; + break; + } + } + else + { + /* skip SHA-1 digest of the file content */ + if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1) + { + break; + } + + /* read the 32 bit length of the file name in host order */ + if (read(fd, &name_len, 4) != 4 || name_len == UINT32_MAX) + { + error = "invalid filename field length"; + break; + } + + /* allocate memory for the file name */ + entry->name = malloc(name_len + 1); + + /* read file name */ + if (read(fd, entry->name, name_len) != name_len) + { + error = "invalid eventname field"; + break; + } + + /* terminate the file name with a nul character */ + entry->name[name_len] = '\0'; + } + + this->list->insert_last(this->list, entry); + } + + DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error); + free_event_entry(entry); + close(fd); + destroy(this); + + return NULL; +} diff --git a/src/libimcv/pts/pts_ima_event_list.h b/src/libimcv/pts/pts_ima_event_list.h new file mode 100644 index 000000000..bf5478a51 --- /dev/null +++ b/src/libimcv/pts/pts_ima_event_list.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_ima_event_list pts_ima_event_list + * @{ @ingroup pts + */ + +#ifndef PTS_IMA_EVENT_LIST_H_ +#define PTS_IMA_EVENT_LIST_H_ + +#include <time.h> + +#include <library.h> + +typedef struct pts_ima_event_list_t pts_ima_event_list_t; + +#define IMA_PCR 10 +#define IMA_ALGO_LEN_MIN 5 +#define IMA_ALGO_LEN_MAX 8 + + +/** + * Class retrieving Linux IMA file measurements + * + */ +struct pts_ima_event_list_t { + + /** + * Get the time the file measurements were taken + * + * @return Measurement time + */ + time_t (*get_time)(pts_ima_event_list_t *this); + + /** + * Get the number of non-processed file measurements + * + * @return Number of measurements left + */ + int (*get_count)(pts_ima_event_list_t *this); + + /** + * Get the next file measurement and remove it from the list + * + * @param measurement Measurement hash + * @param algo Algorithm used to hash files + " @param name Event name (absolute filename or boot_aggregate) + * @return Return code + */ + status_t (*get_next)(pts_ima_event_list_t *this, chunk_t *measurement, + char **algo, char **name); + + /** + * Destroys a pts_ima_event_list_t object. + */ + void (*destroy)(pts_ima_event_list_t *this); + +}; + +/** + * Create a PTS IMA runtime file measurement object + * + * @param file Pathname pointing to the IMA runtme measurements + */ +pts_ima_event_list_t* pts_ima_event_list_create(char *file); + +#endif /** PTS_IMA_EVENT_LIST_H_ @}*/ diff --git a/src/libimcv/pts/pts_meas_algo.c b/src/libimcv/pts/pts_meas_algo.c new file mode 100644 index 000000000..c06371123 --- /dev/null +++ b/src/libimcv/pts/pts_meas_algo.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pts_meas_algo.h" + +#include <utils/debug.h> + +ENUM_BEGIN(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_NONE, + "None"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA384, PTS_MEAS_ALGO_SHA384, + PTS_MEAS_ALGO_NONE, + "SHA384"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA256, PTS_MEAS_ALGO_SHA256, + PTS_MEAS_ALGO_SHA384, + "SHA256"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1, PTS_MEAS_ALGO_SHA1, + PTS_MEAS_ALGO_SHA256, + "SHA1"); +ENUM_END(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1); + +/** + * Described in header. + */ +bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms) +{ + enumerator_t *enumerator; + hash_algorithm_t hash_alg; + const char *plugin_name; + char format1[] = " %s PTS measurement algorithm %N[%s] available"; + char format2[] = " %s PTS measurement algorithm %N not available"; + + *algorithms = 0; + + enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &hash_alg, &plugin_name)) + { + if (hash_alg == HASH_SHA1) + { + *algorithms |= PTS_MEAS_ALGO_SHA1; + DBG2(DBG_PTS, format1, "mandatory", hash_algorithm_names, hash_alg, + plugin_name); + } + else if (hash_alg == HASH_SHA256) + { + *algorithms |= PTS_MEAS_ALGO_SHA256; + DBG2(DBG_PTS, format1, "mandatory", hash_algorithm_names, hash_alg, + plugin_name); + } + else if (hash_alg == HASH_SHA384) + { + *algorithms |= PTS_MEAS_ALGO_SHA384; + DBG2(DBG_PTS, format1, "optional ", hash_algorithm_names, hash_alg, + plugin_name); + } + } + enumerator->destroy(enumerator); + + if (!(*algorithms & PTS_MEAS_ALGO_SHA384)) + { + DBG1(DBG_PTS, format2, "optional ", hash_algorithm_names, HASH_SHA384); + } + if ((*algorithms & PTS_MEAS_ALGO_SHA1) && + (*algorithms & PTS_MEAS_ALGO_SHA256)) + { + return TRUE; + } + if (!(*algorithms & PTS_MEAS_ALGO_SHA1)) + { + DBG1(DBG_PTS, format2, "mandatory", hash_algorithm_names, HASH_SHA1); + } + if (!(*algorithms & PTS_MEAS_ALGO_SHA256)) + { + DBG1(DBG_PTS, format2, "mandatory", hash_algorithm_names, HASH_SHA256); + } + return FALSE; +} + +/** + * Described in header. + */ +bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms) +{ + if (strcaseeq(hash_alg, "sha384") || strcaseeq(hash_alg, "sha2_384")) + { + /* nothing to update, all algorithms are supported */ + return TRUE; + } + if (strcaseeq(hash_alg, "sha256") || strcaseeq(hash_alg, "sha2_256")) + { + /* remove SHA384algorithm */ + *algorithms &= ~PTS_MEAS_ALGO_SHA384; + return TRUE; + } + if (strcaseeq(hash_alg, "sha1")) + { + /* remove SHA384 and SHA256 algorithms */ + *algorithms &= ~(PTS_MEAS_ALGO_SHA384 | PTS_MEAS_ALGO_SHA256); + return TRUE; + } + DBG1(DBG_PTS, "unknown hash algorithm '%s' configured", hash_alg); + return FALSE; +} + +/** + * Described in header. + */ +pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos, + pts_meas_algorithms_t offered_algos) +{ + if ((supported_algos & PTS_MEAS_ALGO_SHA384) && + (offered_algos & PTS_MEAS_ALGO_SHA384)) + { + return PTS_MEAS_ALGO_SHA384; + } + if ((supported_algos & PTS_MEAS_ALGO_SHA256) && + (offered_algos & PTS_MEAS_ALGO_SHA256)) + { + return PTS_MEAS_ALGO_SHA256; + } + if ((supported_algos & PTS_MEAS_ALGO_SHA1) && + (offered_algos & PTS_MEAS_ALGO_SHA1)) + { + return PTS_MEAS_ALGO_SHA1; + } + return PTS_MEAS_ALGO_NONE; +} + +/** + * Described in header. + */ +hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm) +{ + switch (algorithm) + { + case PTS_MEAS_ALGO_SHA1: + return HASH_SHA1; + case PTS_MEAS_ALGO_SHA256: + return HASH_SHA256; + case PTS_MEAS_ALGO_SHA384: + return HASH_SHA384; + default: + return HASH_UNKNOWN; + } +} + +/** + * Described in header. + */ +size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm) +{ + switch (algorithm) + { + case PTS_MEAS_ALGO_SHA1: + return HASH_SIZE_SHA1; + case PTS_MEAS_ALGO_SHA256: + return HASH_SIZE_SHA256; + case PTS_MEAS_ALGO_SHA384: + return HASH_SIZE_SHA384; + case PTS_MEAS_ALGO_NONE: + default: + return 0; + } +} + diff --git a/src/libimcv/pts/pts_meas_algo.h b/src/libimcv/pts/pts_meas_algo.h new file mode 100644 index 000000000..eec7e7981 --- /dev/null +++ b/src/libimcv/pts/pts_meas_algo.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2014 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_meas_algo pts_meas_algo + * @{ @ingroup pts + */ + +#ifndef PTS_MEAS_ALGO_H_ +#define PTS_MEAS_ALGO_H_ + +#include <library.h> +#include <crypto/hashers/hasher.h> + +typedef enum pts_meas_algorithms_t pts_meas_algorithms_t; + +/** + * PTS Measurement Algorithms + */ +enum pts_meas_algorithms_t { + PTS_MEAS_ALGO_NONE = 0, + PTS_MEAS_ALGO_SHA384 = (1<<13), + PTS_MEAS_ALGO_SHA256 = (1<<14), + PTS_MEAS_ALGO_SHA1 = (1<<15) +}; + +/** + * enum name for pts_meas_algorithms_t. + */ +extern enum_name_t *pts_meas_algorithm_names; + +/** + * Diffie-Hellman Hash Algorithm Values + * see section 3.8.5 of PTS Protocol: Binding to TNC IF-M Specification + * + * 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |1|2|3|R|R|R|R|R|R|R|R|R|R|R|R|R| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +/** + * Probe available PTS measurement algorithms + * + * @param algorithms set of available algorithms + * @return TRUE if mandatory algorithms are available + */ +bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms); + +/** + * Update supported PTS measurement algorithms according to configuration + * + * 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 + * + * The PTS-IMC is expected to select the strongest supported algorithm + * + * @param hash_alg configured hash algorithm + * @param algorithms returns set of available PTS measurement algorithms + */ +bool pts_meas_algo_update(char *hash_alg, pts_meas_algorithms_t *algorithms); + +/** + * Select the strongest PTS measurement algorithm + * among a set of offered PTS measurement algorithms + * + * @param supported_algos set of supported PTS measurement algorithms + * @param offered_algos set of offered PTS measurements algorithms + * @return selected algorithm + */ +pts_meas_algorithms_t pts_meas_algo_select(pts_meas_algorithms_t supported_algos, + pts_meas_algorithms_t offered_algos); + +/** + * Convert pts_meas_algorithms_t to hash_algorithm_t + * + * @param algorithm PTS measurement algorithm type + * @return libstrongswan hash algorithm type + */ +hash_algorithm_t pts_meas_algo_to_hash(pts_meas_algorithms_t algorithm); + +/** + * Return the hash size of a pts_meas_algorithm + * + * @param algorithm PTS measurement algorithm type + * @return hash size in bytes + */ +size_t pts_meas_algo_hash_size(pts_meas_algorithms_t algorithm); + +#endif /** PTS_MEAS_ALGO_H_ @}*/ diff --git a/src/libimcv/pts/pts_pcr.c b/src/libimcv/pts/pts_pcr.c new file mode 100644 index 000000000..0af93b608 --- /dev/null +++ b/src/libimcv/pts/pts_pcr.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2012 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_pcr.h" + +#include <utils/debug.h> + +#include <stdarg.h> + +typedef struct private_pts_pcr_t private_pts_pcr_t; + +/** + * Private data of a pts_pcr_t object. + * + */ +struct private_pts_pcr_t { + + /** + * Public pts_pcr_t interface. + */ + pts_pcr_t public; + + /** + * Shadow PCR registers + */ + chunk_t pcrs[PTS_PCR_MAX_NUM]; + + /** + * Number of extended PCR registers + */ + u_int32_t pcr_count; + + /** + * Highest extended PCR register + */ + u_int32_t pcr_max; + + /** + * Bitmap of extended PCR registers + */ + u_int8_t pcr_select[PTS_PCR_MAX_NUM / 8]; + + /** + * Hasher used to extend shadow PCRs + */ + hasher_t *hasher; + +}; + +METHOD(pts_pcr_t, get_count, u_int32_t, + private_pts_pcr_t *this) +{ + return this->pcr_count; +} + +METHOD(pts_pcr_t, select_pcr, bool, + private_pts_pcr_t *this, u_int32_t pcr) +{ + u_int32_t i, f; + + if (pcr >= PTS_PCR_MAX_NUM) + { + DBG1(DBG_PTS, "PCR %2u: number is larger than maximum of %u", + pcr, PTS_PCR_MAX_NUM-1); + return FALSE; + } + + /* Determine PCR selection flag */ + i = pcr / 8; + f = 1 << (pcr - 8*i); + + /* Has this PCR already been selected? */ + if (!(this->pcr_select[i] & f)) + { + this->pcr_select[i] |= f; + this->pcr_max = max(this->pcr_max, pcr); + this->pcr_count++; + } + return TRUE; +} + +METHOD(pts_pcr_t, get_selection_size, size_t, + private_pts_pcr_t *this) +{ + + /** + * A TPM v1.2 has 24 PCR Registers so the bitmask field length + * used by TrouSerS is at least 3 bytes + */ + return PTS_PCR_MAX_NUM / 8; +} + +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** current PCR */ + u_int32_t pcr; + /** back reference to parent */ + private_pts_pcr_t *pcrs; +} pcr_enumerator_t; + +/** + * Implementation of enumerator.enumerate + */ +static bool pcr_enumerator_enumerate(pcr_enumerator_t *this, ...) +{ + u_int32_t *pcr, i, f; + va_list args; + + va_start(args, this); + pcr = va_arg(args, u_int32_t*); + va_end(args); + + while (this->pcr <= this->pcrs->pcr_max) + { + /* Determine PCR selection flag */ + i = this->pcr / 8; + f = 1 << (this->pcr - 8*i); + + /* Assign current PCR to output argument and increase */ + *pcr = this->pcr++; + + /* return if PCR is selected */ + if (this->pcrs->pcr_select[i] & f) + { + return TRUE; + } + } + return FALSE; +} + +METHOD(pts_pcr_t, create_enumerator, enumerator_t*, + private_pts_pcr_t *this) +{ + pcr_enumerator_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = (void*)pcr_enumerator_enumerate, + .destroy = (void*)free, + }, + .pcrs = this, + ); + + return (enumerator_t*)enumerator; +} + +METHOD(pts_pcr_t, get, chunk_t, + private_pts_pcr_t *this, u_int32_t pcr) +{ + return (pcr < PTS_PCR_MAX_NUM) ? this->pcrs[pcr] : chunk_empty; +} + +METHOD(pts_pcr_t, set, bool, + private_pts_pcr_t *this, u_int32_t pcr, chunk_t value) +{ + if (value.len != PTS_PCR_LEN) + { + DBG1(DBG_PTS, "PCR %2u: value does not fit", pcr); + return FALSE; + } + if (select_pcr(this, pcr)) + { + memcpy(this->pcrs[pcr].ptr, value.ptr, PTS_PCR_LEN); + return TRUE; + } + return FALSE; +} + +METHOD(pts_pcr_t, extend, chunk_t, + private_pts_pcr_t *this, u_int32_t pcr, chunk_t measurement) +{ + if (measurement.len != PTS_PCR_LEN) + { + DBG1(DBG_PTS, "PCR %2u: measurement does not fit", pcr); + return chunk_empty; + } + if (!select_pcr(this, pcr)) + { + return chunk_empty; + } + if (!this->hasher->get_hash(this->hasher, this->pcrs[pcr] , NULL) || + !this->hasher->get_hash(this->hasher, measurement, this->pcrs[pcr].ptr)) + { + DBG1(DBG_PTS, "PCR %2u: not extended due to hasher problem", pcr); + return chunk_empty; + } + return this->pcrs[pcr]; +} + +METHOD(pts_pcr_t, get_composite, chunk_t, + private_pts_pcr_t *this) +{ + chunk_t composite; + enumerator_t *enumerator; + u_int16_t selection_size; + u_int32_t pcr_field_size, pcr; + u_char *pos; + + selection_size = get_selection_size(this); + pcr_field_size = this->pcr_count * PTS_PCR_LEN; + + composite = chunk_alloc(2 + selection_size + 4 + pcr_field_size); + pos = composite.ptr; + htoun16(pos, selection_size); + pos += 2; + memcpy(pos, this->pcr_select, selection_size); + pos += selection_size; + htoun32(pos, pcr_field_size); + pos += 4; + + enumerator = create_enumerator(this); + while (enumerator->enumerate(enumerator, &pcr)) + { + memcpy(pos, this->pcrs[pcr].ptr, PTS_PCR_LEN); + pos += PTS_PCR_LEN; + } + enumerator->destroy(enumerator); + + DBG3(DBG_PTS, "constructed PCR Composite: %B", &composite); + return composite; +} + +METHOD(pts_pcr_t, destroy, void, + private_pts_pcr_t *this) +{ + u_int32_t i; + + for (i = 0; i < PTS_PCR_MAX_NUM; i++) + { + free(this->pcrs[i].ptr); + } + this->hasher->destroy(this->hasher); + free(this); +} + +/** + * See header + */ +pts_pcr_t *pts_pcr_create(void) +{ + private_pts_pcr_t *this; + hasher_t *hasher; + u_int32_t i; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + DBG1(DBG_PTS, "%N hasher could not be created", + hash_algorithm_short_names, HASH_SHA1); + return NULL; + } + + INIT(this, + .public = { + .get_count = _get_count, + .select_pcr = _select_pcr, + .get_selection_size = _get_selection_size, + .create_enumerator = _create_enumerator, + .get = _get, + .set = _set, + .extend = _extend, + .get_composite = _get_composite, + .destroy = _destroy, + }, + .hasher = hasher, + ); + + for (i = 0; i < PTS_PCR_MAX_NUM; i++) + { + this->pcrs[i] = chunk_alloc(PTS_PCR_LEN); + memset(this->pcrs[i].ptr, 0x00, PTS_PCR_LEN); + } + + return &this->public; +} + diff --git a/src/libimcv/pts/pts_pcr.h b/src/libimcv/pts/pts_pcr.h new file mode 100644 index 000000000..f638b5ee4 --- /dev/null +++ b/src/libimcv/pts/pts_pcr.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2012 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_pcr pts_pcr + * @{ @ingroup pts + */ + +#ifndef PTS_PCR_H_ +#define PTS_PCR_H_ + +typedef struct pts_pcr_t pts_pcr_t; + +#include <library.h> + +/** + * Maximum number of PCR's of TPM, TPM Spec 1.2 + */ +#define PTS_PCR_MAX_NUM 24 + +/** + * Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2 + */ +#define PTS_PCR_LEN 20 + +/** + * Class implementing a shadow PCR register set + */ +struct pts_pcr_t { + + /** + * Get the number of selected PCRs + * + * @return number of selected PCRs + */ + u_int32_t (*get_count)(pts_pcr_t *this); + + /** + * Mark a PCR as selected + * + * @param pcr index of PCR + * @return TRUE if PCR index exists + */ + bool (*select_pcr)(pts_pcr_t *this, u_int32_t pcr); + + /** + * Get the size of the selection field in bytes + * + * @return number of bytes written + */ + size_t (*get_selection_size)(pts_pcr_t *this); + + /** + * Create an enumerator over all selected PCR indexes + * + * @return enumerator + */ + enumerator_t* (*create_enumerator)(pts_pcr_t *this); + + /** + * Get the current content of a PCR + * + * @param pcr index of PCR + * @return content of PCR + */ + chunk_t (*get)(pts_pcr_t *this, u_int32_t pcr); + + /** + * Set the content of a PCR + * + * @param pcr index of PCR + * @param value new value of PCR + * @return TRUE if value could be set + */ + bool (*set)(pts_pcr_t *this, u_int32_t pcr, chunk_t value); + + /** + * Extend the content of a PCR + * + * @param pcr index of PCR + * @param measurement measurment value to be extended into PCR + * @return new content of PCR + */ + chunk_t (*extend)(pts_pcr_t *this, u_int32_t pcr, chunk_t measurement); + + /** + * Create a PCR Composite object over all selected PCRs + * + * @return PCR Composite object (must be freed) + */ + chunk_t (*get_composite)(pts_pcr_t *this); + + /** + + * Destroys a pts_pcr_t object. + */ + void (*destroy)(pts_pcr_t *this); + +}; + +/** + * Creates an pts_pcr_t object + */ +pts_pcr_t* pts_pcr_create(void); + +#endif /** PTS_PCR_H_ @}*/ diff --git a/src/libimcv/pts/pts_proto_caps.h b/src/libimcv/pts/pts_proto_caps.h new file mode 100644 index 000000000..4346d9b79 --- /dev/null +++ b/src/libimcv/pts/pts_proto_caps.h @@ -0,0 +1,44 @@ +/* + * 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 pts_proto_caps pts_proto_caps + * @{ @ingroup pts + */ + +#ifndef PTS_PROTO_CAPS_H_ +#define PTS_PROTO_CAPS_H_ + +typedef enum pts_proto_caps_flag_t pts_proto_caps_flag_t; + +#include <library.h> + +/** + * PTS Protocol Capabilities Flags + */ +enum pts_proto_caps_flag_t { + /** XML based Evidence Support flag */ + PTS_PROTO_CAPS_X = (1<<0), + /** Trusted Platform Evidence flag */ + PTS_PROTO_CAPS_T = (1<<1), + /** DH Nonce Negotiation Support flag */ + PTS_PROTO_CAPS_D = (1<<2), + /** Verification Support flag */ + PTS_PROTO_CAPS_V = (1<<3), + /** Current (In-Memory) Evidence Support flag */ + PTS_PROTO_CAPS_C = (1<<4), +}; + +#endif /** PTS_PROTO_CAPS_H_ @}*/ diff --git a/src/libimcv/pts/pts_req_func_comp_evid.h b/src/libimcv/pts/pts_req_func_comp_evid.h new file mode 100644 index 000000000..bbf5bbf5b --- /dev/null +++ b/src/libimcv/pts/pts_req_func_comp_evid.h @@ -0,0 +1,42 @@ +/* + * 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 pts_req_func_comp_evid pts_req_func_comp_evid + * @{ @ingroup pts + */ + +#ifndef PTS_REQ_FUNC_COMP_EVID_H_ +#define PTS_REQ_FUNC_COMP_EVID_H_ + +typedef enum pts_req_func_comp_evid_t pts_req_func_comp_evid_t; + +#include <library.h> + +/** + * PTS Request Functional Component Evidence Flags + */ +enum pts_req_func_comp_evid_t { + /** Transitive Trust Chain flag */ + PTS_REQ_FUNC_COMP_EVID_TTC = (1<<7), + /** Verify Component flag */ + PTS_REQ_FUNC_COMP_EVID_VER = (1<<6), + /** Current Evidence flag */ + PTS_REQ_FUNC_COMP_EVID_CURR = (1<<5), + /** PCR Information flag */ + PTS_REQ_FUNC_COMP_EVID_PCR = (1<<4), +}; + +#endif /** PTS_FUNCT_COMP_EVID_REQ_H_ @}*/ diff --git a/src/libimcv/pts/pts_simple_evid_final.h b/src/libimcv/pts/pts_simple_evid_final.h new file mode 100644 index 000000000..0c8dea0cc --- /dev/null +++ b/src/libimcv/pts/pts_simple_evid_final.h @@ -0,0 +1,47 @@ +/* + * 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 pts_simple_evid_final pts_rsimple_evid_final + * @{ @ingroup pts + */ + +#ifndef PTS_SIMPLE_EVID_FINAL_H_ +#define PTS_SIMPLE_EVID_FINAL_H_ + +typedef enum pts_simple_evid_final_flag_t pts_simple_evid_final_flag_t; + +#include <library.h> + +/** + * PTS Simple Evidence Final Flags + */ +enum pts_simple_evid_final_flag_t { + /** TPM PCR Composite and TPM Quote Signature not included */ + PTS_SIMPLE_EVID_FINAL_NO = 0x00, + /** TPM PCR Composite and TPM Quote Signature included + * using TPM_QUOTE_INFO */ + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO = 0x40, + /** TPM PCR Composite and TPM Quote Signature included + * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO not appended */ + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 = 0x80, + /** TPM PCR Composite and TPM Quote Signature included + * using TPM_QUOTE_INFO2, TPM_CAP_VERSION_INFO appended */ + PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2_CAP_VER = 0xC0, + /** Evidence Signature included */ + PTS_SIMPLE_EVID_FINAL_EVID_SIG = 0x20, +}; + +#endif /** PTS_SIMPLE_EVID_FINAL_H_ @}*/ |