diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2014-07-11 07:23:31 +0200 |
commit | 81c63b0eed39432878f78727f60a1e7499645199 (patch) | |
tree | 82387d8fecd1c20788fd8bd784a9b0bde091fb6b /src/libpts/pts/components | |
parent | c5ebfc7b9c16551fe825dc1d79c3f7e2f096f6c9 (diff) | |
download | vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.tar.gz vyos-strongswan-81c63b0eed39432878f78727f60a1e7499645199.zip |
Imported Upstream version 5.2.0
Diffstat (limited to 'src/libpts/pts/components')
-rw-r--r-- | src/libpts/pts/components/ita/ita_comp_ima.c | 694 | ||||
-rw-r--r-- | src/libpts/pts/components/ita/ita_comp_tboot.c | 95 | ||||
-rw-r--r-- | src/libpts/pts/components/ita/ita_comp_tgrub.c | 7 | ||||
-rw-r--r-- | src/libpts/pts/components/pts_component.h | 5 |
4 files changed, 372 insertions, 429 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 |