libimcv: Evaluate IMA SHA-256 measurements
This commit is contained in:
parent
839d6c8f80
commit
9b4a2322d6
|
@ -47,3 +47,7 @@ libimcv.plugins.imc-attestation.pcr18_meas =
|
|||
|
||||
libimcv.plugins.imc-attestation.pcr18_after =
|
||||
PCR18 value after measurement.
|
||||
|
||||
libimcv.plugins.imc-attestation.pcr_padding = no
|
||||
Whether to pad IMA SHA1 measurements values when extending into
|
||||
SHA256 PCR bank.
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#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_FILENAME_LEN_MAX 255
|
||||
|
||||
typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
|
||||
typedef enum ima_state_t ima_state_t;
|
||||
|
@ -118,6 +117,11 @@ struct pts_ita_comp_ima_t {
|
|||
*/
|
||||
bool pcr_info;
|
||||
|
||||
/**
|
||||
* Whether to pad PCR measurements if matching hash is not available
|
||||
*/
|
||||
bool pcr_padding;
|
||||
|
||||
/**
|
||||
* Creation time of measurement
|
||||
*/
|
||||
|
@ -165,16 +169,15 @@ struct pts_ita_comp_ima_t {
|
|||
*/
|
||||
static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
|
||||
uint8_t qualifier, pts_pcr_t *pcrs,
|
||||
uint32_t pcr, chunk_t measurement)
|
||||
uint32_t pcr, chunk_t measurement,
|
||||
pts_pcr_transform_t pcr_transform)
|
||||
{
|
||||
pts_pcr_transform_t pcr_transform;
|
||||
pts_meas_algorithms_t pcr_algo;
|
||||
pts_comp_func_name_t *name;
|
||||
pts_comp_evidence_t *evidence;
|
||||
chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty;
|
||||
|
||||
pcr_algo = pcrs->get_pcr_algo(pcrs);
|
||||
pcr_transform = PTS_PCR_TRANSFORM_MATCH;
|
||||
|
||||
if (this->pcr_info)
|
||||
{
|
||||
|
@ -199,24 +202,31 @@ 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
|
||||
* Compute and check boot aggregate value by hashing PCR0 to PCR7
|
||||
*/
|
||||
static bool ima_hash(chunk_t digest, char *ima_algo, char *ima_name,
|
||||
bool little_endian, pts_meas_algorithms_t algo,
|
||||
char *hash_buf)
|
||||
static bool check_boot_aggregate(pts_pcr_t *pcrs, char *algo, bool pcr_padding,
|
||||
chunk_t boot_aggregate, chunk_t measurement)
|
||||
|
||||
{
|
||||
chunk_t ba_measurement;
|
||||
uint8_t meas_buffer[HASH_SIZE_SHA512];
|
||||
size_t hash_size;
|
||||
pts_meas_algorithms_t pcr_algo;
|
||||
hash_algorithm_t hash_alg;
|
||||
hasher_t *hasher;
|
||||
bool success;
|
||||
uint32_t i, pcr_max;
|
||||
bool success, pcr_ok = TRUE;
|
||||
|
||||
hash_alg = pts_meas_algo_to_hash(algo);
|
||||
/* determine PCR hash algorithm and the need for PCR padding */
|
||||
pcr_algo = pcrs->get_pcr_algo(pcrs);
|
||||
if (pcr_algo == PTS_MEAS_ALGO_SHA1)
|
||||
{
|
||||
pcr_padding = FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* create hasher for boot aggregate computation */
|
||||
hash_alg = pts_meas_algo_to_hash(pcr_algo);
|
||||
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
|
||||
if (!hasher)
|
||||
{
|
||||
|
@ -224,90 +234,39 @@ static bool ima_hash(chunk_t digest, char *ima_algo, char *ima_name,
|
|||
hash_algorithm_short_names, hash_alg);
|
||||
return FALSE;
|
||||
}
|
||||
hash_size = hasher->get_hash_size(hasher);
|
||||
|
||||
if (ima_algo)
|
||||
{
|
||||
uint32_t d_len, n_len;
|
||||
chunk_t algo_name, event_name, digest_len, name_len;
|
||||
/* Include PCR8 and PCR9 in boot aggregate with unpadded non-SHA1 hashes */
|
||||
pcr_max = (pcr_algo == PTS_MEAS_ALGO_SHA1 || pcr_padding) ? 7 : 9;
|
||||
|
||||
/* 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,
|
||||
char *algo)
|
||||
{
|
||||
u_char pcr_buffer[HASH_SIZE_SHA1];
|
||||
chunk_t boot_aggregate;
|
||||
hasher_t *hasher;
|
||||
uint32_t i;
|
||||
bool success, pcr_ok = TRUE;
|
||||
|
||||
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 FALSE;
|
||||
}
|
||||
for (i = 0; i < 8 && pcr_ok; i++)
|
||||
/* the boot aggregate hash is computed over PCR0 .. PCR7/PCR9 */
|
||||
for (i = 0; i <= pcr_max && pcr_ok; i++)
|
||||
{
|
||||
pcr_ok = hasher->get_hash(hasher, pcrs->get(pcrs, i), NULL);
|
||||
}
|
||||
if (pcr_ok)
|
||||
{
|
||||
pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer);
|
||||
pcr_ok = hasher->get_hash(hasher, chunk_empty, boot_aggregate.ptr);
|
||||
}
|
||||
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);
|
||||
ba_measurement = chunk_create(meas_buffer, hash_size);
|
||||
if (pcr_padding)
|
||||
{
|
||||
memset(meas_buffer, 0x00, hash_size);
|
||||
pcr_algo = PTS_MEAS_ALGO_SHA1;
|
||||
}
|
||||
pcr_ok = pts_ima_event_hash(boot_aggregate, algo, "boot_aggregate",
|
||||
pcr_algo, meas_buffer);
|
||||
}
|
||||
if (pcr_ok)
|
||||
{
|
||||
success = chunk_equals_const(boot_aggregate, measurement);
|
||||
DBG1(DBG_PTS, "boot aggregate value is %scorrect",
|
||||
success ? "":"in");
|
||||
success = chunk_equals_const(ba_measurement, measurement);
|
||||
DBG1(DBG_PTS, "boot aggregate computed over PCR0..PCR%d is %scorrect",
|
||||
pcr_max, success ? "":"in");
|
||||
return success;
|
||||
}
|
||||
else
|
||||
|
@ -340,9 +299,11 @@ METHOD(pts_component_t, measure, status_t,
|
|||
pts_comp_evidence_t **evidence)
|
||||
{
|
||||
pts_pcr_t *pcrs;
|
||||
pts_meas_algorithms_t pcr_algo;
|
||||
pts_comp_evidence_t *evid = NULL;
|
||||
size_t algo_len, name_len;
|
||||
chunk_t measurement;
|
||||
size_t algo_len, name_len, pcr_size;
|
||||
chunk_t measurement, boot_aggregate;
|
||||
uint8_t pcr_buffer[HASH_SIZE_SHA512];
|
||||
char *uri, *algo, *name;
|
||||
uint32_t pcr;
|
||||
status_t status;
|
||||
|
@ -352,6 +313,8 @@ METHOD(pts_component_t, measure, status_t,
|
|||
{
|
||||
return FAILED;
|
||||
}
|
||||
pcr_algo = pcrs->get_pcr_algo(pcrs);
|
||||
pcr_size = pts_meas_algo_hash_size(pcr_algo);
|
||||
|
||||
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
|
||||
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
|
||||
|
@ -360,8 +323,7 @@ METHOD(pts_component_t, measure, status_t,
|
|||
{
|
||||
case IMA_STATE_INIT:
|
||||
this->bios_list = pts_ima_bios_list_create(pts->get_tpm(pts),
|
||||
IMA_BIOS_MEASUREMENTS,
|
||||
pcrs->get_pcr_algo(pcrs));
|
||||
IMA_BIOS_MEASUREMENTS, pcr_algo);
|
||||
if (!this->bios_list)
|
||||
{
|
||||
return FAILED;
|
||||
|
@ -378,7 +340,8 @@ METHOD(pts_component_t, measure, status_t,
|
|||
DBG1(DBG_PTS, "could not retrieve bios measurement entry");
|
||||
return status;
|
||||
}
|
||||
evid = extend_pcr(this, qualifier, pcrs, pcr, measurement);
|
||||
evid = extend_pcr(this, qualifier, pcrs, pcr, measurement,
|
||||
PTS_PCR_TRANSFORM_MATCH);
|
||||
|
||||
this->state = this->bios_list->get_count(this->bios_list) ?
|
||||
IMA_STATE_BIOS : IMA_STATE_INIT;
|
||||
|
@ -393,8 +356,16 @@ METHOD(pts_component_t, measure, status_t,
|
|||
switch (this->state)
|
||||
{
|
||||
case IMA_STATE_INIT:
|
||||
|
||||
/* disable padding for SHA1 legacy hash */
|
||||
if (pcr_algo == PTS_MEAS_ALGO_SHA1)
|
||||
{
|
||||
this->pcr_padding = FALSE;
|
||||
}
|
||||
|
||||
this->ima_list = pts_ima_event_list_create(
|
||||
IMA_RUNTIME_MEASUREMENTS);
|
||||
IMA_RUNTIME_MEASUREMENTS,
|
||||
pcr_algo, this->pcr_padding);
|
||||
if (!this->ima_list)
|
||||
{
|
||||
return FAILED;
|
||||
|
@ -414,13 +385,17 @@ METHOD(pts_component_t, measure, status_t,
|
|||
}
|
||||
if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count)
|
||||
{
|
||||
if (!check_boot_aggregate(pcrs, measurement, algo))
|
||||
boot_aggregate = chunk_create(pcr_buffer, pcr_size);
|
||||
if (!check_boot_aggregate(pcrs, algo, this->pcr_padding,
|
||||
boot_aggregate, measurement))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
evid = extend_pcr(this, qualifier, pcrs, IMA_PCR,
|
||||
measurement);
|
||||
|
||||
evid = extend_pcr(this, qualifier, pcrs, IMA_PCR, measurement,
|
||||
this->pcr_padding ? PTS_PCR_TRANSFORM_SHORT :
|
||||
PTS_PCR_TRANSFORM_MATCH);
|
||||
if (evid)
|
||||
{
|
||||
if (algo)
|
||||
|
@ -528,7 +503,8 @@ METHOD(pts_component_t, verify, status_t,
|
|||
{
|
||||
bool has_pcr_info;
|
||||
uint32_t pcr;
|
||||
pts_meas_algorithms_t algo;
|
||||
size_t pcr_size;
|
||||
pts_meas_algorithms_t algo, pcr_algo;
|
||||
pts_pcr_transform_t transform;
|
||||
pts_pcr_t *pcrs;
|
||||
time_t creation_time;
|
||||
|
@ -536,13 +512,25 @@ METHOD(pts_component_t, verify, status_t,
|
|||
status_t status = NOT_FOUND;
|
||||
|
||||
this->aik_id = pts->get_aik_id(pts);
|
||||
|
||||
|
||||
pcrs = pts->get_pcrs(pts);
|
||||
if (!pcrs)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
pcr_algo = pcrs->get_pcr_algo(pcrs);
|
||||
pcr_size = pts_meas_algo_hash_size(pcr_algo);
|
||||
|
||||
measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
|
||||
&creation_time);
|
||||
if (algo != pcr_algo)
|
||||
{
|
||||
DBG1(DBG_PTS, "received %N measurement hash but PCR bank is %N",
|
||||
pts_meas_algorithm_names, algo, pts_meas_algorithm_names, algo);
|
||||
return FAILED;
|
||||
}
|
||||
this->pcr_padding = (transform == PTS_PCR_TRANSFORM_SHORT);
|
||||
|
||||
if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
|
||||
PTS_ITA_QUALIFIER_TYPE_TRUSTED))
|
||||
|
@ -606,6 +594,8 @@ METHOD(pts_component_t, verify, status_t,
|
|||
int ima_count;
|
||||
char *ima_algo, *ima_name;
|
||||
char algo_buf[IMA_ALGO_LEN_MAX];
|
||||
uint8_t pcr_buffer[HASH_SIZE_SHA512];
|
||||
chunk_t boot_aggregate;
|
||||
pts_meas_algorithms_t hash_algo;
|
||||
|
||||
hash_algo = parse_validation_uri(evidence, &ima_name, &ima_algo,
|
||||
|
@ -622,15 +612,17 @@ METHOD(pts_component_t, verify, status_t,
|
|||
"but is '%s'", ima_name);
|
||||
return FAILED;
|
||||
}
|
||||
if (hash_algo != PTS_MEAS_ALGO_SHA1)
|
||||
if (hash_algo != pcr_algo)
|
||||
{
|
||||
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, pcr_algo,
|
||||
pts_meas_algorithm_names, hash_algo);
|
||||
return FAILED;
|
||||
}
|
||||
if (!check_boot_aggregate(pcrs, measurement, ima_algo))
|
||||
boot_aggregate = chunk_create(pcr_buffer, pcr_size);
|
||||
if (!check_boot_aggregate(pcrs, ima_algo, this->pcr_padding,
|
||||
boot_aggregate, measurement))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
@ -652,8 +644,8 @@ METHOD(pts_component_t, verify, status_t,
|
|||
DBG1(DBG_PTS, "checking boot aggregate evidence "
|
||||
"measurement");
|
||||
status = this->pts_db->check_comp_measurement(this->pts_db,
|
||||
measurement, this->ima_cid,
|
||||
this->aik_id, 1, pcr, algo);
|
||||
boot_aggregate, this->ima_cid,
|
||||
this->aik_id, 1, pcr, algo);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -661,8 +653,8 @@ METHOD(pts_component_t, verify, status_t,
|
|||
"measurement");
|
||||
this->is_ima_registering = TRUE;
|
||||
status = this->pts_db->insert_comp_measurement(this->pts_db,
|
||||
measurement, this->ima_cid,
|
||||
this->aik_id, 1, pcr, algo);
|
||||
boot_aggregate, this->ima_cid,
|
||||
this->aik_id, 1, pcr, algo);
|
||||
}
|
||||
this->state = IMA_STATE_RUNTIME;
|
||||
|
||||
|
@ -673,20 +665,33 @@ METHOD(pts_component_t, verify, status_t,
|
|||
break;
|
||||
case IMA_STATE_RUNTIME:
|
||||
{
|
||||
uint8_t hash_buf[HASH_SIZE_SHA512];
|
||||
uint8_t digest_buf[HASH_SIZE_SHA512], *hex_digest_buf;
|
||||
chunk_t hex_digest, digest, hash;
|
||||
uint8_t digest_buf[HASH_SIZE_SHA512], *hex_digest_buf;
|
||||
uint8_t hash_buf[HASH_SIZE_SHA512];
|
||||
size_t hash_size;
|
||||
pts_meas_algorithms_t meas_algo;
|
||||
enumerator_t *e;
|
||||
|
||||
this->count++;
|
||||
if (evidence->get_validation(evidence, NULL) !=
|
||||
PTS_COMP_EVID_VALIDATION_PASSED)
|
||||
PTS_COMP_EVID_VALIDATION_PASSED)
|
||||
{
|
||||
DBG1(DBG_PTS, "evidence validation failed");
|
||||
this->count_failed++;
|
||||
return FAILED;
|
||||
}
|
||||
hash = chunk_create(hash_buf, pts_meas_algo_hash_size(algo));
|
||||
hash_size = pts_meas_algo_hash_size(algo);
|
||||
hash = chunk_create(hash_buf, hash_size);
|
||||
|
||||
if (this->pcr_padding)
|
||||
{
|
||||
memset(hash_buf, 0x00, hash_size);
|
||||
meas_algo = PTS_MEAS_ALGO_SHA1;
|
||||
}
|
||||
else
|
||||
{
|
||||
meas_algo = algo;
|
||||
}
|
||||
|
||||
e = this->pts_db->create_file_meas_enumerator(this->pts_db,
|
||||
pts->get_platform_id(pts),
|
||||
|
@ -697,8 +702,9 @@ METHOD(pts_component_t, verify, status_t,
|
|||
{
|
||||
hex_digest = chunk_from_str(hex_digest_buf);
|
||||
digest = chunk_from_hex(hex_digest, digest_buf);
|
||||
if (!ima_hash(digest, ima_algo, ima_name,
|
||||
FALSE, algo, hash_buf))
|
||||
|
||||
if (!pts_ima_event_hash(digest, ima_algo, ima_name,
|
||||
meas_algo, hash_buf))
|
||||
{
|
||||
status = FAILED;
|
||||
break;
|
||||
|
@ -916,6 +922,8 @@ pts_component_t *pts_ita_comp_ima_create(uint32_t depth,
|
|||
.pts_db = pts_db,
|
||||
.pcr_info = lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.imc-attestation.pcr_info", FALSE, lib->ns),
|
||||
.pcr_padding = lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.imc-attestation.pcr_padding", FALSE, lib->ns),
|
||||
.ref = 1,
|
||||
);
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@ typedef struct event_entry_t event_entry_t;
|
|||
#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
|
||||
#define IMA_FILENAME_LEN_MAX 255
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Private data of a pts_ima_event_list_t object.
|
||||
|
@ -61,7 +64,7 @@ struct private_pts_ima_event_list_t {
|
|||
struct event_entry_t {
|
||||
|
||||
/**
|
||||
* SHA1 measurement hash
|
||||
* Special IMA measurement hash
|
||||
*/
|
||||
chunk_t measurement;
|
||||
|
||||
|
@ -125,11 +128,14 @@ METHOD(pts_ima_event_list_t, destroy, void,
|
|||
/**
|
||||
* See header
|
||||
*/
|
||||
pts_ima_event_list_t* pts_ima_event_list_create(char *file)
|
||||
pts_ima_event_list_t* pts_ima_event_list_create(char *file,
|
||||
pts_meas_algorithms_t pcr_algo, bool pcr_padding)
|
||||
{
|
||||
private_pts_ima_event_list_t *this;
|
||||
event_entry_t *entry;
|
||||
chunk_t digest;
|
||||
uint32_t pcr, type_len, name_len, eventdata_len, algo_digest_len, algo_len;
|
||||
size_t hash_size;
|
||||
char type[IMA_TYPE_LEN_MAX];
|
||||
char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
|
||||
char *pos, *error = "";
|
||||
|
@ -164,6 +170,8 @@ pts_ima_event_list_t* pts_ima_event_list_create(char *file)
|
|||
.list = linked_list_create(),
|
||||
);
|
||||
|
||||
hash_size = pts_meas_algo_hash_size(pcr_algo);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
/* read 32 bit PCR number in host order */
|
||||
|
@ -175,12 +183,13 @@ pts_ima_event_list_t* pts_ima_event_list_create(char *file)
|
|||
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->measurement = chunk_alloc(hash_size);
|
||||
entry->algo = NULL;
|
||||
entry->name = NULL;
|
||||
|
||||
|
@ -190,7 +199,12 @@ pts_ima_event_list_t* pts_ima_event_list_create(char *file)
|
|||
break;
|
||||
}
|
||||
|
||||
/* read 20 byte SHA-1 measurement digest */
|
||||
if (pcr_padding)
|
||||
{
|
||||
memset(entry->measurement.ptr, 0x00, hash_size);
|
||||
}
|
||||
|
||||
/* read 20 byte SHA-1 IMA measurement digest */
|
||||
if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
|
||||
{
|
||||
error = "invalid SHA-1 digest field";
|
||||
|
@ -271,6 +285,9 @@ pts_ima_event_list_t* pts_ima_event_list_create(char *file)
|
|||
entry->algo = malloc(algo_len);
|
||||
memcpy(entry->algo, algo_digest, algo_len);
|
||||
|
||||
/* extract the digest */
|
||||
digest = chunk_create(pos + 1, algo_digest_len - 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)
|
||||
|
@ -288,6 +305,17 @@ pts_ima_event_list_t* pts_ima_event_list_create(char *file)
|
|||
error = "invalid filename field";
|
||||
break;
|
||||
}
|
||||
|
||||
/* re-compute IMA measurement digest for non-SHA1 hash algorithms */
|
||||
if (pcr_algo != PTS_MEAS_ALGO_SHA1 && !pcr_padding)
|
||||
{
|
||||
if (!pts_ima_event_hash(digest, entry->algo, entry->name,
|
||||
pcr_algo, entry->measurement.ptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -328,3 +356,61 @@ pts_ima_event_list_t* pts_ima_event_list_create(char *file)
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
bool pts_ima_event_hash(chunk_t digest, char *ima_algo, char *ima_name,
|
||||
pts_meas_algorithms_t pcr_algo, char *hash_buf)
|
||||
{
|
||||
hash_algorithm_t hash_alg;
|
||||
hasher_t *hasher;
|
||||
bool success;
|
||||
|
||||
hash_alg = pts_meas_algo_to_hash(pcr_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 ad_len, n_len;
|
||||
chunk_t algo_name, event_name, algo_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);
|
||||
|
||||
ad_len = htole32(algo_name.len + digest.len);
|
||||
algo_digest_len = chunk_create((uint8_t*)&ad_len, sizeof(ad_len));
|
||||
|
||||
n_len = htole32(event_name.len);
|
||||
name_len = chunk_create((uint8_t*)&n_len, sizeof(n_len));
|
||||
|
||||
success = hasher->get_hash(hasher, algo_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;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#ifndef PTS_IMA_EVENT_LIST_H_
|
||||
#define PTS_IMA_EVENT_LIST_H_
|
||||
|
||||
#include "pts_meas_algo.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <library.h>
|
||||
|
@ -56,7 +58,7 @@ struct pts_ima_event_list_t {
|
|||
* Get the next file measurement and remove it from the list
|
||||
*
|
||||
* @param measurement Measurement hash
|
||||
* @param algo Algorithm used to hash files
|
||||
* @param algo Algorithm used to compute file digests
|
||||
" @param name Event name (absolute filename or boot_aggregate)
|
||||
* @return Return code
|
||||
*/
|
||||
|
@ -74,7 +76,23 @@ struct pts_ima_event_list_t {
|
|||
* Create a PTS IMA runtime file measurement object
|
||||
*
|
||||
* @param file Pathname pointing to the IMA runtime measurements
|
||||
* @param pcr_algo PCR hash measurement algorithm to be used
|
||||
* @param pcr_padding Apply PCR hash padding if hash algorithm is lacking
|
||||
*/
|
||||
pts_ima_event_list_t* pts_ima_event_list_create(char *file);
|
||||
pts_ima_event_list_t* pts_ima_event_list_create(char *file,
|
||||
pts_meas_algorithms_t pcr_algo, bool pcr_padding);
|
||||
|
||||
/**
|
||||
* Generate an IMA or IMA-NG hash from an event digest and event name
|
||||
*
|
||||
* @param digest event digest
|
||||
* @param ima_algo event digest algorithm string ("sha1:", "sha256:", etc.)
|
||||
* @param ima_name event name
|
||||
* @param pcr_algo hash algorithm used by TPM PCR extension
|
||||
* @param hash_buf hash value to be compared with TPM measurement
|
||||
* @return TRUE if computation successful
|
||||
*/
|
||||
bool pts_ima_event_hash(chunk_t digest, char *ima_algo, char *ima_name,
|
||||
pts_meas_algorithms_t pcr_algo, char *hash_buf);
|
||||
|
||||
#endif /** PTS_IMA_EVENT_LIST_H_ @}*/
|
||||
|
|
Loading…
Reference in New Issue