diff --git a/src/libpts/Makefile.am b/src/libpts/Makefile.am index 3ff941794..8137493ab 100644 --- a/src/libpts/Makefile.am +++ b/src/libpts/Makefile.am @@ -9,6 +9,7 @@ libpts_la_SOURCES = \ libpts.h libpts.c \ pts/pts.h pts/pts.c \ pts/pts_error.h pts/pts_error.c \ + pts/pts_pcr.h pts/pts_pcr.c \ pts/pts_proto_caps.h \ pts/pts_req_func_comp_evid.h \ pts/pts_simple_evid_final.h \ diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c index 576b9de15..b687c0f8e 100644 --- a/src/libpts/pts/components/ita/ita_comp_ima.c +++ b/src/libpts/pts/components/ita/ita_comp_ima.c @@ -17,6 +17,7 @@ #include "ita_comp_func_name.h" #include "libpts.h" +#include "pts/pts_pcr.h" #include "pts/components/pts_component.h" #include @@ -32,10 +33,9 @@ #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; @@ -122,9 +122,14 @@ struct pts_ita_comp_ima_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 @@ -135,12 +140,6 @@ struct pts_ita_comp_ima_t { * IMA state machine */ ima_state_t state; - - /** - * Hasher used to extend emulated PCRs - */ - hasher_t *hasher; - }; /** @@ -362,66 +361,84 @@ static bool load_runtime_measurements(char *file, linked_list_t *list, /** * 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)) - { - DBG1(DBG_PTS, "PCR%d was not extended due to a hasher problem", pcr); - } - pcr_after = chunk_clone(this->pcrs[pcr]); + if (this->pcr_info) + { + 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; + } 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)); - - for (pcr = 0; pcr < 8 && pcr_ok; pcr++) + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) { - pcr_ok = this->hasher->get_hash(this->hasher, this->pcrs[pcr], NULL); + DBG1(DBG_PTS, "%N hasher could not be created", + hash_algorithm_short_names, HASH_SHA1); } - 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)) + 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); + + if (pcr_ok) + { + DBG1(DBG_PTS, "boot aggregate value is %scorrect", + chunk_equals(boot_aggregate, measurement) ? "":"in"); + } + 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*, @@ -476,6 +493,10 @@ METHOD(pts_component_t, measure, status_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)) @@ -534,6 +555,11 @@ METHOD(pts_component_t, measure, status_t, 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; @@ -680,14 +706,10 @@ METHOD(pts_component_t, finalize, bool, 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, @@ -701,7 +723,7 @@ METHOD(pts_component_t, destroy, void, 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); } @@ -713,7 +735,14 @@ pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth, 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 = { @@ -732,14 +761,11 @@ pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth, .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; } diff --git a/src/libpts/pts/pts_pcr.c b/src/libpts/pts/pts_pcr.c new file mode 100644 index 000000000..c21e585e7 --- /dev/null +++ b/src/libpts/pts/pts_pcr.c @@ -0,0 +1,135 @@ +/* + * 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 . + * + * 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 + +/** + * 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; +} + diff --git a/src/libpts/pts/pts_pcr.h b/src/libpts/pts/pts_pcr.h new file mode 100644 index 000000000..43a85dbe9 --- /dev/null +++ b/src/libpts/pts/pts_pcr.h @@ -0,0 +1,70 @@ +/* + * 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 . + * + * 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 + +/** + * 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_ @}*/