#include "ita_comp_func_name.h"
#include "libpts.h"
+#include "pts/pts_pcr.h"
#include "pts/components/pts_component.h"
#include <debug.h>
#define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements"
#define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements"
#define IMA_MEASUREMENT_BATCH_SIZE 200
-#define IMA_EVENT_NAME_LEN_MAX 255
#define IMA_PCR 10
-#define IMA_PCR_MAX 16
#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;
linked_list_t *ima_list;
/**
- * Shadow PCR registers
+ * Shadow PCR set
*/
- chunk_t pcrs[IMA_PCR_MAX];
+ pts_pcr_t *pcrs;
+
+ /**
+ * Whether to send pcr_before and pcr_after info
+ */
+ bool pcr_info;
/**
* IMA measurement time
* IMA state machine
*/
ima_state_t state;
-
- /**
- * Hasher used to extend emulated PCRs
- */
- hasher_t *hasher;
-
};
/**
/**
* Extend measurement into PCR an create evidence
*/
-pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, u_int32_t pcr,
- chunk_t measurement)
+static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, 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_evidence_t *evidence;
- chunk_t pcr_before, pcr_after;
+ 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);
- pcr_before = chunk_clone(this->pcrs[pcr]);
- if (!this->hasher->get_hash(this->hasher, pcr_before, NULL) ||
- !this->hasher->get_hash(this->hasher, measurement, this->pcrs[pcr].ptr))
+
+ if (this->pcr_info)
{
- DBG1(DBG_PTS, "PCR%d was not extended due to a hasher problem", pcr);
+ pcr_before = chunk_clone(this->pcrs->get(this->pcrs, pcr));
+ }
+ pcr_after = this->pcrs->extend(this->pcrs, pcr, measurement);
+ if (!pcr_after.ptr)
+ {
+ free(pcr_before.ptr);
+ return NULL;
}
- pcr_after = chunk_clone(this->pcrs[pcr]);
-
evidence = pts_comp_evidence_create(this->name->clone(this->name),
this->depth, pcr, hash_algo, pcr_transform,
this->measurement_time, measurement);
- evidence->set_pcr_info(evidence, pcr_before, pcr_after);
-
+ if (this->pcr_info)
+ {
+ pcr_after =chunk_clone(this->pcrs->get(this->pcrs, pcr));
+ evidence->set_pcr_info(evidence, pcr_before, pcr_after);
+ }
return evidence;
}
/**
* Compute and check boot aggregate value by hashing PCR0 to PCR7
*/
-void check_boot_aggregate(pts_ita_comp_ima_t *this, chunk_t measurement)
+static void check_boot_aggregate(pts_ita_comp_ima_t *this, chunk_t measurement)
{
- u_int32_t pcr;
+ u_int32_t i;
+ u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
u_char pcr_buffer[HASH_SIZE_SHA1];
- u_char boot_aggregate_name[] = "boot_aggregate";
- u_char filename_buffer[IMA_EVENT_NAME_LEN_MAX + 1];
- chunk_t boot_aggregate, file_name;
+ chunk_t file_name, boot_aggregate;
+ hasher_t *hasher;
bool pcr_ok = TRUE;
- /* See Linux kernel header: security/integrity/ima/ima.h */
- boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer));
- memset(filename_buffer, 0, sizeof(filename_buffer));
- strcpy(filename_buffer, boot_aggregate_name);
- file_name = chunk_create(filename_buffer, sizeof(filename_buffer));
+ 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);
+ }
+ for (i = 0; i < 8 && pcr_ok; i++)
+ {
+ pcr_ok = hasher->get_hash(hasher, this->pcrs->get(this->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);
- for (pcr = 0; pcr < 8 && pcr_ok; pcr++)
+ if (pcr_ok)
{
- pcr_ok = this->hasher->get_hash(this->hasher, this->pcrs[pcr], NULL);
+ DBG1(DBG_PTS, "boot aggregate value is %scorrect",
+ chunk_equals(boot_aggregate, measurement) ? "":"in");
}
- if (!pcr_ok ||
- !this->hasher->get_hash(this->hasher, chunk_empty, pcr_buffer) ||
- !this->hasher->get_hash(this->hasher, boot_aggregate, NULL) ||
- !this->hasher->get_hash(this->hasher, file_name, pcr_buffer))
+ else
{
DBG1(DBG_PTS, "failed to compute boot aggregate value");
- return;
}
- DBG1(DBG_PTS, "boot aggregate value is %scorrect",
- chunk_equals(boot_aggregate, measurement) ? "":"in");
}
METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
*evidence = extend_pcr(this, bios_entry->pcr,
bios_entry->measurement);
free(bios_entry);
+ if (!evidence)
+ {
+ return FAILED;
+ }
/* break if still some BIOS measurements are left */
if (this->bios_list->get_count(this->bios_list))
free(ima_entry->file_measurement.ptr);
free(ima_entry->filename);
free(ima_entry);
+
+ if (!evidence)
+ {
+ return FAILED;
+ }
this->state = this->ima_list->get_count(this->ima_list) ?
IMA_STATE_RUNTIME : IMA_STATE_END;
break;
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)
{
count = this->pts_db->delete_comp_measurements(this->pts_db,
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);
- this->hasher->destroy(this->hasher);
+ this->pcrs->destroy(this->pcrs);
free(this->keyid.ptr);
free(this);
}
pts_database_t *pts_db)
{
pts_ita_comp_ima_t *this;
- int i;
+ 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 = {
.bios_list = linked_list_create(),
.ima_list = linked_list_create(),
.ima_count = IMA_MEASUREMENT_BATCH_SIZE - 1,
- .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1),
+ .pcrs = pcrs,
+ .pcr_info = lib->settings->get_bool(lib->settings,
+ "libimcv.plugins.imc-attestation.pcr_info", TRUE),
);
- 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;
}
--- /dev/null
+/*
+ * 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 <debug.h>
+
+/**
+ * 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_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[PCR_MAX_NUM];
+
+ /**
+ * Hasher used to extend shadow PCRs
+ */
+ hasher_t *hasher;
+
+};
+
+METHOD(pts_pcr_t, get, chunk_t,
+ private_pts_pcr_t *this, u_int32_t pcr)
+{
+ return (pcr < PCR_MAX_NUM) ? this->pcrs[pcr] : chunk_empty;
+}
+
+METHOD(pts_pcr_t, set, void,
+ private_pts_pcr_t *this, u_int32_t pcr, chunk_t value)
+{
+ if (pcr < PCR_MAX_NUM && value.len == PCR_LEN)
+ {
+ memcpy(this->pcrs[pcr].ptr, value.ptr, PCR_LEN);
+ }
+}
+
+METHOD(pts_pcr_t, extend, chunk_t,
+ private_pts_pcr_t *this, u_int32_t pcr, chunk_t measurement)
+{
+ if (pcr >= PCR_MAX_NUM || measurement.len != PCR_LEN)
+ {
+ DBG1(DBG_PTS, "PCR%d does not exist or has the wrong size", 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%d was not extended due to a hasher problem", pcr);
+ return chunk_empty;
+ }
+ return this->pcrs[pcr];
+}
+
+METHOD(pts_pcr_t, destroy, void,
+ private_pts_pcr_t *this)
+{
+ u_int32_t i;
+
+ for (i = 0; i < 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 = _get,
+ .set = _set,
+ .extend = _extend,
+ .destroy = _destroy,
+ },
+ .hasher = hasher,
+ );
+
+ for (i = 0; i < PCR_MAX_NUM; i++)
+ {
+ this->pcrs[i] = chunk_alloc(PCR_LEN);
+ memset(this->pcrs[i].ptr, 0x00, PCR_LEN);
+ }
+
+ return &this->public;
+}
+
--- /dev/null
+/*
+ * 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>
+
+/**
+ * Class implementing a shadow PCR register set
+ */
+struct pts_pcr_t {
+
+ /**
+ * 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
+ */
+ void (*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);
+
+ /**
+ * 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_ @}*/