summaryrefslogtreecommitdiff
path: root/src/libpts/pts
diff options
context:
space:
mode:
Diffstat (limited to 'src/libpts/pts')
-rw-r--r--src/libpts/pts/components/ita/ita_comp_ima.c694
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tboot.c95
-rw-r--r--src/libpts/pts/components/ita/ita_comp_tgrub.c7
-rw-r--r--src/libpts/pts/components/pts_component.h5
-rw-r--r--src/libpts/pts/pts.c152
-rw-r--r--src/libpts/pts/pts.h22
-rw-r--r--src/libpts/pts/pts_database.c172
-rw-r--r--src/libpts/pts/pts_database.h62
-rw-r--r--src/libpts/pts/pts_file_meas.c117
-rw-r--r--src/libpts/pts/pts_file_meas.h5
-rw-r--r--src/libpts/pts/pts_ima_bios_list.c294
-rw-r--r--src/libpts/pts/pts_ima_bios_list.h74
-rw-r--r--src/libpts/pts/pts_ima_event_list.c330
-rw-r--r--src/libpts/pts/pts_ima_event_list.h80
-rw-r--r--src/libpts/pts/pts_meas_algo.c7
-rw-r--r--src/libpts/pts/pts_meas_algo.h4
16 files changed, 1379 insertions, 741 deletions
diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c
index c6b4131bf..be8aa40ad 100644
--- a/src/libpts/pts/components/ita/ita_comp_ima.c
+++ b/src/libpts/pts/components/ita/ita_comp_ima.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Andreas Steffen
+ * Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,27 +18,20 @@
#include "libpts.h"
#include "pts/pts_pcr.h"
+#include "pts/pts_ima_bios_list.h"
+#include "pts/pts_ima_event_list.h"
#include "pts/components/pts_component.h"
#include <utils/debug.h>
+#include <crypto/hashers/hasher.h>
#include <pen/pen.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-
#define SECURITY_DIR "/sys/kernel/security/"
#define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements"
#define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements"
-#define IMA_PCR 10
-#define IMA_TYPE_LEN 3
-#define IMA_FILENAME_LEN_MAX 255
+#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 {
@@ -66,14 +59,9 @@ struct pts_ita_comp_ima_t {
pts_comp_func_name_t *name;
/**
- * AIK keyid
- */
- chunk_t keyid;
-
- /**
* Sub-component depth
*/
- u_int32_t depth;
+ uint32_t depth;
/**
* PTS measurement database
@@ -83,7 +71,7 @@ struct pts_ita_comp_ima_t {
/**
* Primary key for AIK database entry
*/
- int kid;
+ int aik_id;
/**
* Primary key for IMA BIOS Component Functional Name database entry
@@ -118,12 +106,12 @@ struct pts_ita_comp_ima_t {
/**
* IMA BIOS measurements
*/
- linked_list_t *bios_list;
+ pts_ima_bios_list_t *bios_list;
/**
* IMA runtime file measurements
*/
- linked_list_t *ima_list;
+ pts_ima_event_list_t *ima_list;
/**
* Whether to send pcr_before and pcr_after info
@@ -131,9 +119,9 @@ struct pts_ita_comp_ima_t {
bool pcr_info;
/**
- * IMA measurement time
+ * Creation time of measurement
*/
- time_t measurement_time;
+ time_t creation_time;
/**
* IMA state machine
@@ -173,222 +161,11 @@ struct pts_ita_comp_ima_t {
};
/**
- * Linux IMA BIOS measurement entry
- */
-struct bios_entry_t {
-
- /**
- * PCR register
- */
- u_int32_t pcr;
-
- /**
- * 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 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_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_bios_measurements(char *file, linked_list_t *list,
- time_t *created)
-{
- u_int32_t pcr, num, len;
- bios_entry_t *entry;
- struct stat st;
- ssize_t res;
- int fd;
-
- fd = open(file, O_RDONLY);
- if (fd == -1)
- {
- DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
- return FALSE;
- }
-
- 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 bios measurements '%s' (%d entries)",
- file, list->get_count(list));
- close(fd);
- return TRUE;
- }
-
- entry = malloc_thing(bios_entry_t);
- entry->pcr = pcr;
- entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
-
- if (res != 4)
- {
- break;
- }
- if (read(fd, &num, 4) != 4)
- {
- break;
- }
- if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
- {
- break;
- }
- if (read(fd, &len, 4) != 4)
- {
- break;
- }
- if (lseek(fd, len, SEEK_CUR) == -1)
- {
- break;
- }
- list->insert_last(list, entry);
- }
-
- 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
+ * Extend measurement into PCR and 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)
+ uint8_t qualifier, pts_pcr_t *pcrs,
+ uint32_t pcr, chunk_t measurement)
{
size_t pcr_len;
pts_pcr_transform_t pcr_transform;
@@ -414,7 +191,7 @@ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
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);
+ pcr_transform, this->creation_time, measurement);
if (this->pcr_info)
{
pcr_after =chunk_clone(pcrs->get(pcrs, pcr));
@@ -424,15 +201,83 @@ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
}
/**
+ * Generate an IMA or IMA-NG hash from an event digest and event name
+ *
+ * @param digest event digest
+ * @param ima_algo hash algorithm string ("sha1:", "sha256:", etc.)
+ * @param ima_name event name
+ * @param little_endian endianness of client platform
+ * @param algo hash algorithm used by TPM
+ * @param hash_buf hash value to be compared with TPM measurement
+ */
+static bool ima_hash(chunk_t digest, char *ima_algo, char *ima_name,
+ bool little_endian, pts_meas_algorithms_t algo,
+ char *hash_buf)
+{
+ hash_algorithm_t hash_alg;
+ hasher_t *hasher;
+ bool success;
+
+ hash_alg = pts_meas_algo_to_hash(algo);
+ hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
+ if (!hasher)
+ {
+ DBG1(DBG_PTS, "%N hasher could not be created",
+ hash_algorithm_short_names, hash_alg);
+ return FALSE;
+ }
+
+ if (ima_algo)
+ {
+ uint32_t d_len, n_len;
+ chunk_t algo_name, event_name, digest_len, name_len;
+
+ /* IMA-NG hash */
+ algo_name = chunk_create(ima_algo, strlen(ima_algo) + 1);
+ event_name = chunk_create(ima_name, strlen(ima_name) + 1);
+
+ d_len = algo_name.len + digest.len;
+ digest_len = chunk_create((uint8_t*)&d_len, sizeof(d_len));
+ /* TODO handle endianness of both client and server platforms */
+
+ n_len = event_name.len;
+ name_len = chunk_create((uint8_t*)&n_len, sizeof(n_len));
+ /* TODO handle endianness of both client and server platforms */
+
+ success = hasher->get_hash(hasher, digest_len, NULL) &&
+ hasher->get_hash(hasher, algo_name, NULL) &&
+ hasher->get_hash(hasher, digest, NULL) &&
+ hasher->get_hash(hasher, name_len, NULL) &&
+ hasher->get_hash(hasher, event_name, hash_buf);
+ }
+ else
+ {
+ u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
+ chunk_t file_name;
+
+ /* IMA legacy hash */
+ memset(filename_buffer, 0, sizeof(filename_buffer));
+ strncpy(filename_buffer, ima_name, IMA_FILENAME_LEN_MAX);
+ file_name = chunk_create (filename_buffer, sizeof(filename_buffer));
+
+ success = hasher->get_hash(hasher, digest, NULL) &&
+ hasher->get_hash(hasher, file_name, hash_buf);
+ }
+ hasher->destroy(hasher);
+
+ return success;
+}
+
+/**
* Compute and check boot aggregate value by hashing PCR0 to PCR7
*/
-static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement)
+static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement,
+ char *algo)
{
- 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;
+ chunk_t boot_aggregate;
hasher_t *hasher;
+ uint32_t i;
bool success, pcr_ok = TRUE;
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
@@ -448,19 +293,20 @@ static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement)
}
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);
+ pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer);
}
hasher->destroy(hasher);
if (pcr_ok)
{
+ boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer));
+
+ /* TODO handle endianness of client platform */
+ pcr_ok = ima_hash(boot_aggregate, algo, "boot_aggregate",
+ TRUE, PTS_MEAS_ALGO_SHA1, pcr_buffer);
+ }
+ if (pcr_ok)
+ {
success = chunk_equals(boot_aggregate, measurement);
DBG1(DBG_PTS, "boot aggregate value is %scorrect",
success ? "":"in");
@@ -479,26 +325,28 @@ METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
return this->name;
}
-METHOD(pts_component_t, get_evidence_flags, u_int8_t,
+METHOD(pts_component_t, get_evidence_flags, uint8_t,
pts_ita_comp_ima_t *this)
{
return PTS_REQ_FUNC_COMP_EVID_PCR;
}
-METHOD(pts_component_t, get_depth, u_int32_t,
+METHOD(pts_component_t, get_depth, uint32_t,
pts_ita_comp_ima_t *this)
{
return this->depth;
}
METHOD(pts_component_t, measure, status_t,
- pts_ita_comp_ima_t *this, u_int8_t qualifier, pts_t *pts,
+ pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
pts_comp_evidence_t **evidence)
{
- bios_entry_t *bios_entry;
- ima_entry_t *ima_entry;
pts_pcr_t *pcrs;
pts_comp_evidence_t *evid = NULL;
+ size_t algo_len, name_len;
+ chunk_t measurement;
+ char *uri, *algo, *name;
+ uint32_t pcr;
status_t status;
pcrs = pts->get_pcrs(pts);
@@ -509,25 +357,25 @@ METHOD(pts_component_t, measure, status_t,
switch (this->state)
{
case IMA_STATE_INIT:
- if (!load_bios_measurements(IMA_BIOS_MEASUREMENTS,
- this->bios_list, &this->measurement_time))
+ this->bios_list = pts_ima_bios_list_create(
+ IMA_BIOS_MEASUREMENTS);
+ if (!this->bios_list)
{
return FAILED;
}
+ this->creation_time = this->bios_list->get_time(this->bios_list);
this->bios_count = this->bios_list->get_count(this->bios_list);
this->state = IMA_STATE_BIOS;
/* fall through to next state */
case IMA_STATE_BIOS:
- status = this->bios_list->remove_first(this->bios_list,
- (void**)&bios_entry);
+ status = this->bios_list->get_next(this->bios_list, &pcr,
+ &measurement);
if (status != SUCCESS)
{
DBG1(DBG_PTS, "could not retrieve bios measurement entry");
return status;
}
- evid = extend_pcr(this, qualifier, pcrs, bios_entry->pcr,
- bios_entry->measurement);
- free(bios_entry);
+ evid = extend_pcr(this, qualifier, pcrs, pcr, measurement);
this->state = this->bios_list->get_count(this->bios_list) ?
IMA_STATE_BIOS : IMA_STATE_INIT;
@@ -542,17 +390,20 @@ METHOD(pts_component_t, measure, status_t,
switch (this->state)
{
case IMA_STATE_INIT:
- if (!load_runtime_measurements(IMA_RUNTIME_MEASUREMENTS,
- this->ima_list, &this->measurement_time))
+ this->ima_list = pts_ima_event_list_create(
+ IMA_RUNTIME_MEASUREMENTS);
+ if (!this->ima_list)
{
return FAILED;
}
+ this->creation_time = this->ima_list->get_time(this->ima_list);
+ this->count = this->ima_list->get_count(this->ima_list);
this->state = IMA_STATE_BOOT_AGGREGATE;
/* fall through to next state */
case IMA_STATE_BOOT_AGGREGATE:
case IMA_STATE_RUNTIME:
- status = this->ima_list->remove_first(this->ima_list,
- (void**)&ima_entry);
+ status = this->ima_list->get_next(this->ima_list, &measurement,
+ &algo, &name);
if (status != SUCCESS)
{
DBG1(DBG_PTS, "could not retrieve ima measurement entry");
@@ -560,20 +411,33 @@ METHOD(pts_component_t, measure, status_t,
}
if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count)
{
- if (!check_boot_aggregate(pcrs, ima_entry->measurement))
+ if (!check_boot_aggregate(pcrs, measurement, algo))
{
return FAILED;
}
}
evid = extend_pcr(this, qualifier, pcrs, IMA_PCR,
- ima_entry->measurement);
+ measurement);
if (evid)
{
+ if (algo)
+ {
+ algo_len = strlen(algo);
+ name_len = strlen(name);
+ uri = malloc(algo_len + name_len + 1);
+ memcpy(uri, algo, algo_len);
+ strcpy(uri + algo_len, name);
+ }
+ else
+ {
+ uri = strdup(name);
+ }
evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
- ima_entry->filename);
+ uri);
+ free(uri);
}
- free(ima_entry->filename);
- free(ima_entry);
+ free(name);
+ free(algo);
this->state = this->ima_list->get_count(this->ima_list) ?
IMA_STATE_RUNTIME : IMA_STATE_END;
@@ -598,40 +462,80 @@ METHOD(pts_component_t, measure, status_t,
SUCCESS : NEED_MORE;
}
-METHOD(pts_component_t, verify, status_t,
- pts_ita_comp_ima_t *this, u_int8_t qualifier, pts_t *pts,
- pts_comp_evidence_t *evidence)
+/**
+ * Parse a validation URI of the form <hash algorithm>:<event name>
+ * into its components
+ */
+static pts_meas_algorithms_t parse_validation_uri(pts_comp_evidence_t *evidence,
+ char **ima_name, char **ima_algo, char *algo_buf)
{
- bool has_pcr_info;
- 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;
+ pts_meas_algorithms_t hash_algo;
+ char *uri, *pos, *algo, *name;
- /* some first time initializations */
- if (!this->keyid.ptr)
+ evidence->get_validation(evidence, &uri);
+
+ /* IMA-NG format? */
+ pos = strchr(uri, ':');
+ if (pos && (pos - uri + 1) < IMA_ALGO_LEN_MAX)
{
- if (!pts->get_aik_keyid(pts, &this->keyid))
+ memset(algo_buf, '\0', IMA_ALGO_LEN_MAX);
+ memcpy(algo_buf, uri, pos - uri + 1);
+ algo = algo_buf;
+ name = pos + 1;
+
+ if (streq(algo, "sha1:") || streq(algo, ":"))
+ {
+ hash_algo = PTS_MEAS_ALGO_SHA1;
+ }
+ else if (streq(algo, "sha256:"))
{
- DBG1(DBG_PTS, "AIK keyid not available");
- return FAILED;
+ hash_algo = PTS_MEAS_ALGO_SHA256;
}
- this->keyid = chunk_clone(this->keyid);
- if (!this->pts_db)
+ else if (streq(algo, "sha384:"))
{
- DBG1(DBG_PTS, "pts database not available");
- return FAILED;
+ hash_algo = PTS_MEAS_ALGO_SHA384;
+ }
+ else
+ {
+ hash_algo = PTS_MEAS_ALGO_NONE;
}
}
+ else
+ {
+ algo = NULL;
+ name = uri;
+ hash_algo = PTS_MEAS_ALGO_SHA1;
+ }
+
+ if (ima_name)
+ {
+ *ima_name = name;
+ }
+ if (ima_algo)
+ {
+ *ima_algo = algo;
+ }
+
+ return hash_algo;
+}
+
+METHOD(pts_component_t, verify, status_t,
+ pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
+ pts_comp_evidence_t *evidence)
+{
+ bool has_pcr_info;
+ uint32_t pcr;
+ pts_meas_algorithms_t algo;
+ pts_pcr_transform_t transform;
+ pts_pcr_t *pcrs;
+ time_t creation_time;
+ chunk_t measurement, pcr_before, pcr_after;
+ status_t status = NOT_FOUND;
+ this->aik_id = pts->get_aik_id(pts);
pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
- &measurement_time);
+ &creation_time);
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
@@ -641,26 +545,22 @@ METHOD(pts_component_t, verify, status_t,
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, this->aik_id, algo,
+ &this->bios_cid, &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);
+ DBG1(DBG_PTS, "checking %d BIOS evidence measurements",
+ this->bios_count);
}
else
{
- DBG1(DBG_PTS, "registering %N '%N' BIOS evidence measurements",
- pen_names, vid, names, name);
+ DBG1(DBG_PTS, "registering BIOS evidence measurements");
this->is_bios_registering = TRUE;
}
@@ -670,8 +570,8 @@ METHOD(pts_component_t, verify, status_t,
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);
+ measurement, this->bios_cid, this->aik_id,
+ ++this->seq_no, pcr, algo);
if (status != SUCCESS)
{
return status;
@@ -681,8 +581,8 @@ METHOD(pts_component_t, verify, status_t,
else
{
status = this->pts_db->check_comp_measurement(this->pts_db,
- measurement, this->bios_cid, this->kid,
- ++this->seq_no, pcr, algo);
+ measurement, this->bios_cid, this->aik_id,
+ ++this->seq_no, pcr, algo);
if (status == FAILED)
{
return status;
@@ -697,13 +597,34 @@ METHOD(pts_component_t, verify, status_t,
PTS_ITA_QUALIFIER_TYPE_OS))
{
int ima_count;
+ char *ima_algo, *ima_name;
+ char algo_buf[IMA_ALGO_LEN_MAX];
+ pts_meas_algorithms_t hash_algo;
+
+ hash_algo = parse_validation_uri(evidence, &ima_name, &ima_algo,
+ algo_buf);
switch (this->state)
{
case IMA_STATE_BIOS:
- if (!check_boot_aggregate(pcrs, measurement))
+ this->state = IMA_STATE_RUNTIME;
+
+ if (!streq(ima_name, "boot_aggregate"))
+ {
+ DBG1(DBG_PTS, "ima: name must be 'boot_aggregate' "
+ "but is '%s'", ima_name);
+ return FAILED;
+ }
+ if (hash_algo != PTS_MEAS_ALGO_SHA1)
+ {
+ DBG1(DBG_PTS, "ima: boot_aggregate algorithm must be %N "
+ "but is %N",
+ pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1,
+ pts_meas_algorithm_names, hash_algo);
+ return FAILED;
+ }
+ if (!check_boot_aggregate(pcrs, measurement, ima_algo))
{
- this->state = IMA_STATE_RUNTIME;
return FAILED;
}
this->state = IMA_STATE_INIT;
@@ -711,33 +632,30 @@ METHOD(pts_component_t, verify, status_t,
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, this->aik_id, algo,
+ &this->ima_cid, &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);
+ DBG1(DBG_PTS, "checking boot aggregate evidence "
+ "measurement");
status = this->pts_db->check_comp_measurement(this->pts_db,
measurement, this->ima_cid,
- this->kid, 1, pcr, algo);
+ this->aik_id, 1, pcr, algo);
}
else
{
- DBG1(DBG_PTS, "registering %N '%N' boot aggregate evidence "
- "measurement", pen_names, vid, names, name);
+ DBG1(DBG_PTS, "registering boot aggregate evidence "
+ "measurement");
this->is_ima_registering = TRUE;
status = this->pts_db->insert_comp_measurement(this->pts_db,
measurement, this->ima_cid,
- this->kid, 1, pcr, algo);
+ this->aik_id, 1, pcr, algo);
}
this->state = IMA_STATE_RUNTIME;
@@ -747,42 +665,76 @@ METHOD(pts_component_t, verify, status_t,
}
break;
case IMA_STATE_RUNTIME:
+ {
+ uint8_t hash_buf[HASH_SIZE_SHA512];
+ chunk_t digest, hash;
+ enumerator_t *e;
+
this->count++;
- if (evidence->get_validation(evidence, &uri) !=
+ if (evidence->get_validation(evidence, NULL) !=
PTS_COMP_EVID_VALIDATION_PASSED)
{
- DBG1(DBG_PTS, "policy URI could no be retrieved");
+ DBG1(DBG_PTS, "evidence validation failed");
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);
+ hash = chunk_create(hash_buf, pts_meas_algo_hash_size(algo));
+
+ e = this->pts_db->create_file_meas_enumerator(this->pts_db,
+ pts->get_platform_id(pts),
+ hash_algo, ima_name);
+ if (e)
+ {
+ while (e->enumerate(e, &digest))
+ {
+ if (!ima_hash(digest, ima_algo, ima_name,
+ FALSE, algo, hash_buf))
+ {
+ status = FAILED;
+ break;
+ }
+ if (chunk_equals(measurement, hash))
+ {
+ status = SUCCESS;
+ break;
+ }
+ else
+ {
+ status = VERIFY_ERROR;
+ }
+ }
+ e->destroy(e);
+ }
+ else
+ {
+ status = FAILED;
+ }
+
switch (status)
{
case SUCCESS:
DBG3(DBG_PTS, "%#B for '%s' is ok",
- &measurement, uri);
+ &measurement, ima_name);
this->count_ok++;
break;
case NOT_FOUND:
DBG2(DBG_PTS, "%#B for '%s' not found",
- &measurement, uri);
+ &measurement, ima_name);
this->count_unknown++;
break;
case VERIFY_ERROR:
DBG1(DBG_PTS, "%#B for '%s' differs",
- &measurement, uri);
+ &measurement, ima_name);
this->count_differ++;
break;
case FAILED:
default:
DBG1(DBG_PTS, "%#B for '%s' failed",
- &measurement, uri);
+ &measurement, ima_name);
this->count_failed++;
}
break;
+ }
default:
return FAILED;
}
@@ -818,16 +770,15 @@ METHOD(pts_component_t, verify, status_t,
}
METHOD(pts_component_t, finalize, bool,
- pts_ita_comp_ima_t *this, u_int8_t qualifier)
+ pts_ita_comp_ima_t *this, uint8_t qualifier, bio_writer_t *result)
{
- u_int32_t vid, name;
- enum_name_t *names;
+ char result_buf[BUF_LEN];
+ char *pos = result_buf;
+ size_t len = BUF_LEN;
+ int written;
bool success = TRUE;
this->name->set_qualifier(this->name, qualifier);
- 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 (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
@@ -838,16 +789,20 @@ METHOD(pts_component_t, finalize, bool,
/* 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);
+ snprintf(pos, len, "registered %d BIOS evidence measurements",
+ this->seq_no);
}
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);
+ snprintf(pos, len, "%d of %d BIOS evidence measurements missing",
+ this->bios_count - this->seq_no, this->bios_count);
success = FALSE;
}
+ else
+ {
+ snprintf(pos, len, "%d BIOS evidence measurements are ok",
+ this->bios_count);
+ }
}
else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
PTS_ITA_QUALIFIER_TYPE_OS))
@@ -858,26 +813,34 @@ METHOD(pts_component_t, finalize, bool,
/* close registration */
this->is_ima_registering = FALSE;
- DBG1(DBG_PTS, "registered %N '%N' boot aggregate evidence "
- "measurement", pen_names, vid, names, name);
+ written = snprintf(pos, len, "registered IMA boot aggregate "
+ "evidence measurement; ");
+ pos += written;
+ len -= written;
}
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;
+ snprintf(pos, len, "processed %d IMA file evidence measurements: "
+ "%d ok, %d unknown, %d differ, %d failed",
+ this->count, this->count_ok, this->count_unknown,
+ this->count_differ, this->count_failed);
+ }
+ else
+ {
+ snprintf(pos, len, "no IMA file evidence measurements");
+ success = FALSE;
}
}
else
{
- DBG1(DBG_PTS, "unsupported functional component name qualifier");
+ snprintf(pos, len, "unsupported functional component name qualifier");
success = FALSE;
}
this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
+ DBG1(DBG_PTS, "%s", result_buf);
+ result->write_data(result, chunk_from_str(result_buf));
+
return success;
}
@@ -892,35 +855,28 @@ METHOD(pts_component_t, destroy, void,
pts_ita_comp_ima_t *this)
{
int count;
- u_int32_t vid, name;
- enum_name_t *names;
if (ref_put(&this->ref))
{
- 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->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);
+ this->bios_cid, this->aik_id);
+ DBG1(DBG_PTS, "deleted %d registered BIOS evidence measurements",
+ count);
}
if (this->is_ima_registering)
{
count = this->pts_db->delete_comp_measurements(this->pts_db,
- this->ima_cid, this->kid);
- DBG1(DBG_PTS, "deleted registered %N '%N' boot aggregate evidence "
- "measurement", pen_names, vid, names, name);
+ this->ima_cid, this->aik_id);
+ DBG1(DBG_PTS, "deleted registered boot aggregate evidence "
+ "measurement");
}
- this->bios_list->destroy_function(this->bios_list,
- (void *)free_bios_entry);
- this->ima_list->destroy_function(this->ima_list,
- (void *)free_ima_entry);
+ DESTROY_IF(this->bios_list);
+ DESTROY_IF(this->ima_list);
this->name->destroy(this->name);
- free(this->keyid.ptr);
+
free(this);
}
}
@@ -928,7 +884,7 @@ METHOD(pts_component_t, destroy, void,
/**
* See header
*/
-pts_component_t *pts_ita_comp_ima_create(u_int32_t depth,
+pts_component_t *pts_ita_comp_ima_create(uint32_t depth,
pts_database_t *pts_db)
{
pts_ita_comp_ima_t *this;
@@ -948,10 +904,8 @@ pts_component_t *pts_ita_comp_ima_create(u_int32_t depth,
PTS_QUALIFIER_UNKNOWN),
.depth = depth,
.pts_db = pts_db,
- .bios_list = linked_list_create(),
- .ima_list = linked_list_create(),
.pcr_info = lib->settings->get_bool(lib->settings,
- "%s.plugins.imc-attestation.pcr_info", TRUE, lib->ns),
+ "%s.plugins.imc-attestation.pcr_info", FALSE, lib->ns),
.ref = 1,
);
diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.c b/src/libpts/pts/components/ita/ita_comp_tboot.c
index f4859f801..67be1ca3a 100644
--- a/src/libpts/pts/components/ita/ita_comp_tboot.c
+++ b/src/libpts/pts/components/ita/ita_comp_tboot.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Andreas Steffen
+ * Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -41,11 +41,6 @@ struct pts_ita_comp_tboot_t {
pts_comp_func_name_t *name;
/**
- * AIK keyid
- */
- chunk_t keyid;
-
- /**
* Sub-component depth
*/
u_int32_t depth;
@@ -56,6 +51,11 @@ struct pts_ita_comp_tboot_t {
pts_database_t *pts_db;
/**
+ * Primary key for AIK database entry
+ */
+ int aik_id;
+
+ /**
* Primary key for Component Functional Name database entry
*/
int cid;
@@ -201,51 +201,38 @@ METHOD(pts_component_t, verify, status_t,
chunk_t measurement, pcr_before, pcr_after;
status_t status;
+ this->aik_id = pts->get_aik_id(pts);
pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &extended_pcr,
&algo, &transform, &measurement_time);
- if (!this->keyid.ptr)
+ status = this->pts_db->get_comp_measurement_count(this->pts_db,
+ this->name, this->aik_id, algo,
+ &this->cid, &this->count);
+ if (status != SUCCESS)
{
- if (!pts->get_aik_keyid(pts, &this->keyid))
- {
- return FAILED;
- }
- this->keyid = chunk_clone(this->keyid);
-
- if (!this->pts_db)
- {
- DBG1(DBG_PTS, "pts database not available");
- return FAILED;
- }
- 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 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);
+ 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->count)
- {
- DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
- "measurements", this->count, pen_names, vid, names, name);
- }
- else
- {
- DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
- "measurements", pen_names, vid, names, name);
- this->is_registering = TRUE;
- }
+ if (this->count)
+ {
+ DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
+ "measurements", this->count, pen_names, vid, names, name);
+ }
+ else
+ {
+ DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
+ "measurements", pen_names, vid, names, name);
+ this->is_registering = TRUE;
}
if (this->is_registering)
{
status = this->pts_db->insert_comp_measurement(this->pts_db,
- measurement, this->cid, this->kid,
+ measurement, this->cid, this->aik_id,
++this->seq_no, extended_pcr, algo);
if (status != SUCCESS)
{
@@ -282,30 +269,31 @@ METHOD(pts_component_t, verify, status_t,
}
METHOD(pts_component_t, finalize, bool,
- pts_ita_comp_tboot_t *this, u_int8_t qualifier)
+ pts_ita_comp_tboot_t *this, u_int8_t qualifier, bio_writer_t *result)
{
- u_int32_t vid, name;
- enum_name_t *names;
-
- 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);
+ char result_buf[BUF_LEN];
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);
+ snprintf(result_buf, BUF_LEN, "registered %d evidence measurements",
+ this->seq_no);
}
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);
+ snprintf(result_buf, BUF_LEN, "%d of %d evidence measurements "
+ "missing", this->count - this->seq_no, this->count);
return FALSE;
}
+ else
+ {
+ snprintf(result_buf, BUF_LEN, "%d evidence measurements are ok",
+ this->count);
+ }
+ DBG1(DBG_PTS, "%s", result_buf);
+ result->write_data(result, chunk_from_str(result_buf));
return TRUE;
}
@@ -329,7 +317,7 @@ METHOD(pts_component_t, destroy, void,
if (this->is_registering)
{
count = this->pts_db->delete_comp_measurements(this->pts_db,
- this->cid, this->kid);
+ this->cid, this->aik_id);
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);
@@ -337,7 +325,6 @@ METHOD(pts_component_t, destroy, void,
"evidence measurements", count, pen_names, vid, names, name);
}
this->name->destroy(this->name);
- free(this->keyid.ptr);
free(this);
}
}
diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.c b/src/libpts/pts/components/ita/ita_comp_tgrub.c
index e3acd8774..097e4c89c 100644
--- a/src/libpts/pts/components/ita/ita_comp_tgrub.c
+++ b/src/libpts/pts/components/ita/ita_comp_tgrub.c
@@ -49,7 +49,6 @@ struct pts_ita_comp_tgrub_t {
*/
pts_database_t *pts_db;
-
/**
* Reference count
*/
@@ -126,7 +125,8 @@ METHOD(pts_component_t, verify, status_t,
pts_pcr_transform_t transform;
pts_pcr_t *pcrs;
time_t measurement_time;
- chunk_t measurement, pcr_before, pcr_after;
+ chunk_t pcr_before, pcr_after;
+ chunk_t measurement __attribute__((unused));
pcrs = pts->get_pcrs(pts);
measurement = evidence->get_measurement(evidence, &extended_pcr,
@@ -155,7 +155,7 @@ METHOD(pts_component_t, verify, status_t,
}
METHOD(pts_component_t, finalize, bool,
- pts_ita_comp_tgrub_t *this, u_int8_t qualifier)
+ pts_ita_comp_tgrub_t *this, u_int8_t qualifier, bio_writer_t *result)
{
return FALSE;
}
@@ -206,4 +206,3 @@ pts_component_t *pts_ita_comp_tgrub_create(u_int32_t depth,
return &this->public;
}
-
diff --git a/src/libpts/pts/components/pts_component.h b/src/libpts/pts/components/pts_component.h
index da339a55f..71b1ad59c 100644
--- a/src/libpts/pts/components/pts_component.h
+++ b/src/libpts/pts/components/pts_component.h
@@ -30,6 +30,7 @@ typedef struct pts_component_t pts_component_t;
#include "pts/components/pts_comp_evidence.h"
#include <library.h>
+#include <bio/bio_writer.h>
/**
* PTS Functional Component Interface
@@ -85,9 +86,11 @@ struct pts_component_t {
* and check for missing measurements
*
* @param qualifier PTS Component Functional Name Qualifier
+ * @param result writer appending concise measurement result
* @return TRUE if finalization successful
*/
- bool (*finalize)(pts_component_t *this, u_int8_t qualifier);
+ bool (*finalize)(pts_component_t *this, u_int8_t qualifier,
+ bio_writer_t *result);
/**
* Get a new reference to the PTS Functional Component
diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c
index 3ab9b92e6..2fff4c901 100644
--- a/src/libpts/pts/pts.c
+++ b/src/libpts/pts/pts.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
+ * Copyright (C) 2011-2012 Sansar Choinyambuu
+ * Copyright (C) 2012-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -21,6 +22,10 @@
#include <bio/bio_reader.h>
#ifdef TSS_TROUSERS
+#ifdef _BASETSD_H_
+/* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */
+# define _BASETSD_H
+#endif
#include <trousers/tss.h>
#include <trousers/trousers.h>
#else
@@ -34,7 +39,6 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/utsname.h>
#include <libgen.h>
#include <unistd.h>
#include <errno.h>
@@ -88,9 +92,9 @@ struct private_pts_t {
chunk_t secret;
/**
- * Platform and OS Info
+ * Primary key of platform entry in database
*/
- char *platform_info;
+ int platform_id;
/**
* TRUE if IMC-PTS, FALSE if IMV-PTS
@@ -118,6 +122,11 @@ struct private_pts_t {
certificate_t *aik;
/**
+ * Primary key referening AIK in database
+ */
+ int aik_id;
+
+ /**
* Shadow PCR set
*/
pts_pcr_t *pcrs;
@@ -296,29 +305,23 @@ METHOD(pts_t, calculate_secret, bool,
*/
static void print_tpm_version_info(private_pts_t *this)
{
- TPM_CAP_VERSION_INFO versionInfo;
- UINT64 offset = 0;
- TSS_RESULT result;
+ TPM_CAP_VERSION_INFO *info;
- result = Trspi_UnloadBlob_CAP_VERSION_INFO(&offset,
- this->tpm_version_info.ptr, &versionInfo);
- if (result != TSS_SUCCESS)
+ info = (TPM_CAP_VERSION_INFO*)this->tpm_version_info.ptr;
+
+ if (this->tpm_version_info.len >=
+ sizeof(*info) - sizeof(info->vendorSpecific))
{
- DBG1(DBG_PTS, "could not parse tpm version info: tss error 0x%x",
- result);
+ DBG2(DBG_PTS, "TPM Version Info: Chip Version: %u.%u.%u.%u, "
+ "Spec Level: %u, Errata Rev: %u, Vendor ID: %.4s",
+ info->version.major, info->version.minor,
+ info->version.revMajor, info->version.revMinor,
+ untoh16(&info->specLevel), info->errataRev, info->tpmVendorID);
}
else
{
- DBG2(DBG_PTS, "TPM 1.2 Version Info: Chip Version: %hhu.%hhu.%hhu.%hhu,"
- " 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.vendorSpecificSize,
- versionInfo.vendorSpecificSize ?
- (char*)versionInfo.vendorSpecific : "");
+ DBG1(DBG_PTS, "could not parse tpm version info");
}
- free(versionInfo.vendorSpecific);
}
#else
@@ -330,22 +333,16 @@ static void print_tpm_version_info(private_pts_t *this)
#endif /* TSS_TROUSERS */
-METHOD(pts_t, get_platform_info, char*,
+METHOD(pts_t, get_platform_id, int,
private_pts_t *this)
{
- return this->platform_info;
+ return this->platform_id;
}
-METHOD(pts_t, set_platform_info, void,
- private_pts_t *this, chunk_t name, chunk_t version)
+METHOD(pts_t, set_platform_id, void,
+ private_pts_t *this, int pid)
{
- 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 = malloc(len);
- snprintf(this->platform_info, len, "%.*s %.*s", (int)name.len, name.ptr,
- (int)version.len, version.ptr);
+ this->platform_id = pid;
}
METHOD(pts_t, get_tpm_version_info, bool,
@@ -372,42 +369,31 @@ METHOD(pts_t, set_tpm_version_info, void,
*/
static void load_aik_blob(private_pts_t *this)
{
- char *blob_path;
- FILE *fp;
- u_int32_t aikBlobLen;
+ char *path;
+ chunk_t *map;
- blob_path = lib->settings->get_str(lib->settings,
+ path = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.aik_blob", NULL, lib->ns);
-
- if (blob_path)
+ if (path)
{
- /* Read aik key blob from a file */
- if ((fp = fopen(blob_path, "r")) == NULL)
- {
- DBG1(DBG_PTS, "unable to open AIK Blob file: %s", blob_path);
- return;
- }
-
- fseek(fp, 0, SEEK_END);
- aikBlobLen = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
-
- this->aik_blob = chunk_alloc(aikBlobLen);
- if (fread(this->aik_blob.ptr, 1, aikBlobLen, fp) == aikBlobLen)
+ map = chunk_map(path, FALSE);
+ if (map)
{
- DBG2(DBG_PTS, "loaded AIK Blob from '%s'", blob_path);
- DBG3(DBG_PTS, "AIK Blob: %B", &this->aik_blob);
+ DBG2(DBG_PTS, "loaded AIK Blob from '%s'", path);
+ DBG3(DBG_PTS, "AIK Blob: %B", map);
+ this->aik_blob = chunk_clone(*map);
+ chunk_unmap(map);
}
else
{
- DBG1(DBG_PTS, "unable to read AIK Blob file '%s'", blob_path);
- chunk_free(&this->aik_blob);
+ DBG1(DBG_PTS, "unable to map AIK Blob file '%s': %s",
+ path, strerror(errno));
}
- fclose(fp);
- return;
}
-
- DBG1(DBG_PTS, "AIK Blob is not available");
+ else
+ {
+ DBG1(DBG_PTS, "AIK Blob is not available");
+ }
}
/**
@@ -421,7 +407,7 @@ static void load_aik(private_pts_t *this)
cert_path = lib->settings->get_str(lib->settings,
"%s.plugins.imc-attestation.aik_cert", NULL, lib->ns);
key_path = lib->settings->get_str(lib->settings,
- "%s.plugins.imc-attestation.aik_key", NULL, lib->ns);
+ "%s.plugins.imc-attestation.aik_pubkey", NULL, lib->ns);
if (cert_path)
{
@@ -456,37 +442,17 @@ METHOD(pts_t, get_aik, certificate_t*,
}
METHOD(pts_t, set_aik, void,
- private_pts_t *this, certificate_t *aik)
+ private_pts_t *this, certificate_t *aik, int aik_id)
{
DESTROY_IF(this->aik);
this->aik = aik->get_ref(aik);
+ this->aik_id = aik_id;
}
-METHOD(pts_t, get_aik_keyid, bool,
- private_pts_t *this, chunk_t *keyid)
+METHOD(pts_t, get_aik_id, int,
+ private_pts_t *this)
{
- public_key_t *public;
- bool success;
-
- if (!this->aik)
- {
- DBG1(DBG_PTS, "no AIK certificate available");
- return FALSE;
- }
- public = this->aik->get_public_key(this->aik);
- if (!public)
- {
- DBG1(DBG_PTS, "no AIK public key available");
- return FALSE;
- }
- success = public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, keyid);
- if (!success)
- {
- DBG1(DBG_PTS, "no SHA-1 AIK public key info ID available");
- }
- public->destroy(public);
-
- return success;
+ return this->aik_id;
}
METHOD(pts_t, is_path_valid, bool,
@@ -557,6 +523,7 @@ static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
{
this->type = PTS_FILE_FIFO;
}
+#ifndef WIN32
else if (S_ISLNK(st.st_mode))
{
this->type = PTS_FILE_SYM_LINK;
@@ -565,6 +532,7 @@ static bool file_metadata(char *pathname, pts_file_metadata_t **entry)
{
this->type = PTS_FILE_SOCKET;
}
+#endif /* WIN32 */
else
{
this->type = PTS_FILE_OTHER;
@@ -644,7 +612,8 @@ METHOD(pts_t, read_pcr, bool,
TSS_HCONTEXT hContext;
TSS_HTPM hTPM;
TSS_RESULT result;
- chunk_t rgbPcrValue;
+ BYTE *buf;
+ UINT32 len;
bool success = FALSE;
@@ -665,12 +634,12 @@ METHOD(pts_t, read_pcr, bool,
{
goto err;
}
- result = Tspi_TPM_PcrRead(hTPM, pcr_num, (UINT32*)&rgbPcrValue.len, &rgbPcrValue.ptr);
+ result = Tspi_TPM_PcrRead(hTPM, pcr_num, &len, &buf);
if (result != TSS_SUCCESS)
{
goto err;
}
- *pcr_value = chunk_clone(rgbPcrValue);
+ *pcr_value = chunk_clone(chunk_create(buf, len));
DBG3(DBG_PTS, "PCR %d value:%B", pcr_num, pcr_value);
success = TRUE;
@@ -1093,7 +1062,6 @@ METHOD(pts_t, destroy, void,
free(this->initiator_nonce.ptr);
free(this->responder_nonce.ptr);
free(this->secret.ptr);
- free(this->platform_info);
free(this->aik_blob.ptr);
free(this->tpm_version_info.ptr);
free(this);
@@ -1187,13 +1155,13 @@ pts_t *pts_create(bool is_imc)
.get_my_public_value = _get_my_public_value,
.set_peer_public_value = _set_peer_public_value,
.calculate_secret = _calculate_secret,
- .get_platform_info = _get_platform_info,
- .set_platform_info = _set_platform_info,
+ .get_platform_id = _get_platform_id,
+ .set_platform_id = _set_platform_id,
.get_tpm_version_info = _get_tpm_version_info,
.set_tpm_version_info = _set_tpm_version_info,
.get_aik = _get_aik,
.set_aik = _set_aik,
- .get_aik_keyid = _get_aik_keyid,
+ .get_aik_id = _get_aik_id,
.is_path_valid = _is_path_valid,
.get_metadata = _get_metadata,
.read_pcr = _read_pcr,
diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h
index 11154aa38..fead588ae 100644
--- a/src/libpts/pts/pts.h
+++ b/src/libpts/pts/pts.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
+ * Copyright (C) 2012-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -162,19 +163,18 @@ struct pts_t {
bool (*calculate_secret) (pts_t *this);
/**
- * Get Platform and OS Info
+ * Get primary key of platform entry in database
*
* @return Platform and OS info
*/
- char* (*get_platform_info)(pts_t *this);
+ int (*get_platform_id)(pts_t *this);
/**
- * Set Platform and OS Info
+ * Set primary key of platform entry in database
*
- * @param name OS name
- * @param version OS version
+ * @param pid Primary key of platform entry in database
*/
- void (*set_platform_info)(pts_t *this, chunk_t name, chunk_t version);
+ void (*set_platform_id)(pts_t *this, int pid);
/**
* Get TPM 1.2 Version Info
@@ -202,16 +202,16 @@ struct pts_t {
* Set Attestation Identity Certificate or Public Key
*
* @param aik AIK Certificate or Public Key
+ * @param aik_id Primary key referencing AIK in database
*/
- void (*set_aik)(pts_t *this, certificate_t *aik);
+ void (*set_aik)(pts_t *this, certificate_t *aik, int aik_id);
/**
- * Get SHA-1 Attestation Identity Public Key Info ID
+ * Get primary key referencing AIK in database
*
- * @param keyid AIK ID
- * @return TRUE if AIK ID exists
+ * @return Primary key referencing AIK in database
*/
- bool (*get_aik_keyid)(pts_t *this, chunk_t *keyid);
+ int (*get_aik_id)(pts_t *this);
/**
* Check whether path is valid file/directory on filesystem
diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c
index fda644a6a..d7b85c138 100644
--- a/src/libpts/pts/pts_database.c
+++ b/src/libpts/pts/pts_database.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
+ * Copyright (C) 2011-2012 Sansar Choinyambuu
+ * Copyright (C) 2012-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -47,7 +48,7 @@ METHOD(pts_database_t, get_pathname, char*,
private_pts_database_t *this, bool is_dir, int id)
{
enumerator_t *e;
- char *path, *name, *pathname;
+ char *path, *name, *sep, *pathname = NULL;
if (is_dir)
{
@@ -69,11 +70,21 @@ METHOD(pts_database_t, get_pathname, char*,
"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)
+ if (e && e->enumerate(e, &path, &name))
{
- pathname = NULL;
+ if (path[0] == '/')
+ { /* Unix style absolute path */
+ sep = "/";
+ }
+ else
+ { /* Windows absolute path */
+ sep = "\\";
+ }
+ if (asprintf(&pathname, "%s%s%s",
+ path, streq(path, "/") ? "" : sep, name) == -1)
+ {
+ pathname = NULL;
+ }
}
}
DESTROY_IF(e);
@@ -82,7 +93,7 @@ METHOD(pts_database_t, get_pathname, char*,
}
METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
- private_pts_database_t *this, char *product, pts_meas_algorithms_t algo,
+ private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
bool is_dir, int id)
{
enumerator_t *e;
@@ -90,73 +101,34 @@ METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*,
if (is_dir)
{
e = this->db->query(this->db,
- "SELECT f.name, fh.hash FROM file_hashes AS fh "
+ "SELECT f.id, 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 = ? "
+ "WHERE fh.product = ? AND fh.algo = ? AND d.id = ? "
"ORDER BY f.name",
- DB_TEXT, product, DB_INT, algo, DB_INT, id, DB_TEXT, DB_BLOB);
+ DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB);
}
else
{
e = this->db->query(this->db,
- "SELECT f.name, fh.hash FROM file_hashes AS fh "
+ "SELECT f.id, 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);
+ "WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?",
+ DB_INT, pid, DB_INT, algo, DB_INT, id, DB_INT, DB_TEXT, DB_BLOB);
}
return e;
}
-METHOD(pts_database_t, check_aik_keyid, status_t,
- private_pts_database_t *this, chunk_t keyid, int *kid)
-{
- enumerator_t *e;
-
- /* If the AIK is registered get the primary key */
- e = this->db->query(this->db,
- "SELECT id FROM keys WHERE keyid = ?", DB_BLOB, keyid, DB_INT);
- if (!e)
- {
- DBG1(DBG_PTS, "no database query enumerator returned");
- return FAILED;
- }
- if (!e->enumerate(e, kid))
- {
- DBG1(DBG_PTS, "AIK %#B is not registered in database", &keyid);
- e->destroy(e);
- return FAILED;
- }
- e->destroy(e);
-
- return SUCCESS;
-}
-
METHOD(pts_database_t, add_file_measurement, status_t,
- private_pts_database_t *this, char *product, pts_meas_algorithms_t algo,
+ private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
chunk_t measurement, char *filename, bool is_dir, int id)
{
enumerator_t *e;
char *name;
chunk_t hash_value;
- int hash_id, fid, pid = 0;
+ int hash_id, fid;
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? */
@@ -242,18 +214,16 @@ METHOD(pts_database_t, add_file_measurement, status_t,
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)
+METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
+ private_pts_database_t *this, int pid, pts_meas_algorithms_t algo,
+ char *filename)
{
enumerator_t *e;
- chunk_t hash;
- status_t status = NOT_FOUND;
char *dir, *file;
if (strlen(filename) < 1)
{
- return INVALID_ARG;
+ return NULL;
}
/* separate filename into directory and basename components */
@@ -265,84 +235,40 @@ METHOD(pts_database_t, check_file_measurement, status_t,
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.name = ? AND fh.algo = ?",
- DB_TEXT, product, DB_TEXT, file, DB_INT, algo, DB_BLOB);
+ "WHERE fh.product = ? AND f.name = ? AND fh.algo = ?",
+ DB_INT, pid, DB_TEXT, file, DB_INT, algo, DB_BLOB);
}
else
{ /* absolute pathname */
- bool dir_found;
int did;
/* find directory entry first */
e = this->db->query(this->db,
"SELECT id FROM directories WHERE path = ?",
DB_TEXT, dir, DB_INT);
- if (!e)
+
+ if (!e || !e->enumerate(e, &did))
{
- status = FAILED;
goto err;
}
- dir_found = e->enumerate(e, &did);
e->destroy(e);
- if (!dir_found)
- {
- status = NOT_FOUND;
- goto err;
- }
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.dir = ? AND f.name = ? AND fh.algo = ?",
- DB_TEXT, product, DB_INT, did, DB_TEXT, file, DB_INT, algo,
- DB_BLOB);
- }
- if (!e)
- {
- status = FAILED;
- goto err;
+ "WHERE fh.product = ? AND f.dir = ? AND f.name = ? AND fh.algo = ?",
+ DB_INT, pid, DB_INT, did, DB_TEXT, file, DB_INT, algo, DB_BLOB);
}
- 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);
err:
free(file);
free(dir);
- return status;
-}
-
-METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*,
- private_pts_database_t *this, int kid)
-{
- enumerator_t *e;
-
- /* look for all entries belonging to an AIK in the components table */
- e = this->db->query(this->db,
- "SELECT c.vendor_id, c.name, c.qualifier, kc.depth "
- "FROM components AS c "
- "JOIN key_component AS kc ON c.id = kc.component "
- "WHERE kc.key = ? ORDER BY kc.seq_no",
- DB_INT, kid, DB_INT, DB_INT, DB_INT, DB_INT);
return e;
}
METHOD(pts_database_t, check_comp_measurement, status_t,
- private_pts_database_t *this, chunk_t measurement, int cid, int kid,
+ private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
int seq_no, int pcr, pts_meas_algorithms_t algo)
{
enumerator_t *e;
@@ -353,7 +279,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
"SELECT hash FROM component_hashes "
"WHERE component = ? AND key = ? "
"AND seq_no = ? AND pcr = ? AND algo = ? ",
- DB_INT, cid, DB_INT, kid, DB_INT, seq_no,
+ DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no,
DB_INT, pcr, DB_INT, algo, DB_BLOB);
if (!e)
{
@@ -390,7 +316,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t,
}
METHOD(pts_database_t, insert_comp_measurement, status_t,
- private_pts_database_t *this, chunk_t measurement, int cid, int kid,
+ private_pts_database_t *this, chunk_t measurement, int cid, int aik_id,
int seq_no, int pcr, pts_meas_algorithms_t algo)
{
int id;
@@ -399,7 +325,7 @@ METHOD(pts_database_t, insert_comp_measurement, status_t,
"INSERT INTO component_hashes "
"(component, key, seq_no, pcr, algo, hash) "
"VALUES (?, ?, ?, ?, ?, ?)",
- DB_INT, cid, DB_INT, kid, DB_INT, seq_no, DB_INT, pcr,
+ DB_INT, cid, DB_INT, aik_id, DB_INT, seq_no, DB_INT, pcr,
DB_INT, algo, DB_BLOB, measurement) == 1)
{
return SUCCESS;
@@ -410,17 +336,17 @@ METHOD(pts_database_t, insert_comp_measurement, status_t,
}
METHOD(pts_database_t, delete_comp_measurements, int,
- private_pts_database_t *this, int cid, int kid)
+ private_pts_database_t *this, int cid, int aik_id)
{
return this->db->execute(this->db, NULL,
"DELETE FROM component_hashes "
"WHERE component = ? AND key = ?",
- DB_INT, cid, DB_INT, kid);
+ DB_INT, cid, DB_INT, aik_id);
}
METHOD(pts_database_t, get_comp_measurement_count, status_t,
private_pts_database_t *this, pts_comp_func_name_t *comp_name,
- chunk_t keyid, pts_meas_algorithms_t algo, int *cid, int *kid, int *count)
+ int aik_id, pts_meas_algorithms_t algo, int *cid, int *count)
{
enumerator_t *e;
status_t status = SUCCESS;
@@ -428,11 +354,6 @@ METHOD(pts_database_t, get_comp_measurement_count, status_t,
/* Initialize count */
*count = 0;
- if (_check_aik_keyid(this, keyid, kid) != SUCCESS)
- {
- return FAILED;
- }
-
/* Get the primary key of the Component Functional Name */
e = this->db->query(this->db,
"SELECT id FROM components "
@@ -458,7 +379,7 @@ METHOD(pts_database_t, get_comp_measurement_count, status_t,
e = this->db->query(this->db,
"SELECT COUNT(*) FROM component_hashes AS ch "
"WHERE component = ? AND key = ? AND algo = ?",
- DB_INT, *cid, DB_INT, *kid, DB_INT, algo, DB_INT);
+ DB_INT, *cid, DB_INT, aik_id, DB_INT, algo, DB_INT);
if (!e)
{
DBG1(DBG_PTS, "no database query enumerator returned");
@@ -495,11 +416,9 @@ pts_database_t *pts_database_create(imv_database_t *imv_db)
INIT(this,
.public = {
.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,
+ .create_file_meas_enumerator = _create_file_meas_enumerator,
.check_comp_measurement = _check_comp_measurement,
.insert_comp_measurement = _insert_comp_measurement,
.delete_comp_measurements = _delete_comp_measurements,
@@ -511,4 +430,3 @@ pts_database_t *pts_database_create(imv_database_t *imv_db)
return &this->public;
}
-
diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h
index eb8aca346..a6c9fb3b6 100644
--- a/src/libpts/pts/pts_database.h
+++ b/src/libpts/pts/pts_database.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
+ * Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -47,37 +47,20 @@ struct pts_database_t {
/**
* Get stored measurement hash for single file or directory entries
*
- * @param product Software product (os, vpn client, etc.)
+ * @param pid Primary key of software product in database
* @param algo Hash algorithm used for measurement
* @param is_dir TRUE if directory was measured
* @param id Primary key of measured file/directory
* @return Enumerator over all matching measurement hashes
*/
enumerator_t* (*create_file_hash_enumerator)(pts_database_t *this,
- char *product, pts_meas_algorithms_t algo,
+ int pid, pts_meas_algorithms_t algo,
bool is_dir, int id);
/**
- * Check if an AIK given by its keyid is registered in the database
- *
- * @param keyid AIK keyid (SHA-1 hash of the AIK public key info)
- * @param kid Primary key of AIK entry in keys table
- * @return SUCCESS if AIK is present, FAILED otherwise
- */
- status_t (*check_aik_keyid)(pts_database_t *this, chunk_t keyid, int *kid);
-
- /**
- * Get functional components to request evidence of
- *
- * @param kid Primary key of AIK entry in keys table
- * @return Enumerator over all matching components
- */
- 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 pid Primary key of software product in database
* @param algo File measurement hash algorithm used
* @param measurement File measurement hash
* @param filename Optional name of the file to be checked
@@ -85,37 +68,36 @@ struct pts_database_t {
* @param id Primary key into direcories/files table
* @return Status
*/
- status_t (*add_file_measurement)(pts_database_t *this, char *product,
+ status_t (*add_file_measurement)(pts_database_t *this, int pid,
pts_meas_algorithms_t algo,
chunk_t measurement, char *filename,
bool is_dir, int id);
/**
- * Check PTS file measurement against reference stored in database
+ * Get PTS measurement[s] for a given filename stored in database
*
- * @param product Software product (os, vpn client, etc.)
+ * @param pid Primary key of software product in database
* @param algo File measurement hash algorithm used
- * @param measurement File measurement hash
- * @param filename Optional name of the file to be checked
- * @return Status
+ * @param filename Name of the file to be checked
+ * @return Enumerator over all matching measurement hashes
*/
- status_t (*check_file_measurement)(pts_database_t *this, char *product,
- pts_meas_algorithms_t algo,
- chunk_t measurement, char *filename);
+ enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this, int pid,
+ pts_meas_algorithms_t algo,
+ char *filename);
/**
* Check a functional component measurement against value stored in database
*
* @param measurement measurement hash
* @param cid Primary key of Component Functional Name entry
- * @param kid Primary key of AIK entry in keys table
+ * @param aik_id Primary key of AIK entry in database
* @param seq_no Measurement sequence number
* @param prc Number of the PCR the measurement was extended into
* @param algo Hash algorithm used for measurement
* @return SUCCESS if check was successful
*/
status_t (*check_comp_measurement)(pts_database_t *this, chunk_t measurement,
- int cid, int kid, int seq_no, int pcr,
+ int cid, int aik_id, int seq_no, int pcr,
pts_meas_algorithms_t algo);
/**
@@ -123,40 +105,38 @@ struct pts_database_t {
*
* @param measurement Measurement hash
* @param cid Primary key of Component Functional Name entry
- * @param kid Primary key of AIK entry in keys table
+ * @param aik_id Primary key of AIK entry in database
* @param seq_no Measurement sequence number
* @param prc Number of the PCR the measurement was extended into
* @param algo Hash algorithm used for measurement
* @return SUCCESS if INSERT was successful
*/
status_t (*insert_comp_measurement)(pts_database_t *this, chunk_t measurement,
- int cid, int kid, int seq_no, int pcr,
+ int cid, int aik_id, int seq_no, int pcr,
pts_meas_algorithms_t algo);
/**
* Delete functional component measurements from the database
*
* @param cid Primary key of Component Functional Name entry
- * @param kid Primary key of AIK entry in keys table
+ * @param aik_id Primary key of AIK entry in database
* @return number of deleted measurement entries
*/
- int (*delete_comp_measurements)(pts_database_t *this, int cid, int kid);
+ int (*delete_comp_measurements)(pts_database_t *this, int cid, int aik_id);
/**
* Get the number of measurements for a functional component and AIK
*
* @param comp_name Component Functional Name
- * @param keyid SHA-1 hash of AIK public key info
+ * @param aik_id Primary key of AIK entry in database
* @param algo Hash algorithm used for measurement
* @param cid Primary key of Component Functional Name entry
- * @param kid Primary key of AIK entry in keys table
* @param count measurement count
* @return SUCCESS if COUNT was successful
*/
status_t (*get_comp_measurement_count)(pts_database_t *this,
- pts_comp_func_name_t *comp_name, chunk_t keyid,
- pts_meas_algorithms_t algo, int *cid, int *kid,
- int *count);
+ pts_comp_func_name_t *comp_name, int aik_id,
+ pts_meas_algorithms_t algo, int *cid, int *count);
/**
* Destroys a pts_database_t object.
diff --git a/src/libpts/pts/pts_file_meas.c b/src/libpts/pts/pts_file_meas.c
index 77a0957bb..478892aea 100644
--- a/src/libpts/pts/pts_file_meas.c
+++ b/src/libpts/pts/pts_file_meas.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
+ * Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -112,19 +113,43 @@ METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
}
METHOD(pts_file_meas_t, check, bool,
- private_pts_file_meas_t *this, pts_database_t *pts_db, char *product,
+ private_pts_file_meas_t *this, pts_database_t *pts_db, int pid,
pts_meas_algorithms_t algo)
{
- enumerator_t *enumerator;
+ enumerator_t *enumerator, *e;
entry_t *entry;
+ chunk_t hash;
int count_ok = 0, count_not_found = 0, count_differ = 0;
status_t status;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &entry))
{
- status = pts_db->check_file_measurement(pts_db, product, algo,
- entry->measurement, entry->filename);
+ status = NOT_FOUND;
+
+ e = pts_db->create_file_meas_enumerator(pts_db, pid, algo,
+ entry->filename);
+ if (e)
+ {
+ while (e->enumerate(e, &hash))
+ {
+ if (chunk_equals(entry->measurement, hash))
+ {
+ status = SUCCESS;
+ break;
+ }
+ else
+ {
+ status = VERIFY_ERROR;
+ }
+ }
+ e->destroy(e);
+ }
+ else
+ {
+ status = FAILED;
+ }
+
switch (status)
{
case SUCCESS:
@@ -159,47 +184,75 @@ METHOD(pts_file_meas_t, check, bool,
METHOD(pts_file_meas_t, verify, bool,
private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir)
{
+ int fid, fid_last = 0;
char *filename;
chunk_t measurement;
entry_t *entry;
- enumerator_t *enumerator;
- bool found, success = TRUE;
+ enumerator_t *enumerator = NULL;
+ bool found = FALSE, match = FALSE, success = TRUE;
- while (e_hash->enumerate(e_hash, &filename, &measurement))
+ while (e_hash->enumerate(e_hash, &fid, &filename, &measurement))
{
- found = FALSE;
-
- enumerator = this->list->create_enumerator(this->list);
- while (enumerator->enumerate(enumerator, &entry))
+ if (fid != fid_last)
{
- if (!is_dir || streq(filename, entry->filename))
+ if (found && !match)
{
- found = TRUE;
- break;
+ /* no matching hash value found for last filename */
+ success = FALSE;
+ DBG1(DBG_PTS, " %#B for '%s' is incorrect",
+ &entry->measurement, entry->filename);
+ enumerator->destroy(enumerator);
}
- }
- enumerator->destroy(enumerator);
- if (!found)
- {
- DBG1(DBG_PTS, " no measurement found for '%s'", filename);
- success = FALSE;
- continue;
- }
- if (chunk_equals(measurement, entry->measurement))
- {
- DBG2(DBG_PTS, " %#B for '%s' is ok", &measurement, filename);
- }
- else
- {
- DBG1(DBG_PTS, " %#B for '%s' is incorrect", &measurement, filename);
- success = FALSE;
+ /* get a new filename from the database */
+ found = FALSE;
+ match = FALSE;
+ fid_last = fid;
+
+ /**
+ * check if we find an entry for this filename
+ * in the PTS measurement list
+ */
+ enumerator = this->list->create_enumerator(this->list);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (!is_dir || streq(filename, entry->filename))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ /* no PTS measurement returned for this filename */
+ if (!found)
+ {
+ success = FALSE;
+ DBG1(DBG_PTS, " no measurement found for '%s'", filename);
+ enumerator->destroy(enumerator);
+ }
}
- if (!is_dir)
+
+ if (found && !match)
{
- break;
+ if (chunk_equals(measurement, entry->measurement))
+ {
+ match = TRUE;
+ DBG2(DBG_PTS, " %#B for '%s' is ok",
+ &entry->measurement, entry->filename);
+ enumerator->destroy(enumerator);
+ }
}
}
+
+ if (found && !match)
+ {
+ /* no matching hash value found for the very last filename */
+ success = FALSE;
+ DBG1(DBG_PTS, " %#B for '%s' is incorrect",
+ &entry->measurement, entry->filename);
+ enumerator->destroy(enumerator);
+ }
+
return success;
}
diff --git a/src/libpts/pts/pts_file_meas.h b/src/libpts/pts/pts_file_meas.h
index a13bb29ba..4bf28e280 100644
--- a/src/libpts/pts/pts_file_meas.h
+++ b/src/libpts/pts/pts_file_meas.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
+ * Copyright (C) 2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -65,11 +66,11 @@ struct pts_file_meas_t {
* Check PTS File Measurements against reference value in the database
*
* @param db PTS Measurement database
- * @param product Software product (os, vpn client, etc.)
+ * @param pid Primary key of software product in database
* @param algo PTS Measurement algorithm used
* @return TRUE if all measurements agreed
*/
- bool (*check)(pts_file_meas_t *this, pts_database_t *db, char* product,
+ bool (*check)(pts_file_meas_t *this, pts_database_t *db, int pid,
pts_meas_algorithms_t algo);
/**
diff --git a/src/libpts/pts/pts_ima_bios_list.c b/src/libpts/pts/pts_ima_bios_list.c
new file mode 100644
index 000000000..5051b6c2d
--- /dev/null
+++ b/src/libpts/pts/pts_ima_bios_list.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2011-2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "pts_ima_bios_list.h"
+
+#include <utils/debug.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+typedef struct private_pts_ima_bios_list_t private_pts_ima_bios_list_t;
+typedef struct bios_entry_t bios_entry_t;
+typedef enum event_type_t event_type_t;
+
+enum event_type_t {
+ /* BIOS Events (TCG PC Client Specification for Conventional BIOS 1.21) */
+ EV_PREBOOT_CERT = 0x00000000,
+ EV_POST_CODE = 0x00000001,
+ EV_UNUSED = 0x00000002,
+ EV_NO_ACTION = 0x00000003,
+ EV_SEPARATOR = 0x00000004,
+ EV_ACTION = 0x00000005,
+ EV_EVENT_TAG = 0x00000006,
+ EV_S_CRTM_CONTENTS = 0x00000007,
+ EV_S_CRTM_VERSION = 0x00000008,
+ EV_CPU_MICROCODE = 0x00000009,
+ EV_PLATFORM_CONFIG_FLAGS = 0x0000000A,
+ EV_TABLE_OF_DEVICES = 0x0000000B,
+ EV_COMPACT_HASH = 0x0000000C,
+ EV_IPL = 0x0000000D,
+ EV_IPL_PARTITION_DATA = 0x0000000E,
+ EV_NONHOST_CODE = 0x0000000F,
+ EV_NONHOST_CONFIG = 0x00000010,
+ EV_NONHOST_INFO = 0x00000011,
+ EV_OMIT_BOOT_DEVICE_EVENTS = 0x00000012,
+
+ /* EFI Events (TCG EFI Platform Specification 1.22) */
+ EV_EFI_EVENT_BASE = 0x80000000,
+ EV_EFI_VARIABLE_DRIVER_CONFIG = 0x80000001,
+ EV_EFI_VARIABLE_BOOT = 0x80000002,
+ EV_EFI_BOOT_SERVICES_APPLICATION = 0x80000003,
+ EV_EFI_BOOT_SERVICES_DRIVER = 0x80000004,
+ EV_EFI_RUNTIME_SERVICES_DRIVER = 0x80000005,
+ EV_EFI_GPT_EVENT = 0x80000006,
+ EV_EFI_ACTION = 0x80000007,
+ EV_EFI_PLATFORM_FIRMWARE_BLOB = 0x80000008,
+ EV_EFI_HANDOFF_TABLES = 0x80000009,
+
+ EV_EFI_VARIABLE_AUTHORITY = 0x800000E0
+};
+
+ENUM_BEGIN(event_type_names, EV_PREBOOT_CERT, EV_OMIT_BOOT_DEVICE_EVENTS,
+ "Preboot Cert",
+ "POST Code",
+ "Unused",
+ "No Action",
+ "Separator",
+ "Action",
+ "Event Tag",
+ "S-CRTM Contents",
+ "S-CRTM Version",
+ "CPU Microcode",
+ "Platform Config Flags",
+ "Table of Devices",
+ "Compact Hash",
+ "IPL",
+ "IPL Partition Data",
+ "Nonhost Code",
+ "Nonhost Config",
+ "Nonhost Info",
+ "Omit Boot Device Events"
+);
+
+ENUM_NEXT(event_type_names, EV_EFI_EVENT_BASE, EV_EFI_HANDOFF_TABLES,
+ EV_OMIT_BOOT_DEVICE_EVENTS,
+ "EFI Event Base",
+ "EFI Variable Driver Config",
+ "EFI Variable Boot",
+ "EFI Boot Services Application",
+ "EFI Boot Services Driver",
+ "EFI Runtime Services Driver",
+ "EFI GPT Event",
+ "EFI Action",
+ "EFI Platform Firmware Blob",
+ "EFI Handoff Tables"
+);
+ENUM_NEXT(event_type_names, EV_EFI_VARIABLE_AUTHORITY, EV_EFI_VARIABLE_AUTHORITY,
+ EV_EFI_HANDOFF_TABLES,
+ "EFI Variable Authority"
+);
+ENUM_END(event_type_names, EV_EFI_VARIABLE_AUTHORITY);
+
+/**
+ * Private data of a pts_ima_bios_list_t object.
+ *
+ */
+struct private_pts_ima_bios_list_t {
+
+ /**
+ * Public pts_ima_bios_list_t interface.
+ */
+ pts_ima_bios_list_t public;
+
+ /**
+ * List of BIOS measurement entries
+ */
+ linked_list_t *list;
+
+ /**
+ * Time when BIOS measurements were taken
+ */
+ time_t creation_time;
+
+};
+
+/**
+ * Linux IMA BIOS measurement entry
+ */
+struct bios_entry_t {
+
+ /**
+ * PCR register
+ */
+ uint32_t pcr;
+
+ /**
+ * SHA1 measurement hash
+ */
+ chunk_t measurement;
+};
+
+/**
+ * Free a bios_entry_t object
+ */
+static void free_bios_entry(bios_entry_t *this)
+{
+ free(this->measurement.ptr);
+ free(this);
+}
+
+METHOD(pts_ima_bios_list_t, get_time, time_t,
+ private_pts_ima_bios_list_t *this)
+{
+ return this->creation_time;
+}
+
+METHOD(pts_ima_bios_list_t, get_count, int,
+ private_pts_ima_bios_list_t *this)
+{
+ return this->list->get_count(this->list);
+}
+
+METHOD(pts_ima_bios_list_t, get_next, status_t,
+ private_pts_ima_bios_list_t *this, uint32_t *pcr, chunk_t *measurement)
+{
+ bios_entry_t *entry;
+ status_t status;
+
+ status = this->list->remove_first(this->list, (void**)&entry);
+ *pcr = entry->pcr;
+ *measurement = entry->measurement;
+ free(entry);
+
+ return status;
+}
+
+METHOD(pts_ima_bios_list_t, destroy, void,
+ private_pts_ima_bios_list_t *this)
+{
+ this->list->destroy_function(this->list, (void *)free_bios_entry);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_ima_bios_list_t* pts_ima_bios_list_create(char *file)
+{
+ private_pts_ima_bios_list_t *this;
+ uint32_t pcr, event_type, event_len, seek_len;
+ uint32_t buf_len = 2048;
+ uint8_t event_buf[buf_len];
+ chunk_t event;
+ bios_entry_t *entry;
+ struct stat st;
+ ssize_t res;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ {
+ DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
+ return NULL;
+ }
+
+ if (fstat(fd, &st) == -1)
+ {
+ DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
+ strerror(errno));
+ close(fd);
+ return FALSE;
+ }
+
+ INIT(this,
+ .public = {
+ .get_time = _get_time,
+ .get_count = _get_count,
+ .get_next = _get_next,
+ .destroy = _destroy,
+ },
+ .creation_time = st.st_ctime,
+ .list = linked_list_create(),
+ );
+
+ DBG2(DBG_PTS, "PCR Event Type (Size)");
+ while (TRUE)
+ {
+ res = read(fd, &pcr, 4);
+ if (res == 0)
+ {
+ DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
+ file, this->list->get_count(this->list));
+ close(fd);
+ return &this->public;
+ }
+
+ entry = malloc_thing(bios_entry_t);
+ entry->pcr = pcr;
+ entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
+
+ if (res != 4)
+ {
+ break;
+ }
+ if (read(fd, &event_type, 4) != 4)
+ {
+ break;
+ }
+ if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
+ {
+ break;
+ }
+ if (read(fd, &event_len, 4) != 4)
+ {
+ break;
+ }
+ DBG2(DBG_PTS, "%2u %N (%u bytes)", pcr, event_type_names, event_type,
+ event_len);
+
+ seek_len = (event_len > buf_len) ? event_len - buf_len : 0;
+ event_len -= seek_len;
+
+ if (read(fd, event_buf, event_len) != event_len)
+ {
+ break;
+ }
+ event = chunk_create(event_buf, event_len);
+ DBG3(DBG_PTS,"%B", &event);
+
+ if (event_type == EV_ACTION || event_type == EV_EFI_ACTION)
+ {
+ DBG2(DBG_PTS, " '%.*s'", event_len, event_buf);
+ }
+
+ if (seek_len > 0 && lseek(fd, seek_len, SEEK_CUR) == -1)
+ {
+ break;
+ }
+ this->list->insert_last(this->list, entry);
+ }
+
+ DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file,
+ strerror(errno));
+ free_bios_entry(entry);
+ close(fd);
+ destroy(this);
+
+ return NULL;
+}
diff --git a/src/libpts/pts/pts_ima_bios_list.h b/src/libpts/pts/pts_ima_bios_list.h
new file mode 100644
index 000000000..ad162e15a
--- /dev/null
+++ b/src/libpts/pts/pts_ima_bios_list.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup pts_ima_bios_list pts_ima_bios_list
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_IMA_BIOS_LIST_H_
+#define PTS_IMA_BIOS_LIST_H_
+
+#include <time.h>
+
+#include <library.h>
+
+typedef struct pts_ima_bios_list_t pts_ima_bios_list_t;
+
+/**
+ * Class retrieving Linux IMA BIOS measurements
+ *
+ */
+struct pts_ima_bios_list_t {
+
+ /**
+ * Get the time the BIOS measurements were taken
+ *
+ * @return Measurement time
+ */
+ time_t (*get_time)(pts_ima_bios_list_t *this);
+
+ /**
+ * Get the number of non-processed BIOS measurements
+ *
+ * @return Number of measurements left
+ */
+ int (*get_count)(pts_ima_bios_list_t *this);
+
+ /**
+ * Get the next BIOS measurement and remove it from the list
+ *
+ * @param pcr PCR where the measurement was extended into
+ * @param measurement Measurement hash
+ * @return Return code
+ */
+ status_t (*get_next)(pts_ima_bios_list_t *this, uint32_t *pcr,
+ chunk_t *measurement);
+
+ /**
+ * Destroys a pts_ima_bios_list_t object.
+ */
+ void (*destroy)(pts_ima_bios_list_t *this);
+
+};
+
+/**
+ * Create a PTS IMA BIOS measurement object
+ *
+ * @param file Pathname pointing to the BIOS measurements
+ */
+pts_ima_bios_list_t* pts_ima_bios_list_create(char *file);
+
+#endif /** PTS_IMA_BIOS_LIST_H_ @}*/
diff --git a/src/libpts/pts/pts_ima_event_list.c b/src/libpts/pts/pts_ima_event_list.c
new file mode 100644
index 000000000..9bff4654b
--- /dev/null
+++ b/src/libpts/pts/pts_ima_event_list.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2011-2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "pts_ima_event_list.h"
+
+#include <utils/debug.h>
+#include <crypto/hashers/hasher.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+typedef struct private_pts_ima_event_list_t private_pts_ima_event_list_t;
+typedef struct event_entry_t event_entry_t;
+
+#define IMA_TYPE_LEN 3
+#define IMA_NG_TYPE_LEN 6
+#define IMA_TYPE_LEN_MAX 10
+#define IMA_ALGO_DIGEST_LEN_MAX IMA_ALGO_LEN_MAX + HASH_SIZE_SHA512
+
+/**
+ * Private data of a pts_ima_event_list_t object.
+ *
+ */
+struct private_pts_ima_event_list_t {
+
+ /**
+ * Public pts_ima_event_list_t interface.
+ */
+ pts_ima_event_list_t public;
+
+ /**
+ * List of BIOS measurement entries
+ */
+ linked_list_t *list;
+
+ /**
+ * Time when IMA runtime file measurements were taken
+ */
+ time_t creation_time;
+
+};
+
+/**
+ * Linux IMA runtime file measurement entry
+ */
+struct event_entry_t {
+
+ /**
+ * SHA1 measurement hash
+ */
+ chunk_t measurement;
+
+ /**
+ * IMA-NG hash algorithm name or NULL
+ */
+ char *algo;
+
+ /**
+ * IMA-NG eventname or IMA filename
+ */
+ char *name;
+};
+
+/**
+ * Free an ima_event_t object
+ */
+static void free_event_entry(event_entry_t *this)
+{
+ free(this->measurement.ptr);
+ free(this->algo);
+ free(this->name);
+ free(this);
+}
+
+METHOD(pts_ima_event_list_t, get_time, time_t,
+ private_pts_ima_event_list_t *this)
+{
+ return this->creation_time;
+}
+
+METHOD(pts_ima_event_list_t, get_count, int,
+ private_pts_ima_event_list_t *this)
+{
+ return this->list->get_count(this->list);
+}
+
+METHOD(pts_ima_event_list_t, get_next, status_t,
+ private_pts_ima_event_list_t *this, chunk_t *measurement, char **algo,
+ char **name)
+{
+ event_entry_t *entry;
+ status_t status;
+
+ status = this->list->remove_first(this->list, (void**)&entry);
+ *measurement = entry->measurement;
+ *algo = entry->algo;
+ *name = entry->name;
+ free(entry);
+
+ return status;
+}
+
+METHOD(pts_ima_event_list_t, destroy, void,
+ private_pts_ima_event_list_t *this)
+{
+ this->list->destroy_function(this->list, (void *)free_event_entry);
+ free(this);
+}
+
+/**
+ * See header
+ */
+pts_ima_event_list_t* pts_ima_event_list_create(char *file)
+{
+ private_pts_ima_event_list_t *this;
+ event_entry_t *entry;
+ uint32_t pcr, type_len, name_len, eventdata_len, algo_digest_len, algo_len;
+ char type[IMA_TYPE_LEN_MAX];
+ char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
+ char *pos, *error = "";
+ struct stat st;
+ ssize_t res;
+ bool ima_ng;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1)
+ {
+ DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
+ return NULL;
+ }
+
+ if (fstat(fd, &st) == -1)
+ {
+ DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
+ strerror(errno));
+ close(fd);
+ return NULL;
+ }
+
+ INIT(this,
+ .public = {
+ .get_time = _get_time,
+ .get_count = _get_count,
+ .get_next = _get_next,
+ .destroy = _destroy,
+ },
+ .creation_time = st.st_ctime,
+ .list = linked_list_create(),
+ );
+
+ while (TRUE)
+ {
+ /* read 32 bit PCR number in host order */
+ res = read(fd, &pcr, 4);
+
+ /* exit if no more measurement data is available */
+ if (res == 0)
+ {
+ DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
+ file, this->list->get_count(this->list));
+ close(fd);
+ return &this->public;
+ }
+
+ /* create and initialize new IMA entry */
+ entry = malloc_thing(event_entry_t);
+ entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
+ entry->algo = NULL;
+ entry->name = NULL;
+
+ if (res != 4 || pcr != IMA_PCR)
+ {
+ error = "invalid IMA PCR field";
+ break;
+ }
+
+ /* read 20 byte SHA-1 measurement digest */
+ if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
+ {
+ error = "invalid SHA-1 digest field";
+ break;
+ }
+
+ /* read 32 bit length of IMA type string in host order */
+ if (read(fd, &type_len, 4) != 4 || type_len > IMA_TYPE_LEN_MAX)
+ {
+ error = "invalid IMA type field length";
+ break;
+ }
+
+ /* read and interpret IMA type string */
+ if (read(fd, type, type_len) != type_len)
+ {
+ error = "invalid IMA type field";
+ break;
+ }
+ if (type_len == IMA_NG_TYPE_LEN &&
+ memeq(type, "ima-ng", IMA_NG_TYPE_LEN))
+ {
+ ima_ng = TRUE;
+ }
+ else if (type_len == IMA_TYPE_LEN &&
+ memeq(type, "ima", IMA_TYPE_LEN))
+ {
+ ima_ng = FALSE;
+ }
+ else
+ {
+ error = "unknown IMA type";
+ break;
+ }
+
+ if (ima_ng)
+ {
+ /* read the 32 bit length of the event data in host order */
+ if (read(fd, &eventdata_len, 4) != 4 || eventdata_len < 4)
+ {
+ error = "invalid event data field length";
+ break;
+ }
+
+ /* read the 32 bit length of the algo_digest string in host order */
+ if (read(fd, &algo_digest_len, 4) != 4 ||
+ algo_digest_len > IMA_ALGO_DIGEST_LEN_MAX ||
+ eventdata_len < 4 + algo_digest_len + 4)
+ {
+ error = "invalid digest_with_algo field length";
+ break;
+ }
+
+ /* read the IMA algo_digest string */
+ if (read(fd, algo_digest, algo_digest_len) != algo_digest_len)
+ {
+ error = "invalid digest_with_algo field";
+ break;
+ }
+
+ /* extract the hash algorithm name */
+ pos = memchr(algo_digest, '\0', algo_digest_len);
+ if (!pos)
+ {
+ error = "no algo field";
+ break;
+ }
+ algo_len = pos - algo_digest + 1;
+
+ if (algo_len > IMA_ALGO_LEN_MAX ||
+ algo_len < IMA_ALGO_LEN_MIN || *(pos - 1) != ':')
+ {
+ error = "invalid algo field";
+ break;
+ }
+
+ /* copy and store the hash algorithm name */
+ entry->algo = malloc(algo_len);
+ memcpy(entry->algo, algo_digest, algo_len);
+
+ /* read the 32 bit length of the event name in host order */
+ if (read(fd, &name_len, 4) != 4 ||
+ eventdata_len != 4 + algo_digest_len + 4 + name_len)
+ {
+ error = "invalid filename field length";
+ break;
+ }
+
+ /* allocate memory for the file name */
+ entry->name = malloc(name_len);
+
+ /* read file name */
+ if (read(fd, entry->name, name_len) != name_len)
+ {
+ error = "invalid filename field";
+ break;
+ }
+ }
+ else
+ {
+ /* skip SHA-1 digest of the file content */
+ if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1)
+ {
+ break;
+ }
+
+ /* read the 32 bit length of the file name in host order */
+ if (read(fd, &name_len, 4) != 4 || name_len == UINT32_MAX)
+ {
+ error = "invalid filename field length";
+ break;
+ }
+
+ /* allocate memory for the file name */
+ entry->name = malloc(name_len + 1);
+
+ /* read file name */
+ if (read(fd, entry->name, name_len) != name_len)
+ {
+ error = "invalid eventname field";
+ break;
+ }
+
+ /* terminate the file name with a nul character */
+ entry->name[name_len] = '\0';
+ }
+
+ this->list->insert_last(this->list, entry);
+ }
+
+ DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error);
+ free_event_entry(entry);
+ close(fd);
+ destroy(this);
+
+ return NULL;
+}
diff --git a/src/libpts/pts/pts_ima_event_list.h b/src/libpts/pts/pts_ima_event_list.h
new file mode 100644
index 000000000..bf5478a51
--- /dev/null
+++ b/src/libpts/pts/pts_ima_event_list.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup pts_ima_event_list pts_ima_event_list
+ * @{ @ingroup pts
+ */
+
+#ifndef PTS_IMA_EVENT_LIST_H_
+#define PTS_IMA_EVENT_LIST_H_
+
+#include <time.h>
+
+#include <library.h>
+
+typedef struct pts_ima_event_list_t pts_ima_event_list_t;
+
+#define IMA_PCR 10
+#define IMA_ALGO_LEN_MIN 5
+#define IMA_ALGO_LEN_MAX 8
+
+
+/**
+ * Class retrieving Linux IMA file measurements
+ *
+ */
+struct pts_ima_event_list_t {
+
+ /**
+ * Get the time the file measurements were taken
+ *
+ * @return Measurement time
+ */
+ time_t (*get_time)(pts_ima_event_list_t *this);
+
+ /**
+ * Get the number of non-processed file measurements
+ *
+ * @return Number of measurements left
+ */
+ int (*get_count)(pts_ima_event_list_t *this);
+
+ /**
+ * Get the next file measurement and remove it from the list
+ *
+ * @param measurement Measurement hash
+ * @param algo Algorithm used to hash files
+ " @param name Event name (absolute filename or boot_aggregate)
+ * @return Return code
+ */
+ status_t (*get_next)(pts_ima_event_list_t *this, chunk_t *measurement,
+ char **algo, char **name);
+
+ /**
+ * Destroys a pts_ima_event_list_t object.
+ */
+ void (*destroy)(pts_ima_event_list_t *this);
+
+};
+
+/**
+ * Create a PTS IMA runtime file measurement object
+ *
+ * @param file Pathname pointing to the IMA runtme measurements
+ */
+pts_ima_event_list_t* pts_ima_event_list_create(char *file);
+
+#endif /** PTS_IMA_EVENT_LIST_H_ @}*/
diff --git a/src/libpts/pts/pts_meas_algo.c b/src/libpts/pts/pts_meas_algo.c
index 16a66e7b3..c06371123 100644
--- a/src/libpts/pts/pts_meas_algo.c
+++ b/src/libpts/pts/pts_meas_algo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Andreas Steffen
+ * Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,10 +28,7 @@ ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA256, PTS_MEAS_ALGO_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);
+ENUM_END(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1);
/**
* Described in header.
diff --git a/src/libpts/pts/pts_meas_algo.h b/src/libpts/pts/pts_meas_algo.h
index 27cdaea7e..eec7e7981 100644
--- a/src/libpts/pts/pts_meas_algo.h
+++ b/src/libpts/pts/pts_meas_algo.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011 Sansar Choinyambuu
+ * Copyright (C) 2011-2014 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -33,8 +34,7 @@ enum pts_meas_algorithms_t {
PTS_MEAS_ALGO_NONE = 0,
PTS_MEAS_ALGO_SHA384 = (1<<13),
PTS_MEAS_ALGO_SHA256 = (1<<14),
- PTS_MEAS_ALGO_SHA1 = (1<<15),
- PTS_MEAS_ALGO_SHA1_IMA = (1<<16), /* internal use only */
+ PTS_MEAS_ALGO_SHA1 = (1<<15)
};
/**