created a pts_pcr class for PCR computations
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 20 Jul 2012 12:57:28 +0000 (14:57 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 20 Jul 2012 12:57:28 +0000 (14:57 +0200)
src/libpts/Makefile.am
src/libpts/pts/components/ita/ita_comp_ima.c
src/libpts/pts/pts_pcr.c [new file with mode: 0644]
src/libpts/pts/pts_pcr.h [new file with mode: 0644]

index 3ff9417..8137493 100644 (file)
@@ -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 \
index 576b9de..b687c0f 100644 (file)
@@ -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 <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;
@@ -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))
+
+       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*,
@@ -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 (file)
index 0000000..c21e585
--- /dev/null
@@ -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 <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;
+}
+
diff --git a/src/libpts/pts/pts_pcr.h b/src/libpts/pts/pts_pcr.h
new file mode 100644 (file)
index 0000000..43a85db
--- /dev/null
@@ -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 <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_ @}*/