int pcr_hash_measurement_data()

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;
}