Moved BIOS and IMA measurement lists into classes of their own
This commit is contained in:
@@ -31,6 +31,8 @@ libpts_la_SOURCES = \
|
|||||||
pts/pts_file_meas.h pts/pts_file_meas.c \
|
pts/pts_file_meas.h pts/pts_file_meas.c \
|
||||||
pts/pts_file_meta.h pts/pts_file_meta.c \
|
pts/pts_file_meta.h pts/pts_file_meta.c \
|
||||||
pts/pts_file_type.h pts/pts_file_type.c \
|
pts/pts_file_type.h pts/pts_file_type.c \
|
||||||
|
pts/pts_ima_bios_list.h pts/pts_ima_bios_list.c \
|
||||||
|
pts/pts_ima_event_list.h pts/pts_ima_event_list.c \
|
||||||
pts/pts_meas_algo.h pts/pts_meas_algo.c \
|
pts/pts_meas_algo.h pts/pts_meas_algo.c \
|
||||||
pts/components/pts_component.h \
|
pts/components/pts_component.h \
|
||||||
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
|
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
|
||||||
|
|||||||
@@ -18,33 +18,20 @@
|
|||||||
|
|
||||||
#include "libpts.h"
|
#include "libpts.h"
|
||||||
#include "pts/pts_pcr.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 "pts/components/pts_component.h"
|
||||||
|
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <crypto/hashers/hasher.h>
|
#include <crypto/hashers/hasher.h>
|
||||||
#include <pen/pen.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 SECURITY_DIR "/sys/kernel/security/"
|
||||||
#define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements"
|
#define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements"
|
||||||
#define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements"
|
#define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements"
|
||||||
#define IMA_PCR 10
|
|
||||||
#define IMA_TYPE_LEN 3
|
|
||||||
#define IMA_NG_TYPE_LEN 6
|
|
||||||
#define IMA_TYPE_LEN_MAX 10
|
|
||||||
#define IMA_ALGO_LEN_MIN 5
|
|
||||||
#define IMA_ALGO_LEN_MAX 8
|
|
||||||
#define IMA_ALGO_DIGEST_LEN_MAX IMA_ALGO_LEN_MAX + HASH_SIZE_SHA512
|
|
||||||
#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 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;
|
typedef enum ima_state_t ima_state_t;
|
||||||
|
|
||||||
enum ima_state_t {
|
enum ima_state_t {
|
||||||
@@ -119,12 +106,12 @@ struct pts_ita_comp_ima_t {
|
|||||||
/**
|
/**
|
||||||
* IMA BIOS measurements
|
* IMA BIOS measurements
|
||||||
*/
|
*/
|
||||||
linked_list_t *bios_list;
|
pts_ima_bios_list_t *bios_list;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IMA runtime file measurements
|
* 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
|
* Whether to send pcr_before and pcr_after info
|
||||||
@@ -132,9 +119,9 @@ struct pts_ita_comp_ima_t {
|
|||||||
bool pcr_info;
|
bool pcr_info;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IMA measurement time
|
* Creation time of measurement
|
||||||
*/
|
*/
|
||||||
time_t measurement_time;
|
time_t creation_time;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IMA state machine
|
* IMA state machine
|
||||||
@@ -173,333 +160,6 @@ struct pts_ita_comp_ima_t {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Linux IMA BIOS measurement entry
|
|
||||||
*/
|
|
||||||
struct bios_entry_t {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PCR register
|
|
||||||
*/
|
|
||||||
uint32_t pcr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHA1 measurement hash
|
|
||||||
*/
|
|
||||||
chunk_t measurement;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Linux IMA runtime file measurement entry
|
|
||||||
*/
|
|
||||||
struct ima_entry_t {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHA1 measurement hash
|
|
||||||
*/
|
|
||||||
chunk_t measurement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IMA-NG hash algorithm name or NULL
|
|
||||||
*/
|
|
||||||
char *algo;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IMA-NG eventname or IMA filename
|
|
||||||
*/
|
|
||||||
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->algo);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
uint32_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)
|
|
||||||
{
|
|
||||||
ima_entry_t *entry;
|
|
||||||
uint32_t pcr, type_len, filename_len;
|
|
||||||
uint32_t eventdata_len, algo_digest_len, algo_len;
|
|
||||||
bool ima_ng;
|
|
||||||
char type[IMA_TYPE_LEN_MAX];
|
|
||||||
char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
|
|
||||||
char *pos, *error = "";
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
/* 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, list->get_count(list));
|
|
||||||
close(fd);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create and initialize new IMA entry */
|
|
||||||
entry = malloc_thing(ima_entry_t);
|
|
||||||
entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
|
|
||||||
entry->algo = NULL;
|
|
||||||
entry->filename = 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 = strchr(algo_digest, '\0');
|
|
||||||
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 file name in host order */
|
|
||||||
if (read(fd, &filename_len, 4) != 4 ||
|
|
||||||
eventdata_len != 4 + algo_digest_len + 4 + filename_len)
|
|
||||||
{
|
|
||||||
error = "invalid filename field length";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate memory for the file name */
|
|
||||||
entry->filename = malloc(filename_len);
|
|
||||||
|
|
||||||
/* read file name */
|
|
||||||
if (read(fd, entry->filename, filename_len) != filename_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, &filename_len, 4) != 4)
|
|
||||||
{
|
|
||||||
error = "invalid filename field length";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate memory for the file name */
|
|
||||||
entry->filename = malloc(filename_len + 1);
|
|
||||||
|
|
||||||
/* read file name */
|
|
||||||
if (read(fd, entry->filename, filename_len) != filename_len)
|
|
||||||
{
|
|
||||||
error = "invalid filename field";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* terminate the file name with a nul character */
|
|
||||||
entry->filename[filename_len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
list->insert_last(list, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error);
|
|
||||||
free_ima_entry(entry);
|
|
||||||
close(fd);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend measurement into PCR and create evidence
|
* Extend measurement into PCR and create evidence
|
||||||
*/
|
*/
|
||||||
@@ -531,7 +191,7 @@ static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
|
|||||||
name = this->name->clone(this->name);
|
name = this->name->clone(this->name);
|
||||||
name->set_qualifier(name, qualifier);
|
name->set_qualifier(name, qualifier);
|
||||||
evidence = pts_comp_evidence_create(name, this->depth, pcr, hash_algo,
|
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)
|
if (this->pcr_info)
|
||||||
{
|
{
|
||||||
pcr_after =chunk_clone(pcrs->get(pcrs, pcr));
|
pcr_after =chunk_clone(pcrs->get(pcrs, pcr));
|
||||||
@@ -681,12 +341,12 @@ METHOD(pts_component_t, measure, status_t,
|
|||||||
pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
|
pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
|
||||||
pts_comp_evidence_t **evidence)
|
pts_comp_evidence_t **evidence)
|
||||||
{
|
{
|
||||||
bios_entry_t *bios_entry;
|
|
||||||
ima_entry_t *ima_entry;
|
|
||||||
pts_pcr_t *pcrs;
|
pts_pcr_t *pcrs;
|
||||||
pts_comp_evidence_t *evid = NULL;
|
pts_comp_evidence_t *evid = NULL;
|
||||||
size_t algo_len, name_len;
|
size_t algo_len, name_len;
|
||||||
char *uri;
|
chunk_t measurement;
|
||||||
|
char *uri, *algo, *name;
|
||||||
|
uint32_t pcr;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
pcrs = pts->get_pcrs(pts);
|
pcrs = pts->get_pcrs(pts);
|
||||||
@@ -697,25 +357,25 @@ METHOD(pts_component_t, measure, status_t,
|
|||||||
switch (this->state)
|
switch (this->state)
|
||||||
{
|
{
|
||||||
case IMA_STATE_INIT:
|
case IMA_STATE_INIT:
|
||||||
if (!load_bios_measurements(IMA_BIOS_MEASUREMENTS,
|
this->bios_list = pts_ima_bios_list_create(
|
||||||
this->bios_list, &this->measurement_time))
|
IMA_BIOS_MEASUREMENTS);
|
||||||
|
if (!this->bios_list)
|
||||||
{
|
{
|
||||||
return FAILED;
|
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->bios_count = this->bios_list->get_count(this->bios_list);
|
||||||
this->state = IMA_STATE_BIOS;
|
this->state = IMA_STATE_BIOS;
|
||||||
/* fall through to next state */
|
/* fall through to next state */
|
||||||
case IMA_STATE_BIOS:
|
case IMA_STATE_BIOS:
|
||||||
status = this->bios_list->remove_first(this->bios_list,
|
status = this->bios_list->get_next(this->bios_list, &pcr,
|
||||||
(void**)&bios_entry);
|
&measurement);
|
||||||
if (status != SUCCESS)
|
if (status != SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "could not retrieve bios measurement entry");
|
DBG1(DBG_PTS, "could not retrieve bios measurement entry");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
evid = extend_pcr(this, qualifier, pcrs, bios_entry->pcr,
|
evid = extend_pcr(this, qualifier, pcrs, pcr, measurement);
|
||||||
bios_entry->measurement);
|
|
||||||
free(bios_entry);
|
|
||||||
|
|
||||||
this->state = this->bios_list->get_count(this->bios_list) ?
|
this->state = this->bios_list->get_count(this->bios_list) ?
|
||||||
IMA_STATE_BIOS : IMA_STATE_INIT;
|
IMA_STATE_BIOS : IMA_STATE_INIT;
|
||||||
@@ -730,17 +390,20 @@ METHOD(pts_component_t, measure, status_t,
|
|||||||
switch (this->state)
|
switch (this->state)
|
||||||
{
|
{
|
||||||
case IMA_STATE_INIT:
|
case IMA_STATE_INIT:
|
||||||
if (!load_runtime_measurements(IMA_RUNTIME_MEASUREMENTS,
|
this->ima_list = pts_ima_event_list_create(
|
||||||
this->ima_list, &this->measurement_time))
|
IMA_RUNTIME_MEASUREMENTS);
|
||||||
|
if (!this->ima_list)
|
||||||
{
|
{
|
||||||
return FAILED;
|
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;
|
this->state = IMA_STATE_BOOT_AGGREGATE;
|
||||||
/* fall through to next state */
|
/* fall through to next state */
|
||||||
case IMA_STATE_BOOT_AGGREGATE:
|
case IMA_STATE_BOOT_AGGREGATE:
|
||||||
case IMA_STATE_RUNTIME:
|
case IMA_STATE_RUNTIME:
|
||||||
status = this->ima_list->remove_first(this->ima_list,
|
status = this->ima_list->get_next(this->ima_list, &measurement,
|
||||||
(void**)&ima_entry);
|
&algo, &name);
|
||||||
if (status != SUCCESS)
|
if (status != SUCCESS)
|
||||||
{
|
{
|
||||||
DBG1(DBG_PTS, "could not retrieve ima measurement entry");
|
DBG1(DBG_PTS, "could not retrieve ima measurement entry");
|
||||||
@@ -748,35 +411,33 @@ METHOD(pts_component_t, measure, status_t,
|
|||||||
}
|
}
|
||||||
if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count)
|
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))
|
||||||
ima_entry->algo))
|
|
||||||
{
|
{
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evid = extend_pcr(this, qualifier, pcrs, IMA_PCR,
|
evid = extend_pcr(this, qualifier, pcrs, IMA_PCR,
|
||||||
ima_entry->measurement);
|
measurement);
|
||||||
if (evid)
|
if (evid)
|
||||||
{
|
{
|
||||||
if (ima_entry->algo)
|
if (algo)
|
||||||
{
|
{
|
||||||
algo_len = strlen(ima_entry->algo);
|
algo_len = strlen(algo);
|
||||||
name_len = strlen(ima_entry->filename);
|
name_len = strlen(name);
|
||||||
uri = malloc(algo_len + name_len + 1);
|
uri = malloc(algo_len + name_len + 1);
|
||||||
memcpy(uri, ima_entry->algo, algo_len);
|
memcpy(uri, algo, algo_len);
|
||||||
strcpy(uri + algo_len, ima_entry->filename);
|
strcpy(uri + algo_len, name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uri = strdup(ima_entry->filename);
|
uri = strdup(name);
|
||||||
}
|
}
|
||||||
evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
|
evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
|
||||||
uri);
|
uri);
|
||||||
free(uri);
|
free(uri);
|
||||||
}
|
}
|
||||||
free(ima_entry->filename);
|
free(name);
|
||||||
free(ima_entry->algo);
|
free(algo);
|
||||||
free(ima_entry);
|
|
||||||
|
|
||||||
this->state = this->ima_list->get_count(this->ima_list) ?
|
this->state = this->ima_list->get_count(this->ima_list) ?
|
||||||
IMA_STATE_RUNTIME : IMA_STATE_END;
|
IMA_STATE_RUNTIME : IMA_STATE_END;
|
||||||
@@ -867,14 +528,14 @@ METHOD(pts_component_t, verify, status_t,
|
|||||||
pts_meas_algorithms_t algo;
|
pts_meas_algorithms_t algo;
|
||||||
pts_pcr_transform_t transform;
|
pts_pcr_transform_t transform;
|
||||||
pts_pcr_t *pcrs;
|
pts_pcr_t *pcrs;
|
||||||
time_t measurement_time;
|
time_t creation_time;
|
||||||
chunk_t measurement, pcr_before, pcr_after;
|
chunk_t measurement, pcr_before, pcr_after;
|
||||||
status_t status = NOT_FOUND;
|
status_t status = NOT_FOUND;
|
||||||
|
|
||||||
this->aik_id = pts->get_aik_id(pts);
|
this->aik_id = pts->get_aik_id(pts);
|
||||||
pcrs = pts->get_pcrs(pts);
|
pcrs = pts->get_pcrs(pts);
|
||||||
measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
|
measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
|
||||||
&measurement_time);
|
&creation_time);
|
||||||
|
|
||||||
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
|
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
|
||||||
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
|
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
|
||||||
@@ -1212,10 +873,8 @@ METHOD(pts_component_t, destroy, void,
|
|||||||
DBG1(DBG_PTS, "deleted registered boot aggregate evidence "
|
DBG1(DBG_PTS, "deleted registered boot aggregate evidence "
|
||||||
"measurement");
|
"measurement");
|
||||||
}
|
}
|
||||||
this->bios_list->destroy_function(this->bios_list,
|
DESTROY_IF(this->bios_list);
|
||||||
(void *)free_bios_entry);
|
DESTROY_IF(this->ima_list);
|
||||||
this->ima_list->destroy_function(this->ima_list,
|
|
||||||
(void *)free_ima_entry);
|
|
||||||
this->name->destroy(this->name);
|
this->name->destroy(this->name);
|
||||||
|
|
||||||
free(this);
|
free(this);
|
||||||
@@ -1245,8 +904,6 @@ pts_component_t *pts_ita_comp_ima_create(uint32_t depth,
|
|||||||
PTS_QUALIFIER_UNKNOWN),
|
PTS_QUALIFIER_UNKNOWN),
|
||||||
.depth = depth,
|
.depth = depth,
|
||||||
.pts_db = pts_db,
|
.pts_db = pts_db,
|
||||||
.bios_list = linked_list_create(),
|
|
||||||
.ima_list = linked_list_create(),
|
|
||||||
.pcr_info = lib->settings->get_bool(lib->settings,
|
.pcr_info = lib->settings->get_bool(lib->settings,
|
||||||
"%s.plugins.imc-attestation.pcr_info", TRUE, lib->ns),
|
"%s.plugins.imc-attestation.pcr_info", TRUE, lib->ns),
|
||||||
.ref = 1,
|
.ref = 1,
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, 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 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(),
|
||||||
|
);
|
||||||
|
|
||||||
|
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, &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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -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_ @}*/
|
||||||
@@ -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 = strchr(algo_digest, '\0');
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -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_ @}*/
|
||||||
Reference in New Issue
Block a user