summaryrefslogtreecommitdiff
path: root/src/libimcv/pts
diff options
context:
space:
mode:
authorRomain Francoise <rfrancoise@debian.org>2014-10-21 19:28:38 +0200
committerRomain Francoise <rfrancoise@debian.org>2014-10-21 19:41:50 +0200
commitb23b0e5609ed4b3d29396a1727aab035fa4a395f (patch)
tree091d0b144dd92a0c124b7fbe9eae68f79cb975dc /src/libimcv/pts
parent4a01a7e2574040cf246fd00ebff173b873c17349 (diff)
downloadvyos-strongswan-b23b0e5609ed4b3d29396a1727aab035fa4a395f.tar.gz
vyos-strongswan-b23b0e5609ed4b3d29396a1727aab035fa4a395f.zip
Import upstream release 5.2.1
Diffstat (limited to 'src/libimcv/pts')
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_func_name.c45
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_func_name.h85
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_ima.c914
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_ima.h35
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_tboot.c362
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_tboot.h35
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_tgrub.c208
-rw-r--r--src/libimcv/pts/components/ita/ita_comp_tgrub.h35
-rw-r--r--src/libimcv/pts/components/pts_comp_evidence.c255
-rw-r--r--src/libimcv/pts/components/pts_comp_evidence.h170
-rw-r--r--src/libimcv/pts/components/pts_comp_func_name.c162
-rw-r--r--src/libimcv/pts/components/pts_comp_func_name.h103
-rw-r--r--src/libimcv/pts/components/pts_component.h109
-rw-r--r--src/libimcv/pts/components/pts_component_manager.c315
-rw-r--r--src/libimcv/pts/components/pts_component_manager.h124
-rw-r--r--src/libimcv/pts/components/tcg/tcg_comp_func_name.c48
-rw-r--r--src/libimcv/pts/components/tcg/tcg_comp_func_name.h98
-rw-r--r--src/libimcv/pts/pts.c1198
-rw-r--r--src/libimcv/pts/pts.h315
-rw-r--r--src/libimcv/pts/pts_creds.c136
-rw-r--r--src/libimcv/pts/pts_creds.h55
-rw-r--r--src/libimcv/pts/pts_database.c432
-rw-r--r--src/libimcv/pts/pts_database.h155
-rw-r--r--src/libimcv/pts/pts_dh_group.c184
-rw-r--r--src/libimcv/pts/pts_dh_group.h107
-rw-r--r--src/libimcv/pts/pts_error.c99
-rw-r--r--src/libimcv/pts/pts_error.h89
-rw-r--r--src/libimcv/pts/pts_file_meas.c414
-rw-r--r--src/libimcv/pts/pts_file_meas.h112
-rw-r--r--src/libimcv/pts/pts_file_meta.c96
-rw-r--r--src/libimcv/pts/pts_file_meta.h85
-rw-r--r--src/libimcv/pts/pts_file_type.c33
-rw-r--r--src/libimcv/pts/pts_file_type.h63
-rw-r--r--src/libimcv/pts/pts_ima_bios_list.c294
-rw-r--r--src/libimcv/pts/pts_ima_bios_list.h74
-rw-r--r--src/libimcv/pts/pts_ima_event_list.c330
-rw-r--r--src/libimcv/pts/pts_ima_event_list.h80
-rw-r--r--src/libimcv/pts/pts_meas_algo.c176
-rw-r--r--src/libimcv/pts/pts_meas_algo.h106
-rw-r--r--src/libimcv/pts/pts_pcr.c289
-rw-r--r--src/libimcv/pts/pts_pcr.h118
-rw-r--r--src/libimcv/pts/pts_proto_caps.h44
-rw-r--r--src/libimcv/pts/pts_req_func_comp_evid.h42
-rw-r--r--src/libimcv/pts/pts_simple_evid_final.h47
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",&quote_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_ @}*/