summaryrefslogtreecommitdiff
path: root/src/libpts/pts
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2013-10-17 21:23:38 +0200
committerYves-Alexis Perez <corsac@debian.org>2013-10-17 21:23:38 +0200
commit9d37ad77ef660b92ea51b69d74e14f931d2a04e2 (patch)
treed6bbb4a5fed1959f8675df9ee7c03713b543fcc9 /src/libpts/pts
parent104f57d4b0fb6d7547d6898352eaa5fb4b222010 (diff)
parente5ee4e7fcdd58b7d86bf1b458da2c63e8e19627b (diff)
downloadvyos-strongswan-9d37ad77ef660b92ea51b69d74e14f931d2a04e2.tar.gz
vyos-strongswan-9d37ad77ef660b92ea51b69d74e14f931d2a04e2.zip
Merge tag 'v5.1.0-1' into sid
tag strongSwan 5.1.0-1
Diffstat (limited to 'src/libpts/pts')
-rw-r--r--src/libpts/pts/components/ita/ita_comp_ima.c815
-rw-r--r--src/libpts/pts/components/ita/ita_comp_ima.h5
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tboot.c157
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tboot.h5
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tgrub.c73
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tgrub.h5
-rw-r--r--src/libpts/pts/components/pts_comp_evidence.c26
-rw-r--r--src/libpts/pts/components/pts_comp_evidence.h4
-rw-r--r--src/libpts/pts/components/pts_comp_func_name.c11
-rw-r--r--src/libpts/pts/components/pts_comp_func_name.h11
-rw-r--r--src/libpts/pts/components/pts_component.h24
-rw-r--r--src/libpts/pts/components/pts_component_manager.c16
-rw-r--r--src/libpts/pts/components/pts_component_manager.h3
-rw-r--r--src/libpts/pts/pts.c606
-rw-r--r--src/libpts/pts/pts.h62
-rw-r--r--src/libpts/pts/pts_creds.c2
-rw-r--r--src/libpts/pts/pts_database.c263
-rw-r--r--src/libpts/pts/pts_database.h58
-rw-r--r--src/libpts/pts/pts_dh_group.c4
-rw-r--r--src/libpts/pts/pts_dh_group.h10
-rw-r--r--src/libpts/pts/pts_error.c12
-rw-r--r--src/libpts/pts/pts_file_meas.c182
-rw-r--r--src/libpts/pts/pts_file_meas.h30
-rw-r--r--src/libpts/pts/pts_file_meta.c4
-rw-r--r--src/libpts/pts/pts_meas_algo.c25
-rw-r--r--src/libpts/pts/pts_meas_algo.h9
-rw-r--r--src/libpts/pts/pts_pcr.c289
-rw-r--r--src/libpts/pts/pts_pcr.h118
28 files changed, 1941 insertions, 888 deletions
diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c
index a7da76651..02470f5f5 100644
--- a/src/libpts/pts/components/ita/ita_comp_ima.c
+++ b/src/libpts/pts/components/ita/ita_comp_ima.c
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
- *
+ * Copyright (C) 2011-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,9 +17,10 @@
#include "ita_comp_func_name.h"
#include "libpts.h"
+#include "pts/pts_pcr.h"
#include "pts/components/pts_component.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <pen/pen.h>
#include <sys/types.h>
@@ -29,11 +29,25 @@
#include <fcntl.h>
#include <errno.h>
-#define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/"
-#define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements"
-#define IMA_PCR_MAX 16
+#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_PCR 10
+#define IMA_TYPE_LEN 3
+#define IMA_FILENAME_LEN_MAX 255
typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
+typedef struct bios_entry_t bios_entry_t;
+typedef struct ima_entry_t ima_entry_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.
@@ -67,52 +81,101 @@ struct pts_ita_comp_ima_t {
pts_database_t *pts_db;
/**
- * Primary key for Component Functional Name database entry
+ * Primary key for AIK database entry
*/
- int cid;
+ int kid;
/**
- * Primary key for AIK database entry
+ * Primary key for IMA BIOS Component Functional Name database entry
*/
- int kid;
+ int bios_cid;
+
+ /**
+ * Primary key for IMA Runtime Component Functional Name database entry
+ */
+ int ima_cid;
/**
- * Component is registering measurements
+ * Component is registering IMA BIOS measurements
*/
- bool is_registering;
+ bool is_bios_registering;
+
+ /**
+ * Component is registering IMA boot aggregate measurement
+ */
+ bool is_ima_registering;
+
+ /**
+ * Measurement sequence number
+ */
+ int seq_no;
/**
- * IMA BIOS measurement time
+ * Expected IMA BIOS measurement count
*/
- time_t bios_measurement_time;
+ int bios_count;
/**
* IMA BIOS measurements
*/
- linked_list_t *list;
+ linked_list_t *bios_list;
/**
- * Expected measurement count
+ * IMA runtime file measurements
+ */
+ linked_list_t *ima_list;
+
+ /**
+ * Whether to send pcr_before and pcr_after info
+ */
+ bool pcr_info;
+
+ /**
+ * IMA measurement time
+ */
+ time_t measurement_time;
+
+ /**
+ * IMA state machine
+ */
+ ima_state_t state;
+
+ /**
+ * Total number of component measurements
*/
int count;
/**
- * Measurement sequence number
+ * Number of successful component measurements
*/
- int seq_no;
+ int count_ok;
/**
- * Shadow PCR registers
+ * Number of unknown component measurements
*/
- chunk_t pcrs[IMA_PCR_MAX];
-};
+ int count_unknown;
-typedef struct entry_t entry_t;
+ /**
+ * Number of differing component measurements
+ */
+ int count_differ;
+
+ /**
+ * Number of failed component measurements
+ */
+ int count_failed;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+
+};
/**
- * Linux IMA measurement entry
+ * Linux IMA BIOS measurement entry
*/
-struct entry_t {
+struct bios_entry_t {
/**
* PCR register
@@ -121,26 +184,53 @@ struct entry_t {
/**
* SHA1 measurement hash
- */
+ */
+ chunk_t measurement;
+};
+
+/**
+ * Linux IMA runtime file measurement entry
+ */
+struct ima_entry_t {
+
+ /**
+ * SHA1 measurement hash
+ */
chunk_t measurement;
+
+ /**
+ * absolute path of executable files or basename of dynamic libraries
+ */
+ char *filename;
};
/**
- * Free an entry_t object
+ * Free a bios_entry_t object
+ */
+static void free_bios_entry(bios_entry_t *this)
+{
+ free(this->measurement.ptr);
+ free(this);
+}
+
+/**
+ * Free an ima_entry_t object
*/
-static void free_entry(entry_t *this)
+static void free_ima_entry(ima_entry_t *this)
{
free(this->measurement.ptr);
+ free(this->filename);
free(this);
}
/**
* Load a PCR measurement file and determine the creation date
*/
-static bool load_measurements(char *file, linked_list_t *list, time_t *created)
+static bool load_bios_measurements(char *file, linked_list_t *list,
+ time_t *created)
{
u_int32_t pcr, num, len;
- entry_t *entry;
+ bios_entry_t *entry;
struct stat st;
ssize_t res;
int fd;
@@ -148,13 +238,13 @@ static bool load_measurements(char *file, linked_list_t *list, time_t *created)
fd = open(file, O_RDONLY);
if (fd == -1)
{
- DBG1(DBG_PTS, " opening '%s' failed: %s", file, strerror(errno));
+ DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
return FALSE;
}
if (fstat(fd, &st) == -1)
{
- DBG1(DBG_PTS, " getting statistics of '%s' failed: %s", file,
+ DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
strerror(errno));
close(fd);
return FALSE;
@@ -167,12 +257,12 @@ static bool load_measurements(char *file, linked_list_t *list, time_t *created)
if (res == 0)
{
DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
- file, list->get_count(list));
+ file, list->get_count(list));
close(fd);
return TRUE;
}
- entry = malloc_thing(entry_t);
+ entry = malloc_thing(bios_entry_t);
entry->pcr = pcr;
entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
@@ -199,12 +289,190 @@ static bool load_measurements(char *file, linked_list_t *list, time_t *created)
list->insert_last(list, entry);
}
- DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s",
- file, strerror(errno));
+ DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file,
+ strerror(errno));
+ free_bios_entry(entry);
close(fd);
return FALSE;
}
+/**
+ * Load an IMA runtime measurement file and determine the creation and
+ * update dates
+ */
+static bool load_runtime_measurements(char *file, linked_list_t *list,
+ time_t *created)
+{
+ u_int32_t pcr, len;
+ ima_entry_t *entry;
+ char type[IMA_TYPE_LEN];
+ 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 TRUE;
+ }
+
+ if (fstat(fd, &st) == -1)
+ {
+ DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
+ strerror(errno));
+ close(fd);
+ return FALSE;
+ }
+ *created = st.st_ctime;
+
+ while (TRUE)
+ {
+ res = read(fd, &pcr, 4);
+ if (res == 0)
+ {
+ DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
+ file, list->get_count(list));
+ close(fd);
+ return TRUE;
+ }
+
+ entry = malloc_thing(ima_entry_t);
+ entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
+ entry->filename = NULL;
+
+ if (res != 4 || pcr != IMA_PCR)
+ {
+ break;
+ }
+ if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
+ {
+ break;
+ }
+ if (read(fd, &len, 4) != 4 || len != IMA_TYPE_LEN)
+ {
+ break;
+ }
+ if (read(fd, type, IMA_TYPE_LEN) != IMA_TYPE_LEN ||
+ memcmp(type, "ima", IMA_TYPE_LEN))
+ {
+ break;
+ }
+ if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1)
+ {
+ break;
+ }
+ if (read(fd, &len, 4) != 4)
+ {
+ break;
+ }
+ entry->filename = malloc(len + 1);
+ if (read(fd, entry->filename, len) != len)
+ {
+ break;
+ }
+ entry->filename[len] = '\0';
+
+ list->insert_last(list, entry);
+ }
+
+ DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s",
+ file, strerror(errno));
+ free_ima_entry(entry);
+ close(fd);
+ return FALSE;
+}
+
+/**
+ * Extend measurement into PCR an create evidence
+ */
+static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
+ u_int8_t qualifier, pts_pcr_t *pcrs,
+ u_int32_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->measurement_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;
+}
+
+/**
+ * Compute and check boot aggregate value by hashing PCR0 to PCR7
+ */
+static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement)
+{
+ u_int32_t i;
+ u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
+ u_char pcr_buffer[HASH_SIZE_SHA1];
+ chunk_t file_name, boot_aggregate;
+ hasher_t *hasher;
+ 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)
+ {
+ boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer));
+ memset(filename_buffer, 0, sizeof(filename_buffer));
+ strcpy(filename_buffer, "boot_aggregate");
+ file_name = chunk_create (filename_buffer, sizeof(filename_buffer));
+
+ pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer) &&
+ hasher->get_hash(hasher, boot_aggregate, NULL) &&
+ hasher->get_hash(hasher, file_name, boot_aggregate.ptr);
+ }
+ hasher->destroy(hasher);
+
+ 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)
{
@@ -224,193 +492,446 @@ METHOD(pts_component_t, get_depth, u_int32_t,
}
METHOD(pts_component_t, measure, status_t,
- pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
+ pts_ita_comp_ima_t *this, u_int8_t qualifier, pts_t *pts,
+ pts_comp_evidence_t **evidence)
{
- pts_comp_evidence_t *evid;
- chunk_t pcr_before, pcr_after;
- pts_pcr_transform_t pcr_transform;
- pts_meas_algorithms_t hash_algo;
- size_t pcr_len;
- entry_t *entry;
- hasher_t *hasher;
+ bios_entry_t *bios_entry;
+ ima_entry_t *ima_entry;
+ pts_pcr_t *pcrs;
+ pts_comp_evidence_t *evid = NULL;
+ status_t status;
- hash_algo = PTS_MEAS_ALGO_SHA1;
- pcr_len = pts->get_pcr_len(pts);
- pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
+ pcrs = pts->get_pcrs(pts);
- if (this->list->get_count(this->list) == 0)
+ if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
+ PTS_ITA_QUALIFIER_TYPE_TRUSTED))
{
- if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH, this->list,
- &this->bios_measurement_time))
+ switch (this->state)
{
- return FAILED;
+ case IMA_STATE_INIT:
+ if (!load_bios_measurements(IMA_BIOS_MEASUREMENTS,
+ this->bios_list, &this->measurement_time))
+ {
+ return FAILED;
+ }
+ 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->remove_first(this->bios_list,
+ (void**)&bios_entry);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_PTS, "could not retrieve bios measurement entry");
+ return status;
+ }
+ evid = extend_pcr(this, qualifier, pcrs, bios_entry->pcr,
+ bios_entry->measurement);
+ free(bios_entry);
+
+ 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:
+ if (!load_runtime_measurements(IMA_RUNTIME_MEASUREMENTS,
+ this->ima_list, &this->measurement_time))
+ {
+ return FAILED;
+ }
+ this->state = IMA_STATE_BOOT_AGGREGATE;
+ /* fall through to next state */
+ case IMA_STATE_BOOT_AGGREGATE:
+ case IMA_STATE_RUNTIME:
+ status = this->ima_list->remove_first(this->ima_list,
+ (void**)&ima_entry);
+ 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, ima_entry->measurement))
+ {
+ return FAILED;
+ }
+ }
+ evid = extend_pcr(this, qualifier, pcrs, IMA_PCR,
+ ima_entry->measurement);
+ if (evid)
+ {
+ evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
+ ima_entry->filename);
+ }
+ free(ima_entry->filename);
+ free(ima_entry);
+
+ this->state = this->ima_list->get_count(this->ima_list) ?
+ IMA_STATE_RUNTIME : IMA_STATE_END;
+ break;
+ default:
+ return FAILED;
}
}
-
- if (this->list->remove_first(this->list, (void**)&entry) != SUCCESS)
+ else
{
- DBG1(DBG_PTS, "could not retrieve measurement entry");
+ DBG1(DBG_PTS, "unsupported functional component name qualifier");
return FAILED;
}
-
- pcr_before = chunk_clone(this->pcrs[entry->pcr]);
-
- hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
- hasher->get_hash(hasher, pcr_before, NULL);
- hasher->get_hash(hasher, entry->measurement, this->pcrs[entry->pcr].ptr);
- hasher->destroy(hasher);
- pcr_after = chunk_clone(this->pcrs[entry->pcr]);
-
- evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
- this->depth, entry->pcr, hash_algo, pcr_transform,
- this->bios_measurement_time, entry->measurement);
- evid->set_pcr_info(evid, pcr_before, pcr_after);
-
- free(entry);
+ *evidence = evid;
+ if (!evid)
+ {
+ return FAILED;
+ }
- return (this->list->get_count(this->list)) ? NEED_MORE : SUCCESS;
+ return (this->state == IMA_STATE_INIT || this->state == IMA_STATE_END) ?
+ SUCCESS : NEED_MORE;
}
METHOD(pts_component_t, verify, status_t,
- pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
+ pts_ita_comp_ima_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;
+ u_int32_t 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;
+ char *uri;
- measurement = evidence->get_measurement(evidence, &extended_pcr,
- &algo, &transform, &measurement_time);
-
+ /* some first time initializations */
if (!this->keyid.ptr)
{
if (!pts->get_aik_keyid(pts, &this->keyid))
{
+ DBG1(DBG_PTS, "AIK keyid not available");
return FAILED;
}
this->keyid = chunk_clone(this->keyid);
-
if (!this->pts_db)
{
DBG1(DBG_PTS, "pts database not available");
return FAILED;
}
- if (this->pts_db->get_comp_measurement_count(this->pts_db,
- this->name, this->keyid, algo,
- &this->cid, &this->kid, &this->count) != SUCCESS)
- {
- return FAILED;
- }
- vid = this->name->get_vendor_id(this->name);
- name = this->name->get_name(this->name);
- names = pts_components->get_comp_func_names(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
+ pcrs = pts->get_pcrs(pts);
+ measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
+ &measurement_time);
+
+ if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
+ PTS_ITA_QUALIFIER_TYPE_TRUSTED))
+ {
+ switch (this->state)
{
- DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
- "measurements", pen_names, vid, names, name);
- this->is_registering = TRUE;
+ 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->keyid, algo, &this->bios_cid,
+ &this->kid, &this->bios_count);
+ this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+
+ if (this->bios_count)
+ {
+ DBG1(DBG_PTS, "checking %d %N '%N' BIOS evidence measurements",
+ this->bios_count, pen_names, vid, names, name);
+ }
+ else
+ {
+ DBG1(DBG_PTS, "registering %N '%N' BIOS evidence measurements",
+ pen_names, vid, names, name);
+ 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->kid,
+ ++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->kid,
+ ++this->seq_no, pcr, algo);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ }
+ break;
+ default:
+ return FAILED;
}
}
-
- if (this->is_registering)
+ else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
+ PTS_ITA_QUALIFIER_TYPE_OS))
{
- if (this->pts_db->insert_comp_measurement(this->pts_db, measurement,
- this->cid, this->kid, ++this->seq_no,
- extended_pcr, algo) != SUCCESS)
+ int ima_count;
+
+ switch (this->state)
{
- return FAILED;
+ case IMA_STATE_BIOS:
+ if (!check_boot_aggregate(pcrs, measurement))
+ {
+ this->state = IMA_STATE_RUNTIME;
+ 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->keyid, algo,
+ &this->ima_cid, &this->kid, &ima_count);
+ this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(pts_components, vid);
+
+ if (ima_count)
+ {
+ DBG1(DBG_PTS, "checking %N '%N' boot aggregate evidence "
+ "measurement", pen_names, vid, names, name);
+ status = this->pts_db->check_comp_measurement(this->pts_db,
+ measurement, this->ima_cid,
+ this->kid, 1, pcr, algo);
+ }
+ else
+ {
+ DBG1(DBG_PTS, "registering %N '%N' boot aggregate evidence "
+ "measurement", pen_names, vid, names, name);
+ this->is_ima_registering = TRUE;
+ status = this->pts_db->insert_comp_measurement(this->pts_db,
+ measurement, this->ima_cid,
+ this->kid, 1, pcr, algo);
+ }
+ this->state = IMA_STATE_RUNTIME;
+
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ break;
+ case IMA_STATE_RUNTIME:
+ this->count++;
+ if (evidence->get_validation(evidence, &uri) !=
+ PTS_COMP_EVID_VALIDATION_PASSED)
+ {
+ DBG1(DBG_PTS, "policy URI could no be retrieved");
+ this->count_failed++;
+ return FAILED;
+ }
+ status = this->pts_db->check_file_measurement(this->pts_db,
+ pts->get_platform_info(pts),
+ PTS_MEAS_ALGO_SHA1_IMA,
+ measurement, uri);
+ switch (status)
+ {
+ case SUCCESS:
+ DBG3(DBG_PTS, "%#B for '%s' is ok",
+ &measurement, uri);
+ this->count_ok++;
+ break;
+ case NOT_FOUND:
+ DBG2(DBG_PTS, "%#B for '%s' not found",
+ &measurement, uri);
+ this->count_unknown++;
+ break;
+ case VERIFY_ERROR:
+ DBG1(DBG_PTS, "%#B for '%s' differs",
+ &measurement, uri);
+ this->count_differ++;
+ break;
+ case FAILED:
+ default:
+ DBG1(DBG_PTS, "%#B for '%s' failed",
+ &measurement, uri);
+ this->count_failed++;
+ }
+ break;
+ default:
+ return FAILED;
}
- this->count = this->seq_no + 1;
}
else
{
- if (this->pts_db->check_comp_measurement(this->pts_db, measurement,
- this->cid, this->kid, ++this->seq_no,
- extended_pcr, algo) != SUCCESS)
- {
- return FAILED;
- }
+ 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 (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
+ if (!chunk_equals(pcr_before, pcrs->get(pcrs, pcr)))
{
- return FAILED;
+ DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
+ pcr);
+ }
+ if (pcrs->set(pcrs, pcr, pcr_after))
+ {
+ return SUCCESS;
}
}
-
- return (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
+ else
+ {
+ pcr_after = pcrs->extend(pcrs, pcr, measurement);
+ if (pcr_after.ptr)
+ {
+ return SUCCESS;
+ }
+ }
+ return FAILED;
}
-METHOD(pts_component_t, check_off_registrations, bool,
- pts_ita_comp_ima_t *this)
+METHOD(pts_component_t, finalize, bool,
+ pts_ita_comp_ima_t *this, u_int8_t qualifier)
{
u_int32_t vid, name;
enum_name_t *names;
-
- if (!this->is_registering)
- {
- return FALSE;
- }
-
- /* Finalize registration */
- this->is_registering = FALSE;
+ bool success = TRUE;
+ this->name->set_qualifier(this->name, qualifier);
vid = this->name->get_vendor_id(this->name);
name = this->name->get_name(this->name);
names = pts_components->get_comp_func_names(pts_components, vid);
- DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
- "measurements", this->seq_no, pen_names, vid, names, name);
- return TRUE;
+
+ 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;
+
+ DBG1(DBG_PTS, "registered %d %N '%N' BIOS evidence measurements",
+ this->seq_no, pen_names, vid, names, name);
+ }
+ else if (this->seq_no < this->bios_count)
+ {
+ DBG1(DBG_PTS, "%d of %d %N '%N' BIOS evidence measurements missing",
+ this->bios_count - this->seq_no, this->bios_count,
+ pen_names, vid, names, name);
+ success = FALSE;
+ }
+ }
+ 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;
+
+ DBG1(DBG_PTS, "registered %N '%N' boot aggregate evidence "
+ "measurement", pen_names, vid, names, name);
+ }
+ if (this->count)
+ {
+ DBG1(DBG_PTS, "processed %d %N '%N' file evidence measurements: "
+ "%d ok, %d unknown, %d differ, %d failed",
+ this->count, pen_names, vid, names, name,
+ this->count_ok, this->count_unknown,
+ this->count_differ, this->count_failed);
+ success = !this->count_differ && !this->count_failed;
+ }
+ }
+ else
+ {
+ DBG1(DBG_PTS, "unsupported functional component name qualifier");
+ success = FALSE;
+ }
+ this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
+
+ 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 i, count;
+ int count;
u_int32_t vid, name;
enum_name_t *names;
- for (i = 0; i < IMA_PCR_MAX; i++)
- {
- free(this->pcrs[i].ptr);
- }
- if (this->is_registering)
+ if (ref_put(&this->ref))
{
- count = this->pts_db->delete_comp_measurements(this->pts_db,
- this->cid, this->kid);
vid = this->name->get_vendor_id(this->name);
name = this->name->get_name(this->name);
names = pts_components->get_comp_func_names(pts_components, vid);
- DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
- "evidence measurements", count, pen_names, vid, names, name);
+
+ if (this->is_bios_registering)
+ {
+ count = this->pts_db->delete_comp_measurements(this->pts_db,
+ this->bios_cid, this->kid);
+ DBG1(DBG_PTS, "deleted %d registered %N '%N' BIOS evidence "
+ "measurements", count, pen_names, vid, names, name);
+ }
+ if (this->is_ima_registering)
+ {
+ count = this->pts_db->delete_comp_measurements(this->pts_db,
+ this->ima_cid, this->kid);
+ DBG1(DBG_PTS, "deleted registered %N '%N' boot aggregate evidence "
+ "measurement", pen_names, vid, names, name);
+ }
+ this->bios_list->destroy_function(this->bios_list,
+ (void *)free_bios_entry);
+ this->ima_list->destroy_function(this->ima_list,
+ (void *)free_ima_entry);
+ this->name->destroy(this->name);
+ free(this->keyid.ptr);
+ free(this);
}
- this->list->destroy_function(this->list, (void *)free_entry);
- this->name->destroy(this->name);
- free(this->keyid.ptr);
- free(this);
}
/**
* See header
*/
-pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
+pts_component_t *pts_ita_comp_ima_create(u_int32_t depth,
pts_database_t *pts_db)
{
pts_ita_comp_ima_t *this;
- int i;
INIT(this,
.public = {
@@ -419,21 +940,21 @@ pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
.get_depth = _get_depth,
.measure = _measure,
.verify = _verify,
- .check_off_registrations = _check_off_registrations,
+ .finalize = _finalize,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
- qualifier),
+ PTS_QUALIFIER_UNKNOWN),
.depth = depth,
.pts_db = pts_db,
- .list = linked_list_create(),
+ .bios_list = linked_list_create(),
+ .ima_list = linked_list_create(),
+ .pcr_info = lib->settings->get_bool(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr_info", TRUE),
+ .ref = 1,
);
- for (i = 0; i < IMA_PCR_MAX; i++)
- {
- this->pcrs[i] = chunk_alloc(HASH_SIZE_SHA1);
- memset(this->pcrs[i].ptr, 0x00, HASH_SIZE_SHA1);
- }
return &this->public;
}
diff --git a/src/libpts/pts/components/ita/ita_comp_ima.h b/src/libpts/pts/components/ita/ita_comp_ima.h
index 1ca27e6f0..546d0a4b2 100644
--- a/src/libpts/pts/components/ita/ita_comp_ima.h
+++ b/src/libpts/pts/components/ita/ita_comp_ima.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
+ * Copyright (C) 2011-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -26,11 +26,10 @@
/**
* Create a PTS ITS Functional Component object
*
- * @param qualifier PTS Component Functional Name Qualifier
* @param depth Sub-component depth
* @param pts_db PTS measurement database
*/
-pts_component_t* pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
+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/libpts/pts/components/ita/ita_comp_tboot.c b/src/libpts/pts/components/ita/ita_comp_tboot.c
index a85de8cd8..8fb5abddf 100644
--- a/src/libpts/pts/components/ita/ita_comp_tboot.c
+++ b/src/libpts/pts/components/ita/ita_comp_tboot.c
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
- *
+ * Copyright (C) 2011-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,7 +19,7 @@
#include "libpts.h"
#include "pts/components/pts_component.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <pen/pen.h>
typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t;
@@ -67,7 +66,7 @@ struct pts_ita_comp_tboot_t {
int kid;
/**
- * Component is registering measurements
+ * Component is registering measurements
*/
bool is_registering;
@@ -86,6 +85,11 @@ struct pts_ita_comp_tboot_t {
*/
int seq_no;
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+
};
METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
@@ -107,16 +111,19 @@ METHOD(pts_component_t, get_depth, u_int32_t,
}
METHOD(pts_component_t, measure, status_t,
- pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
+ 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;
- size_t hash_size, pcr_len;
u_int32_t extended_pcr;
- pts_pcr_transform_t pcr_transform;
- pts_meas_algorithms_t hash_algo;
-
+
switch (this->seq_no++)
{
case 0:
@@ -149,9 +156,8 @@ METHOD(pts_component_t, measure, status_t,
return FAILED;
}
- hash_algo = pts->get_meas_algorithm(pts);
- hash_size = pts_meas_algo_hash_size(hash_algo);
- pcr_len = pts->get_pcr_len(pts);
+ 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 */
@@ -162,35 +168,40 @@ METHOD(pts_component_t, measure, status_t,
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 != hash_size)
+ measurement.len != pcr_len)
{
- DBG1(DBG_PTS, "TBOOT measurement or pcr data have the wrong size");
+ 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);
+ 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, pts_t *pts, pts_comp_evidence_t *evidence)
+ 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;
+ pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &extended_pcr,
&algo, &transform, &measurement_time);
@@ -207,11 +218,12 @@ METHOD(pts_component_t, verify, status_t,
DBG1(DBG_PTS, "pts database not available");
return FAILED;
}
- if (this->pts_db->get_comp_measurement_count(this->pts_db,
- this->name, this->keyid, algo,
- &this->cid, &this->kid, &this->count) != SUCCESS)
+ status = this->pts_db->get_comp_measurement_count(this->pts_db,
+ this->name, this->keyid, algo, &this->cid,
+ &this->kid, &this->count);
+ if (status != SUCCESS)
{
- return FAILED;
+ return status;
}
vid = this->name->get_vendor_id(this->name);
name = this->name->get_name(this->name);
@@ -232,58 +244,79 @@ METHOD(pts_component_t, verify, status_t,
if (this->is_registering)
{
- if (this->pts_db->insert_comp_measurement(this->pts_db, measurement,
- this->cid, this->kid, ++this->seq_no,
- extended_pcr, algo) != SUCCESS)
+ status = this->pts_db->insert_comp_measurement(this->pts_db,
+ measurement, this->cid, this->kid,
+ ++this->seq_no, extended_pcr, algo);
+ if (status != SUCCESS)
{
- return FAILED;
+ return status;
}
this->count = this->seq_no + 1;
}
else
{
- if (this->pts_db->check_comp_measurement(this->pts_db, measurement,
- this->cid, this->kid, ++this->seq_no,
- extended_pcr, algo) != SUCCESS)
+ 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 FAILED;
+ return status;
}
}
has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
if (has_pcr_info)
{
- if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
+ if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr)))
{
- return FAILED;
+ 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 (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
+ return SUCCESS;
}
-METHOD(pts_component_t, check_off_registrations, bool,
- pts_ita_comp_tboot_t *this)
+METHOD(pts_component_t, finalize, bool,
+ pts_ita_comp_tboot_t *this, u_int8_t qualifier)
{
u_int32_t vid, name;
enum_name_t *names;
-
- if (!this->is_registering)
- {
- return FALSE;
- }
-
- /* Finalize registration */
- this->is_registering = FALSE;
vid = this->name->get_vendor_id(this->name);
name = this->name->get_name(this->name);
names = pts_components->get_comp_func_names(pts_components, vid);
- DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
- "measurements", this->seq_no, pen_names, vid, names, name);
+
+ if (this->is_registering)
+ {
+ /* close registration */
+ this->is_registering = FALSE;
+
+ DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
+ "measurements", this->seq_no, pen_names, vid, names, name);
+ }
+ else if (this->seq_no < this->count)
+ {
+ DBG1(DBG_PTS, "%d of %d %N '%N' functional component evidence "
+ "measurements missing", this->count - this->seq_no,
+ this->count, pen_names, vid, names, name);
+ return FALSE;
+ }
+
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)
{
@@ -291,25 +324,28 @@ METHOD(pts_component_t, destroy, void,
u_int32_t vid, name;
enum_name_t *names;
- if (this->is_registering)
+ if (ref_put(&this->ref))
{
- count = this->pts_db->delete_comp_measurements(this->pts_db,
- this->cid, this->kid);
- vid = this->name->get_vendor_id(this->name);
- name = this->name->get_name(this->name);
- names = pts_components->get_comp_func_names(pts_components, vid);
- DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
- "evidence measurements", count, pen_names, vid, names, name);
+ if (this->is_registering)
+ {
+ count = this->pts_db->delete_comp_measurements(this->pts_db,
+ this->cid, this->kid);
+ vid = this->name->get_vendor_id(this->name);
+ name = this->name->get_name(this->name);
+ names = pts_components->get_comp_func_names(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->keyid.ptr);
+ free(this);
}
- this->name->destroy(this->name);
- free(this->keyid.ptr);
- free(this);
}
/**
* See header
*/
-pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth,
+pts_component_t *pts_ita_comp_tboot_create(u_int32_t depth,
pts_database_t *pts_db)
{
pts_ita_comp_tboot_t *this;
@@ -321,13 +357,16 @@ pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth,
.get_depth = _get_depth,
.measure = _measure,
.verify = _verify,
- .check_off_registrations = _check_off_registrations,
+ .finalize = _finalize,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT,
- qualifier),
+ 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/libpts/pts/components/ita/ita_comp_tboot.h b/src/libpts/pts/components/ita/ita_comp_tboot.h
index 39554fbc7..1e1a14831 100644
--- a/src/libpts/pts/components/ita/ita_comp_tboot.h
+++ b/src/libpts/pts/components/ita/ita_comp_tboot.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Sansar Choinyambuu
+ * 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
@@ -26,11 +26,10 @@
/**
* Create a PTS ITS Functional Component object
*
- * @param qualifier PTS Component Functional Name Qualifier
* @param depth Sub-component depth
* @param pts_db PTS measurement database
*/
-pts_component_t* pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth,
+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/libpts/pts/components/ita/ita_comp_tgrub.c b/src/libpts/pts/components/ita/ita_comp_tgrub.c
index 0dfd5fd41..e3acd8774 100644
--- a/src/libpts/pts/components/ita/ita_comp_tgrub.c
+++ b/src/libpts/pts/components/ita/ita_comp_tgrub.c
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
- *
+ * Copyright (C) 2011-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -19,7 +18,7 @@
#include "pts/components/pts_component.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <pen/pen.h>
typedef struct pts_ita_comp_tgrub_t pts_ita_comp_tgrub_t;
@@ -50,6 +49,12 @@ struct pts_ita_comp_tgrub_t {
*/
pts_database_t *pts_db;
+
+ /**
+ * Reference count
+ */
+ refcount_t ref;
+
};
METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
@@ -71,34 +76,34 @@ METHOD(pts_component_t, get_depth, u_int32_t,
}
METHOD(pts_component_t, measure, status_t,
- pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
+ 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;
- pts_pcr_transform_t pcr_transform;
- pts_meas_algorithms_t hash_algo;
- size_t hash_size, pcr_len;
/* 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->get_meas_algorithm(pts);
- hash_size = pts_meas_algo_hash_size(hash_algo);
- pcr_len = pts->get_pcr_len(pts);
+ 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(hash_size);
+ 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);
@@ -112,15 +117,18 @@ METHOD(pts_component_t, measure, status_t,
}
METHOD(pts_component_t, verify, status_t,
- pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
+ 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 measurement, pcr_before, pcr_after;
+ pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &extended_pcr,
&algo, &transform, &measurement_time);
if (extended_pcr != PCR_DEBUG)
@@ -133,32 +141,46 @@ METHOD(pts_component_t, verify, status_t,
has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
if (has_pcr_info)
{
- if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
+ if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr)))
{
- return FAILED;
+ 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, check_off_registrations, bool,
- pts_ita_comp_tgrub_t *this)
+METHOD(pts_component_t, finalize, bool,
+ pts_ita_comp_tgrub_t *this, u_int8_t qualifier)
{
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)
{
- this->name->destroy(this->name);
- free(this);
+ if (ref_put(&this->ref))
+ {
+ this->name->destroy(this->name);
+ free(this);
+ }
}
/**
* See header
*/
-pts_component_t *pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth,
+pts_component_t *pts_ita_comp_tgrub_create(u_int32_t depth,
pts_database_t *pts_db)
{
pts_ita_comp_tgrub_t *this;
@@ -170,13 +192,16 @@ pts_component_t *pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth,
.get_depth = _get_depth,
.measure = _measure,
.verify = _verify,
- .check_off_registrations = _check_off_registrations,
+ .finalize = _finalize,
+ .get_ref = _get_ref,
.destroy = _destroy,
},
.name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TGRUB,
- qualifier),
+ 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/libpts/pts/components/ita/ita_comp_tgrub.h b/src/libpts/pts/components/ita/ita_comp_tgrub.h
index 52ecc325c..59913c82d 100644
--- a/src/libpts/pts/components/ita/ita_comp_tgrub.h
+++ b/src/libpts/pts/components/ita/ita_comp_tgrub.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Sansar Choinyambuu
+ * 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
@@ -26,11 +26,10 @@
/**
* Create a PTS ITS Functional Component object
*
- * @param qualifier PTS Component Functional Name Qualifier
* @param depth Sub-component depth
* @param pts_db PTS measurement database
*/
-pts_component_t* pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth,
+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/libpts/pts/components/pts_comp_evidence.c b/src/libpts/pts/components/pts_comp_evidence.c
index 9eb8dae75..08c3d5e9a 100644
--- a/src/libpts/pts/components/pts_comp_evidence.c
+++ b/src/libpts/pts/components/pts_comp_evidence.c
@@ -15,7 +15,7 @@
#include "pts/components/pts_comp_evidence.h"
-#include <debug.h>
+#include <utils/debug.h>
typedef struct private_pts_comp_evidence_t private_pts_comp_evidence_t;
@@ -87,7 +87,7 @@ struct private_pts_comp_evidence_t {
/**
* Verification Policy URI
*/
- chunk_t policy_uri;
+ char *policy_uri;
};
@@ -148,16 +148,16 @@ METHOD(pts_comp_evidence_t, get_pcr_info, bool,
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->has_pcr_info = TRUE;
this->pcr_before = pcr_before;
this->pcr_after = pcr_after;
- DBG2(DBG_PTS, "PCR %2d before value : %#B", this->extended_pcr, &pcr_before);
- DBG2(DBG_PTS, "PCR %2d after value : %#B", this->extended_pcr, &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, chunk_t *uri)
+ private_pts_comp_evidence_t *this, char **uri)
{
if (uri)
{
@@ -168,10 +168,14 @@ METHOD(pts_comp_evidence_t, get_validation, pts_comp_evid_validation_t,
METHOD(pts_comp_evidence_t, set_validation, void,
private_pts_comp_evidence_t *this, pts_comp_evid_validation_t validation,
- chunk_t uri)
+ char *uri)
{
this->validation = validation;
- this->policy_uri = chunk_clone(uri);
+ if (uri)
+ {
+ this->policy_uri = strdup(uri);
+ DBG3(DBG_PTS, "'%s'", uri);
+ }
}
METHOD(pts_comp_evidence_t, destroy, void,
@@ -181,7 +185,7 @@ METHOD(pts_comp_evidence_t, destroy, void,
free(this->measurement.ptr);
free(this->pcr_before.ptr);
free(this->pcr_after.ptr);
- free(this->policy_uri.ptr);
+ free(this->policy_uri);
free(this);
}
@@ -219,8 +223,8 @@ pts_comp_evidence_t *pts_comp_evidence_create(pts_comp_func_name_t *name,
);
name->log(name, "");
- DBG2(DBG_PTS, "measurement time: %T", &measurement_time, FALSE);
- DBG2(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement);
+ DBG3(DBG_PTS, "measurement time: %T", &measurement_time, FALSE);
+ DBG3(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement);
return &this->public;
}
diff --git a/src/libpts/pts/components/pts_comp_evidence.h b/src/libpts/pts/components/pts_comp_evidence.h
index fe86aa940..55776ce8b 100644
--- a/src/libpts/pts/components/pts_comp_evidence.h
+++ b/src/libpts/pts/components/pts_comp_evidence.h
@@ -120,7 +120,7 @@ struct pts_comp_evidence_t {
* @return validation Validation Result
*/
pts_comp_evid_validation_t (*get_validation)(pts_comp_evidence_t *this,
- chunk_t *uri);
+ char **uri);
/**
* Sets Validation Result if available
@@ -129,7 +129,7 @@ struct pts_comp_evidence_t {
* @param uri Verification Policy URI
*/
void (*set_validation)(pts_comp_evidence_t *this,
- pts_comp_evid_validation_t validation, chunk_t uri);
+ pts_comp_evid_validation_t validation, char* uri);
/**
* Destroys a pts_comp_evidence_t object.
diff --git a/src/libpts/pts/components/pts_comp_func_name.c b/src/libpts/pts/components/pts_comp_func_name.c
index d98850d78..6c630f8fb 100644
--- a/src/libpts/pts/components/pts_comp_func_name.c
+++ b/src/libpts/pts/components/pts_comp_func_name.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
+ * Copyright (C) 2011-2012 Andreas Steffen
*
* HSR Hochschule fuer Technik Rapperswil
*
@@ -17,7 +17,7 @@
#include "libpts.h"
#include "pts/components/pts_comp_func_name.h"
-#include <debug.h>
+#include <utils/debug.h>
typedef struct private_pts_comp_func_name_t private_pts_comp_func_name_t;
@@ -67,6 +67,12 @@ METHOD(pts_comp_func_name_t, get_qualifier, u_int8_t,
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)
{
@@ -137,6 +143,7 @@ pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name,
.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_,
diff --git a/src/libpts/pts/components/pts_comp_func_name.h b/src/libpts/pts/components/pts_comp_func_name.h
index 2c7a84177..90ad7083f 100644
--- a/src/libpts/pts/components/pts_comp_func_name.h
+++ b/src/libpts/pts/components/pts_comp_func_name.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Sansar Choinyambuu
+ * 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
@@ -55,6 +55,13 @@ struct pts_comp_func_name_t {
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
@@ -88,7 +95,7 @@ struct pts_comp_func_name_t {
*
* @param vid PTS Component Functional Name Vendor ID
* @param name PTS Component Functional Name
- * @param PTS Component Functional Name Qualifier
+ * @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);
diff --git a/src/libpts/pts/components/pts_component.h b/src/libpts/pts/components/pts_component.h
index 524ff332d..da339a55f 100644
--- a/src/libpts/pts/components/pts_component.h
+++ b/src/libpts/pts/components/pts_component.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
+ * Copyright (C) 2011-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@ 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"
@@ -59,30 +60,41 @@ struct pts_component_t {
/**
* 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, pts_t *pts,
+ 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, pts_t *pts,
+ 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
+ * @return TRUE if finalization successful
+ */
+ bool (*finalize)(pts_component_t *this, u_int8_t qualifier);
+
+ /**
+ * Get a new reference to the PTS Functional Component
*
- * @return TRUE if there are pending registrations
+ * @return this, with an increased refcount
*/
- bool (*check_off_registrations)(pts_component_t *this);
+ pts_component_t* (*get_ref)(pts_component_t *this);
/**
* Destroys a pts_component_t object.
diff --git a/src/libpts/pts/components/pts_component_manager.c b/src/libpts/pts/components/pts_component_manager.c
index 8ac4767bf..9c1375b79 100644
--- a/src/libpts/pts/components/pts_component_manager.c
+++ b/src/libpts/pts/components/pts_component_manager.c
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
- *
+ * Copyright (C) 2011-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -16,8 +15,8 @@
#include "pts/components/pts_component_manager.h"
-#include <utils/linked_list.h>
-#include <debug.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;
@@ -57,7 +56,7 @@ struct vendor_entry_t {
/**
* List of vendor-specific registered Functional Components
- */
+ */
linked_list_t *components;
};
@@ -104,7 +103,7 @@ struct private_pts_component_manager_t {
};
METHOD(pts_component_manager_t, add_vendor, void,
- private_pts_component_manager_t *this, pen_t vendor_id,
+ 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)
{
@@ -270,8 +269,7 @@ METHOD(pts_component_manager_t, create, pts_component_t*,
{
if (entry2->name == name->get_name(name) && entry2->create)
{
- component = entry2->create(name->get_qualifier(name),
- depth, pts_db);
+ component = entry2->create(depth, pts_db);
break;
}
}
@@ -287,7 +285,7 @@ METHOD(pts_component_manager_t, create, pts_component_t*,
METHOD(pts_component_manager_t, destroy, void,
private_pts_component_manager_t *this)
{
- this->list->destroy_function(this->list, (void *)vendor_entry_destroy);
+ this->list->destroy_function(this->list, (void *)vendor_entry_destroy);
free(this);
}
diff --git a/src/libpts/pts/components/pts_component_manager.h b/src/libpts/pts/components/pts_component_manager.h
index 0079d0e26..61055ec74 100644
--- a/src/libpts/pts/components/pts_component_manager.h
+++ b/src/libpts/pts/components/pts_component_manager.h
@@ -30,8 +30,7 @@ typedef struct pts_component_manager_t pts_component_manager_t;
#include <library.h>
#include <pen/pen.h>
-typedef pts_component_t* (*pts_component_create_t)(u_int8_t qualifier,
- u_int32_t depth,
+typedef pts_component_t* (*pts_component_create_t)(u_int32_t depth,
pts_database_t *pts_db);
/**
diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c
index 65ae2b2d2..f646d67e1 100644
--- a/src/libpts/pts/pts.c
+++ b/src/libpts/pts/pts.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Sansar Choinyambuu
+ * 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
@@ -15,30 +15,30 @@
#include "pts.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <crypto/hashers/hasher.h>
#include <bio/bio_writer.h>
#include <bio/bio_reader.h>
+#ifdef TSS_TROUSERS
#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 <sys/utsname.h>
+#include <libgen.h>
+#include <unistd.h>
#include <errno.h>
-#define PTS_BUF_SIZE 4096
-
-/**
- * Maximum number of PCR's of TPM, TPM Spec 1.2
- */
-#define PCR_MAX_NUM 24
-
-/**
- * Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2
- */
-#define PCR_LEN 20
-
typedef struct private_pts_t private_pts_t;
/**
@@ -118,29 +118,9 @@ struct private_pts_t {
certificate_t *aik;
/**
- * Table of extended PCRs with corresponding values
- */
- u_char* pcrs[PCR_MAX_NUM];
-
- /**
- * Length of PCR registers
- */
- size_t pcr_len;
-
- /**
- * Number of extended PCR registers
- */
- u_int32_t pcr_count;
-
- /**
- * Highest extended PCR register
- */
- u_int32_t pcr_max;
-
- /**
- * Bitmap of extended PCR registers
+ * Shadow PCR set
*/
- u_int8_t pcr_select[PCR_MAX_NUM / 8];
+ pts_pcr_t *pcrs;
};
@@ -225,9 +205,13 @@ METHOD(pts_t, create_dh_nonce, bool,
DBG2(DBG_PTS, "nonce length is %d", nonce_len);
nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce;
chunk_free(nonce);
- rng->allocate_bytes(rng, nonce_len, 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;
}
@@ -282,10 +266,15 @@ METHOD(pts_t, calculate_secret, bool,
hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
- hasher->allocate_hash(hasher, chunk_from_chars('1'), NULL);
- hasher->allocate_hash(hasher, this->initiator_nonce, NULL);
- hasher->allocate_hash(hasher, this->responder_nonce, NULL);
- hasher->allocate_hash(hasher, shared_secret, &this->secret);
+ 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 */
@@ -300,6 +289,8 @@ METHOD(pts_t, calculate_secret, bool,
return TRUE;
}
+#ifdef TSS_TROUSERS
+
/**
* Print TPM 1.2 Version Info
*/
@@ -319,14 +310,26 @@ static void print_tpm_version_info(private_pts_t *this)
else
{
DBG2(DBG_PTS, "TPM 1.2 Version Info: Chip Version: %hhu.%hhu.%hhu.%hhu,"
- " Spec Level: %hu, Errata Rev: %hhu, Vendor ID: %.4s",
+ " Spec Level: %hu, Errata Rev: %hhu, Vendor ID: %.4s [%.*s]",
versionInfo.version.major, versionInfo.version.minor,
versionInfo.version.revMajor, versionInfo.version.revMinor,
versionInfo.specLevel, versionInfo.errataRev,
- versionInfo.tpmVendorID);
+ versionInfo.tpmVendorID, versionInfo.vendorSpecificSize,
+ versionInfo.vendorSpecificSize ?
+ (char*)versionInfo.vendorSpecific : "");
}
+ free(versionInfo.vendorSpecific);
}
+#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_info, char*,
private_pts_t *this)
{
@@ -334,10 +337,15 @@ METHOD(pts_t, get_platform_info, char*,
}
METHOD(pts_t, set_platform_info, void,
- private_pts_t *this, char *info)
+ private_pts_t *this, chunk_t name, chunk_t version)
{
+ int len = name.len + 1 + version.len + 1;
+
+ /* platform info is a concatenation of OS name and OS version */
free(this->platform_info);
- this->platform_info = strdup(info);
+ this->platform_info = malloc(len);
+ snprintf(this->platform_info, len, "%.*s %.*s", (int)name.len, name.ptr,
+ (int)version.len, version.ptr);
}
METHOD(pts_t, get_tpm_version_info, bool,
@@ -359,12 +367,6 @@ METHOD(pts_t, set_tpm_version_info, void,
print_tpm_version_info(this);
}
-METHOD(pts_t, get_pcr_len, size_t,
- private_pts_t *this)
-{
- return this->pcr_len;
-}
-
/**
* Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute)
*/
@@ -486,54 +488,6 @@ METHOD(pts_t, get_aik_keyid, bool,
return success;
}
-METHOD(pts_t, hash_file, bool,
- private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash)
-{
- u_char buffer[PTS_BUF_SIZE];
- FILE *file;
- int bytes_read;
-
- 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)
- {
- hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL);
- }
- else
- {
- hasher->get_hash(hasher, chunk_empty, hash);
- break;
- }
- }
- fclose(file);
-
- return TRUE;
-}
-
-/**
- * Get the relative filename of a fully qualified file pathname
- */
-static char* get_filename(char *pathname)
-{
- char *pos, *filename;
-
- pos = filename = pathname;
- while (pos && *(++pos) != '\0')
- {
- filename = pos;
- pos = strchr(filename, '/');
- }
- return filename;
-}
-
METHOD(pts_t, is_path_valid, bool,
private_pts_t *this, char *path, pts_error_code_t *error_code)
{
@@ -565,82 +519,6 @@ METHOD(pts_t, is_path_valid, bool,
return TRUE;
}
-METHOD(pts_t, do_measurements, pts_file_meas_t*,
- private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory)
-{
- hasher_t *hasher;
- hash_algorithm_t hash_alg;
- u_char hash[HASH_SIZE_SHA384];
- chunk_t measurement;
- pts_file_meas_t *measurements;
-
- /* Create a hasher */
- hash_alg = pts_meas_algo_to_hash(this->algorithm);
- 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;
- }
-
- /* Create a measurement object */
- measurements = pts_file_meas_create(request_id);
-
- /* Link the hash to the measurement and set the measurement length */
- measurement = chunk_create(hash, hasher->get_hash_size(hasher));
-
- 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));
- hasher->destroy(hasher);
- measurements->destroy(measurements);
- return NULL;
- }
- while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st))
- {
- /* measure regular files only */
- if (S_ISREG(st.st_mode) && *rel_name != '.')
- {
- if (!hash_file(this, hasher, abs_name, hash))
- {
- enumerator->destroy(enumerator);
- hasher->destroy(hasher);
- measurements->destroy(measurements);
- return NULL;
- }
- DBG2(DBG_PTS, " %#B for '%s'", &measurement, rel_name);
- measurements->add(measurements, rel_name, measurement);
- }
- }
- enumerator->destroy(enumerator);
- }
- else
- {
- char *filename;
-
- if (!hash_file(this, hasher, pathname, hash))
- {
- hasher->destroy(hasher);
- measurements->destroy(measurements);
- return NULL;
- }
- filename = get_filename(pathname);
- DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
- measurements->add(measurements, filename, measurement);
- }
- hasher->destroy(hasher);
-
- return measurements;
-}
-
/**
* Obtain statistical information describing a file
*/
@@ -654,6 +532,7 @@ static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
if (stat(pathname, &st))
{
DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname);
+ free(this);
return FALSE;
}
@@ -748,13 +627,16 @@ METHOD(pts_t, get_metadata, pts_file_meta_t*,
metadata->destroy(metadata);
return NULL;
}
- entry->filename = strdup(get_filename(pathname));
+ entry->filename = strdup(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)
{
@@ -809,7 +691,7 @@ METHOD(pts_t, extend_pcr, bool,
TSS_HTPM hTPM;
TSS_RESULT result;
u_int32_t pcr_length;
- chunk_t pcr_value;
+ chunk_t pcr_value = chunk_empty;
result = Tspi_Context_Create(&hContext);
if (result != TSS_SUCCESS)
@@ -829,8 +711,8 @@ METHOD(pts_t, extend_pcr, bool,
goto err;
}
- pcr_value = chunk_alloc(PCR_LEN);
- result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PCR_LEN, input.ptr,
+ 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)
{
@@ -842,7 +724,7 @@ METHOD(pts_t, extend_pcr, bool,
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);
@@ -851,28 +733,12 @@ METHOD(pts_t, extend_pcr, bool,
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;
-}
-
-static void clear_pcrs(private_pts_t *this)
-{
- int i;
-
- for (i = 0; i <= this->pcr_max; i++)
- {
- free(this->pcrs[i]);
- this->pcrs[i] = NULL;
- }
- this->pcr_count = 0;
- this->pcr_max = 0;
-
- memset(this->pcr_select, 0x00, sizeof(this->pcr_select));
+ return FALSE;
}
METHOD(pts_t, quote_tpm, bool,
@@ -890,7 +756,8 @@ METHOD(pts_t, quote_tpm, bool,
TSS_RESULT result;
chunk_t quote_info;
BYTE* versionInfo;
- u_int32_t versionInfoSize, pcr, i = 0, f = 1;
+ u_int32_t versionInfoSize, pcr;
+ enumerator_t *enumerator;
bool success = FALSE;
result = Tspi_Context_Create(&hContext);
@@ -943,32 +810,30 @@ METHOD(pts_t, quote_tpm, bool,
Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
TSS_PCRS_STRUCT_INFO_SHORT, &hPcrComposite) :
Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS,
- 0, &hPcrComposite);
+ TSS_PCRS_STRUCT_DEFAULT, &hPcrComposite);
if (result != TSS_SUCCESS)
{
goto err2;
}
/* Select PCRs */
- for (pcr = 0; pcr <= this->pcr_max ; pcr++)
- {
- if (f == 256)
+ 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)
{
- i++;
- f = 1;
- }
- if (this->pcr_select[i] & f)
- {
- result = use_quote2 ?
- Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr,
- TSS_PCRS_DIRECTION_RELEASE) :
- Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr);
- if (result != TSS_SUCCESS)
- {
- goto err3;
- }
+ break;
}
- f <<= 1;
+ }
+ enumerator->destroy(enumerator);
+
+ if (result != TSS_SUCCESS)
+ {
+ goto err3;
}
/* Set the Validation Data */
@@ -1023,94 +888,35 @@ err2:
err1:
Tspi_Context_Close(hContext);
-
if (!success)
{
DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result);
}
- clear_pcrs(this);
-
return success;
}
-METHOD(pts_t, select_pcr, bool,
- private_pts_t *this, u_int32_t pcr)
-{
- u_int32_t i, f;
-
- if (pcr >= PCR_MAX_NUM)
- {
- DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u",
- pcr, PCR_MAX_NUM-1);
- return FALSE;
- }
-
- /* Determine PCR selection flag */
- i = pcr / 8;
- f = 1 << (pcr - 8*i);
+#else /* TSS_TROUSERS */
- /* 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_t, read_pcr, bool,
+ private_pts_t *this, u_int32_t pcr_num, chunk_t *pcr_value)
+{
+ return FALSE;
}
-METHOD(pts_t, add_pcr, bool,
- private_pts_t *this, u_int32_t pcr, chunk_t pcr_before, chunk_t pcr_after)
+METHOD(pts_t, extend_pcr, bool,
+ private_pts_t *this, u_int32_t pcr_num, chunk_t input, chunk_t *output)
{
- if (pcr >= PCR_MAX_NUM)
- {
- DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u",
- pcr, PCR_MAX_NUM-1);
- return FALSE;
- }
-
- /* Is the length of the PCR registers already set? */
- if (this->pcr_len)
- {
- if (pcr_after.len != this->pcr_len)
- {
- DBG1(DBG_PTS, "PCR %02u: length is %d bytes but should be %d bytes",
- pcr_after.len, this->pcr_len);
- return FALSE;
- }
- }
- else
- {
- this->pcr_len = pcr_after.len;
- }
-
- /* Has the value of the PCR register already been assigned? */
- if (this->pcrs[pcr])
- {
- if (!memeq(this->pcrs[pcr], pcr_before.ptr, this->pcr_len))
- {
- DBG1(DBG_PTS, "PCR %02u: new pcr_before value does not equal "
- "old pcr_after value");
- }
- /* remove the old PCR value */
- free(this->pcrs[pcr]);
- }
- else
- {
- /* add extended PCR Register */
- this->pcr_select[pcr / 8] |= 1 << (pcr % 8);
- this->pcr_max = max(this->pcr_max, pcr);
- this->pcr_count++;
- }
-
- /* Duplicate and store current PCR value */
- pcr_after = chunk_clone(pcr_after);
- this->pcrs[pcr] = pcr_after.ptr;
+ return FALSE;
+}
- return TRUE;
+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
@@ -1130,13 +936,11 @@ METHOD(pts_t, get_quote_info, bool,
pts_meas_algorithms_t comp_hash_algo,
chunk_t *out_pcr_comp, chunk_t *out_quote_info)
{
- u_int8_t size_of_select;
- int pcr_comp_len, i;
- chunk_t pcr_comp, hash_pcr_comp;
+ chunk_t selection, pcr_comp, hash_pcr_comp;
bio_writer_t *writer;
hasher_t *hasher;
- if (this->pcr_count == 0)
+ if (!this->pcrs->get_count(this->pcrs))
{
DBG1(DBG_PTS, "No extended PCR entries available, "
"unable to construct TPM Quote Info");
@@ -1154,34 +958,9 @@ METHOD(pts_t, get_quote_info, bool,
"unable to construct TPM Quote Info2");
return FALSE;
}
-
- /**
- * A TPM v1.2 has 24 PCR Registers
- * so the bitmask field length used by TrouSerS is at least 3 bytes
- */
- size_of_select = max(PCR_MAX_NUM / 8, 1 + this->pcr_max / 8);
- pcr_comp_len = 2 + size_of_select + 4 + this->pcr_count * this->pcr_len;
-
- writer = bio_writer_create(pcr_comp_len);
-
- writer->write_uint16(writer, size_of_select);
- for (i = 0; i < size_of_select; i++)
- {
- writer->write_uint8(writer, this->pcr_select[i]);
- }
- writer->write_uint32(writer, this->pcr_count * this->pcr_len);
- for (i = 0; i < 8 * size_of_select; i++)
- {
- if (this->pcrs[i])
- {
- writer->write_data(writer, chunk_create(this->pcrs[i], this->pcr_len));
- }
- }
- pcr_comp = chunk_clone(writer->get_buf(writer));
- DBG3(DBG_PTS, "constructed PCR Composite: %B", &pcr_comp);
+ pcr_comp = this->pcrs->get_composite(this->pcrs);
- writer->destroy(writer);
/* Output the TPM_PCR_COMPOSITE expected from IMC */
if (comp_hash_algo)
@@ -1192,7 +971,12 @@ METHOD(pts_t, get_quote_info, bool,
hasher = lib->crypto->create_hasher(lib->crypto, algo);
/* Hash the PCR Composite Structure */
- hasher->allocate_hash(hasher, pcr_comp, out_pcr_comp);
+ 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);
}
@@ -1203,7 +987,13 @@ METHOD(pts_t, get_quote_info, bool,
/* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
- hasher->allocate_hash(hasher, pcr_comp, &hash_pcr_comp);
+ 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 */
@@ -1220,15 +1010,11 @@ METHOD(pts_t, get_quote_info, bool,
/* Secret assessment value 20 bytes (nonce) */
writer->write_data(writer, this->secret);
- /* Length of the PCR selection field */
- writer->write_uint16(writer, size_of_select);
-
/* PCR selection */
- for (i = 0; i < size_of_select ; i++)
- {
- writer->write_uint8(writer, this->pcr_select[i]);
- }
-
+ 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);
@@ -1257,13 +1043,12 @@ METHOD(pts_t, get_quote_info, bool,
}
/* TPM Quote Info */
- *out_quote_info = chunk_clone(writer->get_buf(writer));
+ *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);
- clear_pcrs(this);
return TRUE;
}
@@ -1292,10 +1077,16 @@ METHOD(pts_t, verify_quote_signature, bool,
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)
{
- clear_pcrs(this);
+ DESTROY_IF(this->pcrs);
DESTROY_IF(this->aik);
DESTROY_IF(this->dh);
free(this->initiator_nonce.ptr);
@@ -1307,121 +1098,8 @@ METHOD(pts_t, destroy, void,
free(this);
}
-#define RELEASE_LSB 0
-#define RELEASE_DEBIAN 1
-/**
- * Determine Linux distribution and hardware platform
- */
-static char* extract_platform_info(void)
-{
- FILE *file;
- char buf[BUF_LEN], *pos = buf, *value = NULL;
- int i, len = BUF_LEN - 1;
- struct utsname uninfo;
-
- /* Linux/Unix distribution release info (from http://linuxmafia.com) */
- const char* releases[] = {
- "/etc/lsb-release", "/etc/debian_version",
- "/etc/SuSE-release", "/etc/novell-release",
- "/etc/sles-release", "/etc/redhat-release",
- "/etc/fedora-release", "/etc/gentoo-release",
- "/etc/slackware-version", "/etc/annvix-release",
- "/etc/arch-release", "/etc/arklinux-release",
- "/etc/aurox-release", "/etc/blackcat-release",
- "/etc/cobalt-release", "/etc/conectiva-release",
- "/etc/debian_release", "/etc/immunix-release",
- "/etc/lfs-release", "/etc/linuxppc-release",
- "/etc/mandrake-release", "/etc/mandriva-release",
- "/etc/mandrakelinux-release", "/etc/mklinux-release",
- "/etc/pld-release", "/etc/redhat_version",
- "/etc/slackware-release", "/etc/e-smith-release",
- "/etc/release", "/etc/sun-release",
- "/etc/tinysofa-release", "/etc/turbolinux-release",
- "/etc/ultrapenguin-release", "/etc/UnitedLinux-release",
- "/etc/va-release", "/etc/yellowdog-release"
- };
-
- const char description[] = "DISTRIB_DESCRIPTION=\"";
- const char str_debian[] = "Debian ";
-
- for (i = 0; i < countof(releases); i++)
- {
- file = fopen(releases[i], "r");
- if (!file)
- {
- continue;
- }
-
- if (i == RELEASE_DEBIAN)
- {
- strcpy(buf, str_debian);
- pos += strlen(str_debian);
- len -= strlen(str_debian);
- }
-
- fseek(file, 0, SEEK_END);
- len = min(ftell(file), len);
- rewind(file);
- pos[len] = '\0';
- if (fread(pos, 1, len, file) != len)
- {
- DBG1(DBG_PTS, "failed to read file '%s'", releases[i]);
- fclose(file);
- return NULL;
- }
- fclose(file);
-
- if (i == RELEASE_LSB)
- {
- pos = strstr(buf, description);
- if (!pos)
- {
- DBG1(DBG_PTS, "failed to find begin of lsb-release "
- "DESCRIPTION field");
- return NULL;
- }
- value = pos + strlen(description);
- pos = strchr(value, '"');
- if (!pos)
- {
- DBG1(DBG_PTS, "failed to find end of lsb-release "
- "DESCRIPTION field");
- return NULL;
- }
- }
- else
- {
- value = buf;
- pos = strchr(pos, '\n');
- if (!pos)
- {
- DBG1(DBG_PTS, "failed to find end of release string");
- return NULL;
- }
- }
- break;
- }
-
- if (!value)
- {
- DBG1(DBG_PTS, "no distribution release file found");
- return NULL;
- }
-
- if (uname(&uninfo) < 0)
- {
- DBG1(DBG_PTS, "could not retrieve machine architecture");
- return NULL;
- }
-
- *pos++ = ' ';
- len = sizeof(buf)-1 + (pos - buf);
- strncpy(pos, uninfo.machine, len);
-
- DBG1(DBG_PTS, "platform is '%s'", value);
- return strdup(value);
-}
+#ifdef TSS_TROUSERS
/**
* Check for a TPM by querying for TPM Version Info
@@ -1471,12 +1149,30 @@ static bool has_tpm(private_pts_t *this)
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 = {
@@ -1494,19 +1190,15 @@ pts_t *pts_create(bool is_imc)
.set_platform_info = _set_platform_info,
.get_tpm_version_info = _get_tpm_version_info,
.set_tpm_version_info = _set_tpm_version_info,
- .get_pcr_len = _get_pcr_len,
.get_aik = _get_aik,
.set_aik = _set_aik,
.get_aik_keyid = _get_aik_keyid,
.is_path_valid = _is_path_valid,
- .hash_file = _hash_file,
- .do_measurements = _do_measurements,
.get_metadata = _get_metadata,
.read_pcr = _read_pcr,
.extend_pcr = _extend_pcr,
.quote_tpm = _quote_tpm,
- .select_pcr = _select_pcr,
- .add_pcr = _add_pcr,
+ .get_pcrs = _get_pcrs,
.get_quote_info = _get_quote_info,
.verify_quote_signature = _verify_quote_signature,
.destroy = _destroy,
@@ -1515,16 +1207,14 @@ pts_t *pts_create(bool 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)
{
- this->platform_info = extract_platform_info();
-
if (has_tpm(this))
{
this->has_tpm = TRUE;
- this->pcr_len = PCR_LEN;
this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D;
load_aik(this);
load_aik_blob(this);
diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h
index 212acb02a..11154aa38 100644
--- a/src/libpts/pts/pts.h
+++ b/src/libpts/pts/pts.h
@@ -15,7 +15,7 @@
/**
* @defgroup pts pts
- * @{ @ingroup pts
+ * @{ @ingroup libpts
*/
#ifndef PTS_H_
@@ -29,12 +29,13 @@ typedef struct pts_t pts_t;
#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 <utils/linked_list.h>
+#include <collections/linked_list.h>
/**
* UTF-8 encoding of the character used to delimiter the filename
@@ -170,9 +171,10 @@ struct pts_t {
/**
* Set Platform and OS Info
*
- * @param info Platform and OS info
+ * @param name OS name
+ * @param version OS version
*/
- void (*set_platform_info)(pts_t *this, char *info);
+ void (*set_platform_info)(pts_t *this, chunk_t name, chunk_t version);
/**
* Get TPM 1.2 Version Info
@@ -190,13 +192,6 @@ struct pts_t {
void (*set_tpm_version_info)(pts_t *this, chunk_t info);
/**
- * Get the length of the TPM PCR registers
- *
- * @return Length of PCR registers in bytes, 0 if undefined
- */
- size_t (*get_pcr_len)(pts_t *this);
-
- /**
* Get Attestation Identity Certificate or Public Key
*
* @return AIK Certificate or Public Key
@@ -230,34 +225,13 @@ struct pts_t {
bool (*is_path_valid)(pts_t *this, char *path, pts_error_code_t *error_code);
/**
- * Compute a hash over a file
- * @param hasher Hasher to be used
- * @param pathname Absolute path of a file
- * @param hash Buffer to keep hash output
- * @return TRUE if path is valid and hashing succeeded
- */
- bool (*hash_file)(pts_t *this, hasher_t *hasher, char *pathname, u_char *hash);
-
- /**
- * Do PTS File Measurements
- *
- * @param request_id ID of PTS File Measurement Request
- * @param pathname Absolute pathname of file to be measured
- * @param is_directory TRUE if directory contents are measured
- * @return PTS File Measurements of NULL if FAILED
- */
- pts_file_meas_t* (*do_measurements)(pts_t *this, u_int16_t request_id,
- char *pathname, bool is_directory);
-
- /**
* Obtain file metadata
*
* @param pathname Absolute pathname of file/directory
- * @param is_directory TRUE if directory contents are requested
+ * @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_directory);
+ pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir);
/**
* Reads given PCR value and returns it
@@ -294,24 +268,12 @@ struct pts_t {
bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp,
chunk_t *quote_sig);
- /**
- * Mark an extended PCR as selected
- *
- * @param pcr Number of the extended PCR
- * @return TRUE if PCR number is valid
- */
- bool (*select_pcr)(pts_t *this, u_int32_t pcr);
-
- /**
- * Add an extended PCR with its corresponding value
+ /**
+ * Get the shadow PCR set
*
- * @param pcr Number of the extended PCR
- * @param pcr_before PCR value before extension
- * @param pcr_after PCR value after extension
- * @return TRUE if PCR number and register length is valid
+ * @return shadow PCR set
*/
- bool (*add_pcr)(pts_t *this, u_int32_t pcr, chunk_t pcr_before,
- chunk_t pcr_after);
+ pts_pcr_t* (*get_pcrs)(pts_t *this);
/**
* Constructs and returns TPM Quote Info structure expected from IMC
diff --git a/src/libpts/pts/pts_creds.c b/src/libpts/pts/pts_creds.c
index 5a6197bdb..bc483eb84 100644
--- a/src/libpts/pts/pts_creds.c
+++ b/src/libpts/pts/pts_creds.c
@@ -15,7 +15,7 @@
#include "pts_creds.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <credentials/certificates/x509.h>
#include <credentials/sets/mem_cred.h>
diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c
index 282755c0a..e5a06cc8d 100644
--- a/src/libpts/pts/pts_database.c
+++ b/src/libpts/pts/pts_database.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Sansar Choinyambuu
+ * 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
@@ -13,9 +13,12 @@
* for more details.
*/
+#define _GNU_SOURCE
+#include <stdio.h>
+
#include "pts_database.h"
-#include <debug.h>
+#include <utils/debug.h>
#include <crypto/hashers/hasher.h>
@@ -39,60 +42,69 @@ struct private_pts_database_t {
};
-METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
- private_pts_database_t *this, char *product)
+METHOD(pts_database_t, get_pathname, char*,
+ private_pts_database_t *this, bool is_dir, int id)
{
enumerator_t *e;
+ char *path, *name, *pathname;
- /* look for all entries belonging to a product in the files table */
- e = this->db->query(this->db,
- "SELECT f.id, f.type, f.path FROM files AS f "
- "JOIN product_file AS pf ON f.id = pf.file "
- "JOIN products AS p ON p.id = pf.product "
- "WHERE p.name = ? AND pf.measurement = 1",
- DB_TEXT, product, DB_INT, DB_INT, DB_TEXT);
- return e;
-}
-
-METHOD(pts_database_t, create_file_meta_enumerator, enumerator_t*,
- private_pts_database_t *this, char *product)
-{
- enumerator_t *e;
+ 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) ||
+ asprintf(&pathname, "%s%s%s",
+ path, streq(path, "/") ? "" : "/", name) == -1)
+ {
+ pathname = NULL;
+ }
+ }
+ DESTROY_IF(e);
- /* look for all entries belonging to a product in the files table */
- e = this->db->query(this->db,
- "SELECT f.type, f.path FROM files AS f "
- "JOIN product_file AS pf ON f.id = pf.file "
- "JOIN products AS p ON p.id = pf.product "
- "WHERE p.name = ? AND pf.metadata = 1",
- DB_TEXT, product, DB_INT, DB_TEXT);
- return e;
+ return pathname;
}
METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
private_pts_database_t *this, char *product, pts_meas_algorithms_t algo,
- int id, bool is_dir)
+ bool is_dir, int id)
{
enumerator_t *e;
if (is_dir)
{
e = this->db->query(this->db,
- "SELECT f.path, fh.hash FROM file_hashes AS fh "
- "JOIN files AS f ON fh.file = f.id "
- "JOIN products AS p ON fh.product = p.id "
- "WHERE p.name = ? AND fh.directory = ? AND fh.algo = ? "
- "ORDER BY f.path",
- DB_TEXT, product, DB_INT, id, DB_INT, algo, DB_TEXT, DB_BLOB);
+ "SELECT f.name, fh.hash FROM file_hashes AS fh "
+ "JOIN files AS f ON f.id = fh.file "
+ "JOIN products AS p ON p.id = fh.product "
+ "JOIN directories as d ON d.id = f.dir "
+ "WHERE p.name = ? AND fh.algo = ? AND d.id = ? "
+ "ORDER BY f.name",
+ DB_TEXT, product, DB_INT, algo, DB_INT, id, DB_TEXT, DB_BLOB);
}
else
{
e = this->db->query(this->db,
- "SELECT f.path, fh.hash FROM file_hashes AS fh "
- "JOIN files AS f ON fh.file = f.id "
- "JOIN products AS p ON fh.product = p.id "
- "WHERE p.name = ? AND fh.file = ? AND fh.algo = ?",
- DB_TEXT, product, DB_INT, id, DB_INT, algo, DB_TEXT, DB_BLOB);
+ "SELECT f.name, fh.hash FROM file_hashes AS fh "
+ "JOIN files AS f ON f.id = fh.file "
+ "JOIN products AS p ON p.id = fh.product "
+ "WHERE p.name = ? AND fh.algo = ? AND fh.file = ?",
+ DB_TEXT, product, DB_INT, algo, DB_INT, id, DB_TEXT, DB_BLOB);
}
return e;
}
@@ -121,6 +133,150 @@ METHOD(pts_database_t, check_aik_keyid, status_t,
return SUCCESS;
}
+METHOD(pts_database_t, add_file_measurement, status_t,
+ private_pts_database_t *this, char *product, 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, pid = 0;
+ status_t status = SUCCESS;
+
+ /* get primary key of product string */
+ e = this->db->query(this->db,
+ "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT);
+ if (e)
+ {
+ e->enumerate(e, &pid);
+ e->destroy(e);
+ }
+ if (pid == 0)
+ {
+ return FAILED;
+ }
+
+ 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, check_file_measurement, status_t,
+ private_pts_database_t *this, char *product, pts_meas_algorithms_t algo,
+ chunk_t measurement, char *filename)
+{
+ enumerator_t *e;
+ chunk_t hash;
+ status_t status = NOT_FOUND;
+
+ e = this->db->query(this->db,
+ "SELECT fh.hash FROM file_hashes AS fh "
+ "JOIN files AS f ON f.id = fh.file "
+ "JOIN products AS p ON p.id = fh.product "
+ "WHERE p.name = ? AND f.path = ? AND fh.algo = ?",
+ DB_TEXT, product, DB_TEXT, filename, DB_INT, algo, DB_BLOB);
+ if (!e)
+ {
+ return FAILED;
+ }
+ while (e->enumerate(e, &hash))
+ {
+ /* with relative filenames there might be multiple entries */
+ if (chunk_equals(measurement, hash))
+ {
+ status = SUCCESS;
+ break;
+ }
+ else
+ {
+ status = VERIFY_ERROR;
+ }
+ }
+ e->destroy(e);
+
+ return status;
+}
+
METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*,
private_pts_database_t *this, int kid)
{
@@ -143,7 +299,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
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 = ? "
@@ -152,7 +308,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
DB_INT, pcr, DB_INT, algo, DB_BLOB);
if (!e)
{
- DBG1(DBG_PTS, "no database query enumerator returned");
+ DBG1(DBG_PTS, "no database query enumerator returned");
return FAILED;
}
@@ -169,7 +325,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
"found in database", pcr, seq_no);
DBG1(DBG_PTS, " expected: %#B", &hash);
DBG1(DBG_PTS, " received: %#B", &measurement);
- status = FAILED;
+ status = VERIFY_ERROR;
break;
}
}
@@ -189,7 +345,7 @@ METHOD(pts_database_t, insert_comp_measurement, status_t,
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) "
@@ -272,41 +428,38 @@ METHOD(pts_database_t, get_comp_measurement_count, status_t,
METHOD(pts_database_t, destroy, void,
private_pts_database_t *this)
{
- this->db->destroy(this->db);
free(this);
}
/**
* See header
*/
-pts_database_t *pts_database_create(char *uri)
+pts_database_t *pts_database_create(imv_database_t *imv_db)
{
private_pts_database_t *this;
+ if (!imv_db)
+ {
+ return NULL;
+ }
+
INIT(this,
.public = {
- .create_file_meas_enumerator = _create_file_meas_enumerator,
- .create_file_meta_enumerator = _create_file_meta_enumerator,
+ .get_pathname = _get_pathname,
.create_comp_evid_enumerator = _create_comp_evid_enumerator,
.create_file_hash_enumerator = _create_file_hash_enumerator,
.check_aik_keyid = _check_aik_keyid,
+ .add_file_measurement = _add_file_measurement,
+ .check_file_measurement = _check_file_measurement,
.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 = lib->db->create(lib->db, uri),
+ .db = imv_db->get_database(imv_db),
);
- if (!this->db)
- {
- DBG1(DBG_PTS,
- "failed to connect to PTS file measurement database '%s'", uri);
- free(this);
- return NULL;
- }
-
return &this->public;
}
diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h
index a9a68ac76..eb8aca346 100644
--- a/src/libpts/pts/pts_database.h
+++ b/src/libpts/pts/pts_database.h
@@ -25,6 +25,8 @@ 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>
/**
@@ -34,35 +36,26 @@ typedef struct pts_database_t pts_database_t;
struct pts_database_t {
/**
- * Get files/directories to be measured by PTS
- *
- * @param product Software product (os, vpn client, etc.)
- * @return Enumerator over all matching files/directories
- */
- enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this,
- char *product);
-
- /**
- * Get files/directories to request metadata of
+ * Get absolute pathname for file or directory measurement
*
- * @param product Software product (os, vpn client, etc.)
- * @return Enumerator over all matching files/directories
+ * @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
*/
- enumerator_t* (*create_file_meta_enumerator)(pts_database_t *this,
- char *product);
+ char* (*get_pathname)(pts_database_t *this, bool is_dir, int id);
/**
* Get stored measurement hash for single file or directory entries
*
* @param product Software product (os, vpn client, etc.)
* @param algo Hash algorithm used for measurement
- * @param id Primary key of measured file/directory
* @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,
char *product, pts_meas_algorithms_t algo,
- int id, bool is_dir);
+ bool is_dir, int id);
/**
* Check if an AIK given by its keyid is registered in the database
@@ -82,6 +75,35 @@ struct pts_database_t {
enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, int kid);
/**
+ * Add PTS file measurement reference value
+ *
+ * @param product Software product (os, vpn client, etc.)
+ * @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, char *product,
+ pts_meas_algorithms_t algo,
+ chunk_t measurement, char *filename,
+ bool is_dir, int id);
+
+ /**
+ * Check PTS file measurement against reference stored in database
+ *
+ * @param product Software product (os, vpn client, etc.)
+ * @param algo File measurement hash algorithm used
+ * @param measurement File measurement hash
+ * @param filename Optional name of the file to be checked
+ * @return Status
+ */
+ status_t (*check_file_measurement)(pts_database_t *this, char *product,
+ pts_meas_algorithms_t algo,
+ chunk_t measurement, char *filename);
+
+ /**
* Check a functional component measurement against value stored in database
*
* @param measurement measurement hash
@@ -146,8 +168,8 @@ struct pts_database_t {
/**
* Creates an pts_database_t object
*
- * @param uri database uri
+ * @param imv_db Already attached IMV database
*/
-pts_database_t* pts_database_create(char *uri);
+pts_database_t* pts_database_create(imv_database_t *imv_db);
#endif /** PTS_DATABASE_H_ @}*/
diff --git a/src/libpts/pts/pts_dh_group.c b/src/libpts/pts/pts_dh_group.c
index fb141327f..41a436036 100644
--- a/src/libpts/pts/pts_dh_group.c
+++ b/src/libpts/pts/pts_dh_group.c
@@ -15,7 +15,7 @@
#include "pts_dh_group.h"
-#include <debug.h>
+#include <utils/debug.h>
/**
* Described in header.
@@ -27,7 +27,7 @@ bool pts_dh_group_probe(pts_dh_group_t *dh_groups)
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);
diff --git a/src/libpts/pts/pts_dh_group.h b/src/libpts/pts/pts_dh_group.h
index 8664a4b84..2aab90263 100644
--- a/src/libpts/pts/pts_dh_group.h
+++ b/src/libpts/pts/pts_dh_group.h
@@ -48,12 +48,12 @@ enum pts_dh_group_t {
* 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
+ * 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|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
+ *
*/
/**
@@ -90,8 +90,8 @@ bool pts_dh_group_update(char *dh_group, pts_dh_group_t *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_dh_groups,
- pts_dh_group_t offered_dh_groups);
+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
diff --git a/src/libpts/pts/pts_error.c b/src/libpts/pts/pts_error.c
index 6e914b2a9..1e79689f9 100644
--- a/src/libpts/pts/pts_error.c
+++ b/src/libpts/pts/pts_error.c
@@ -46,13 +46,13 @@ 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(PEN_TCG, TCG_PTS_HASH_ALG_NOT_SUPPORTED,
- msg_info);
+ attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
@@ -66,13 +66,13 @@ 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(PEN_TCG, TCG_PTS_DH_GRPS_NOT_SUPPORTED,
- msg_info);
+ attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
@@ -86,13 +86,13 @@ 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(PEN_TCG, TCG_PTS_BAD_NONCE_LENGTH,
- msg_info);
+ attr = ietf_attr_pa_tnc_error_create(error_code, msg_info);
writer->destroy(writer);
return attr;
diff --git a/src/libpts/pts/pts_file_meas.c b/src/libpts/pts/pts_file_meas.c
index f0e0d4c0a..f684087d7 100644
--- a/src/libpts/pts/pts_file_meas.c
+++ b/src/libpts/pts/pts_file_meas.c
@@ -15,8 +15,12 @@
#include "pts_file_meas.h"
-#include <utils/linked_list.h>
-#include <debug.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;
@@ -107,6 +111,51 @@ METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
(void*)entry_filter, NULL, NULL);
}
+METHOD(pts_file_meas_t, check, bool,
+ private_pts_file_meas_t *this, pts_database_t *pts_db, char *product,
+ pts_meas_algorithms_t algo)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ 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 = pts_db->check_file_measurement(pts_db, product, algo,
+ entry->measurement, entry->filename);
+ 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)
{
@@ -130,7 +179,7 @@ METHOD(pts_file_meas_t, verify, bool,
}
}
enumerator->destroy(enumerator);
-
+
if (!found)
{
DBG1(DBG_PTS, " no measurement found for '%s'", filename);
@@ -151,7 +200,7 @@ METHOD(pts_file_meas_t, verify, bool,
break;
}
}
- return success;
+ return success;
}
METHOD(pts_file_meas_t, destroy, void,
@@ -174,6 +223,7 @@ pts_file_meas_t *pts_file_meas_create(u_int16_t request_id)
.get_file_count = _get_file_count,
.add = _add,
.create_enumerator = _create_enumerator,
+ .check = _check,
.verify = _verify,
.destroy = _destroy,
},
@@ -184,3 +234,127 @@ pts_file_meas_t *pts_file_meas_create(u_int16_t request_id)
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 ? basename(pathname) : pathname;
+ DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
+ add(this, filename, measurement);
+ }
+
+end:
+ hasher->destroy(hasher);
+ if (success)
+ {
+ return &this->public;
+ }
+ else
+ {
+ destroy(this);
+ return NULL;
+ }
+}
diff --git a/src/libpts/pts/pts_file_meas.h b/src/libpts/pts/pts_file_meas.h
index 3ebb5c2a0..a13bb29ba 100644
--- a/src/libpts/pts/pts_file_meas.h
+++ b/src/libpts/pts/pts_file_meas.h
@@ -21,6 +21,8 @@
#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;
@@ -55,15 +57,26 @@ struct pts_file_meas_t {
/**
* Create a PTS File Measurement enumerator
*
- * @return Enumerator returning filename and measurement
+ * @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 product Software product (os, vpn client, etc.)
+ * @param algo PTS Measurement algorithm used
+ * @return TRUE if all measurements agreed
+ */
+ bool (*check)(pts_file_meas_t *this, pts_database_t *db, char* product,
+ pts_meas_algorithms_t algo);
+
+ /**
* Verify stored hashes against PTS File Measurements
*
* @param e_hash Hash enumerator
- * @paraem is_dir TRUE for directory contents hashes
+ * @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);
@@ -82,4 +95,17 @@ struct pts_file_meas_t {
*/
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/libpts/pts/pts_file_meta.c b/src/libpts/pts/pts_file_meta.c
index 6ed1c01b4..9cca0a5a5 100644
--- a/src/libpts/pts/pts_file_meta.c
+++ b/src/libpts/pts/pts_file_meta.c
@@ -15,8 +15,8 @@
#include "pts_file_meta.h"
-#include <utils/linked_list.h>
-#include <debug.h>
+#include <collections/linked_list.h>
+#include <utils/debug.h>
typedef struct private_pts_file_meta_t private_pts_file_meta_t;
diff --git a/src/libpts/pts/pts_meas_algo.c b/src/libpts/pts/pts_meas_algo.c
index 865857d3c..16a66e7b3 100644
--- a/src/libpts/pts/pts_meas_algo.c
+++ b/src/libpts/pts/pts_meas_algo.c
@@ -15,14 +15,23 @@
#include "pts_meas_algo.h"
-#include <debug.h>
+#include <utils/debug.h>
-ENUM(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_SHA384,
- "None",
- "SHA1",
- "SHA256",
- "SHA384"
-);
+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_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1_IMA, PTS_MEAS_ALGO_SHA1_IMA,
+ PTS_MEAS_ALGO_SHA1,
+ "SHA1-IMA");
+ENUM_END(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1_IMA);
/**
* Described in header.
@@ -34,7 +43,7 @@ bool pts_meas_algo_probe(pts_meas_algorithms_t *algorithms)
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);
diff --git a/src/libpts/pts/pts_meas_algo.h b/src/libpts/pts/pts_meas_algo.h
index 1d96a4946..27cdaea7e 100644
--- a/src/libpts/pts/pts_meas_algo.h
+++ b/src/libpts/pts/pts_meas_algo.h
@@ -30,10 +30,11 @@ 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_SHA1 = (1<<15),
- PTS_MEAS_ALGO_SHA256 = (1<<14),
- PTS_MEAS_ALGO_SHA384 = (1<<13),
+ PTS_MEAS_ALGO_NONE = 0,
+ PTS_MEAS_ALGO_SHA384 = (1<<13),
+ PTS_MEAS_ALGO_SHA256 = (1<<14),
+ PTS_MEAS_ALGO_SHA1 = (1<<15),
+ PTS_MEAS_ALGO_SHA1_IMA = (1<<16), /* internal use only */
};
/**
diff --git a/src/libpts/pts/pts_pcr.c b/src/libpts/pts/pts_pcr.c
new file mode 100644
index 000000000..0af93b608
--- /dev/null
+++ b/src/libpts/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/libpts/pts/pts_pcr.h b/src/libpts/pts/pts_pcr.h
new file mode 100644
index 000000000..f638b5ee4
--- /dev/null
+++ b/src/libpts/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_ @}*/