int pcr_get_tcg_log()

in core/attestation/pcr.c [1196:1325]


int pcr_get_tcg_log (struct pcr_bank *pcr, uint32_t pcr_num, size_t offset, uint8_t *buffer,
	size_t length, size_t *total_len)
{
	union {
		struct pcr_tcg_event2_header header;
		struct pcr_tcg_event2_sha256 sha256;
		struct pcr_tcg_event2_sha384 sha384;
		struct pcr_tcg_event2_sha512 sha512;
	} entry;
	size_t num_bytes = 0;
	size_t i = 0;
	uint8_t *entry_digest;
	uint32_t *entry_event_size;
	size_t entry_digest_len;
	size_t entry_total_len;
	uint8_t *entry_ptr = NULL;
	size_t entry_len = 0;
	size_t entry_offset = 0;
	size_t event_size;
	int status = 0;

	if ((pcr == NULL) || (buffer == NULL) || (total_len == NULL)) {
		return PCR_INVALID_ARGUMENT;
	}

	*total_len = 0;

	if (pcr->explicit_measurement) {
		return 0;
	}

	entry.header.pcr_index = pcr_num;
	entry.header.digest_count = 1;

	switch (pcr->config.measurement_algo) {
		default:
		/* This isn't possible, since invalid hash types would be caught during init.
			 * Fall-through to SHA-256.  This is here mostly to keep compilers happy. */
		case HASH_TYPE_SHA256:
			entry.header.digest_algorithm_id = PCR_TCG_SHA256_ALG_ID;
			entry_digest = entry.sha256.digest;
			entry_event_size = &entry.sha256.event_size;
			entry_digest_len = SHA256_HASH_LENGTH;
			entry_total_len = sizeof (entry.sha256);
			break;

#if PCR_MAX_DIGEST_LENGTH >= SHA384_HASH_LENGTH
		case HASH_TYPE_SHA384:
			entry.header.digest_algorithm_id = PCR_TCG_SHA384_ALG_ID;
			entry_digest = entry.sha384.digest;
			entry_event_size = &entry.sha384.event_size;
			entry_digest_len = SHA384_HASH_LENGTH;
			entry_total_len = sizeof (entry.sha384);
			break;
#endif

#if PCR_MAX_DIGEST_LENGTH >= SHA512_HASH_LENGTH
		case HASH_TYPE_SHA512:
			entry.header.digest_algorithm_id = PCR_TCG_SHA512_ALG_ID;
			entry_digest = entry.sha512.digest;
			entry_event_size = &entry.sha512.event_size;
			entry_digest_len = SHA512_HASH_LENGTH;
			entry_total_len = sizeof (entry.sha512);
			break;
#endif
	}

	platform_mutex_lock (&pcr->lock);

	while ((i < pcr->config.num_measurements) && (length > 0)) {
		entry.header.event_type = pcr->measurement_list[i].event_type;

		memcpy (entry_digest, pcr->measurement_list[i].digest, entry_digest_len);

		*total_len += entry_total_len;

		if (offset >= entry_total_len) {
			offset -= entry_total_len;
		}
		else if (length > 0) {
			entry_len = min (entry_total_len - offset, length);
			entry_offset = offset;
			entry_ptr = buffer;

			/* Do not write the entry yet because we don't know the entry size, but update the state
			 * as if it was written to ensure everything ends up in the right place. */
			num_bytes += entry_len;
			buffer += entry_len;
			length -= entry_len;
			offset = 0;
		}

		/* The entry event size is not word-aligned, so use a temp location that is aligned. */
		status = pcr_get_measurement_data_internal (pcr, i, offset, buffer, length, &event_size);
		if (ROT_IS_ERROR (status)) {
			goto exit;
		}

		*entry_event_size = event_size;

		if (entry_ptr != NULL) {
			memcpy (entry_ptr, ((uint8_t*) &entry) + entry_offset, entry_len);
			entry_ptr = NULL;
		}

		*total_len += event_size;
		buffer += status;
		length -= status;

		if (status > 0) {
			offset = 0;
			num_bytes += status;
		}
		else {
			offset -= event_size;
		}

		i++;
	}

exit:
	platform_mutex_unlock (&pcr->lock);

	if (ROT_IS_ERROR (status)) {
		return status;
	}
	else {
		return num_bytes;
	}
}