in core/attestation/pcr.c [1051:1180]
int pcr_hash_measurement_data (struct pcr_bank *pcr, uint8_t measurement_index,
const struct hash_engine *hash, enum hash_type hash_type, uint8_t *buffer, size_t length)
{
const struct pcr_measured_data *measured_data;
int hash_length;
bool include_event;
bool include_version;
int status = 0;
if ((pcr == NULL) || (hash == NULL) || (buffer == NULL)) {
return PCR_INVALID_ARGUMENT;
}
if (measurement_index >= pcr->config.num_measurements) {
return PCR_INVALID_INDEX;
}
hash_length = hash_get_hash_length (hash_type);
if (hash_length == HASH_ENGINE_UNKNOWN_HASH) {
return hash_length;
}
if (length < (size_t) hash_length) {
return PCR_SMALL_OUTPUT_BUFFER;
}
platform_mutex_lock (&pcr->lock);
if (hash_type == pcr->config.measurement_algo) {
/* No need to recalculate the hash since the requested algorithm matches the one used for
* all measurements in the PCR. */
memcpy (buffer, pcr->measurement_list[measurement_index].digest, hash_length);
}
else {
/* Calculate the digest from the raw measured data. */
measured_data = pcr->measurement_list[measurement_index].measured_data;
if (measured_data == NULL) {
/* There is no measured data for this measurement, so it's not possible to calculate the
* hash */
status = PCR_MEASURED_DATA_NOT_AVIALABLE;
goto exit;
}
include_event = pcr->measurement_list[measurement_index].measurement_config &
PCR_MEASUREMENT_FLAG_EVENT;
include_version = pcr->measurement_list[measurement_index].measurement_config &
PCR_MEASUREMENT_FLAG_VERSION;
status = hash_start_new_hash (hash, hash_type);
if (status != 0) {
goto exit;
}
if (include_event) {
status = hash->update (hash,
(uint8_t*) &pcr->measurement_list[measurement_index].event_type, 4);
if (status != 0) {
goto hash_done;
}
}
if (include_version) {
status = hash->update (hash, &pcr->measurement_list[measurement_index].version, 1);
if (status != 0) {
goto hash_done;
}
}
switch (measured_data->type) {
case PCR_DATA_TYPE_1BYTE:
status = hash->update (hash, &measured_data->data.value_1byte, 1);
break;
case PCR_DATA_TYPE_2BYTE:
status = hash->update (hash, (uint8_t*) &measured_data->data.value_2byte, 2);
break;
case PCR_DATA_TYPE_4BYTE:
status = hash->update (hash, (uint8_t*) &measured_data->data.value_4byte, 4);
break;
case PCR_DATA_TYPE_8BYTE:
status = hash->update (hash, (uint8_t*) &measured_data->data.value_8byte, 8);
break;
case PCR_DATA_TYPE_MEMORY:
status = hash->update (hash, measured_data->data.memory.buffer,
measured_data->data.memory.length);
break;
case PCR_DATA_TYPE_FLASH:
status = flash_hash_update_contents (measured_data->data.flash.flash,
measured_data->data.flash.addr, measured_data->data.flash.length, hash);
break;
case PCR_DATA_TYPE_CALLBACK:
if (measured_data->data.callback.hash_data != NULL) {
status =
measured_data->data.callback.hash_data (
measured_data->data.callback.context, hash);
}
else {
status = PCR_MEASURED_DATA_NO_HASH_CALLBACK;
}
break;
default:
status = PCR_INVALID_DATA_TYPE;
break;
}
if (status != 0) {
goto hash_done;
}
status = hash->finish (hash, buffer, length);
}
hash_done:
if (status == 0) {
status = hash_length;
}
else {
hash->cancel (hash);
}
exit:
platform_mutex_unlock (&pcr->lock);
return status;
}