static int attestation_requester_send_and_receive_spdm_get_measurements()

in core/attestation/attestation_requester.c [2333:2452]


static int attestation_requester_send_and_receive_spdm_get_measurements (
	const struct attestation_requester *attestation, uint8_t eid, int device_addr,
	uint8_t measurement_operation, bool raw_bitstream_requested)
{
	uint8_t nonce[SPDM_NONCE_LEN];
	int rq_len;
	int status;

	if (!attestation->state->txn.device_discovery) {
		if (!attestation->state->txn.hash_finish) {
			attestation->secondary_hash->cancel (attestation->secondary_hash);
		}

		attestation->state->txn.hash_finish = true;

		status = hash_start_new_hash (attestation->secondary_hash,
			attestation->state->txn.transcript_hash_type);
		if (status != 0) {
			return status;
		}

		attestation->state->txn.hash_finish = false;
	}

	/* In 1.2+, every Get Measurement transaction with a signature requested in response requires a
	 * a transcript that includes VDM. */
	if (((attestation->state->txn.protocol != ATTESTATION_PROTOCOL_CERBERUS) &&
		(attestation->state->txn.spdm_minor_version > ATTESTATION_PROTOCOL_DMTF_SPDM_1_1)) ||
		attestation->state->txn.device_discovery) {
		status = attestation_requester_setup_spdm_device (attestation, eid, device_addr);
		if (status != 0) {
			return status;
		}
	}

	// No signature or nonce needed when getting device ID measurement block in device discovery
	if (!attestation->state->txn.device_discovery) {
		if (attestation->state->txn.cert_supported) {
			status = attestation->rng->generate_random_buffer (attestation->rng, SPDM_NONCE_LEN,
				nonce);
			if (status != 0) {
				return status;
			}
		}

		rq_len = spdm_generate_get_measurements_request (attestation->state->spdm_msg_buffer,
			ATTESTATION_REQUESTER_MAX_SPDM_REQUEST, attestation->state->txn.slot_num,
			measurement_operation, attestation->state->txn.cert_supported ? true : false,
			raw_bitstream_requested, attestation->state->txn.cert_supported ? nonce : NULL,
			attestation->state->txn.spdm_minor_version);
		if (ROT_IS_ERROR (rq_len)) {
			return rq_len;
		}
	}
	else {
		/* SPDM 1.1.x requires all measurement blocks to be contiguous.  This means that device
		 * might not be able to support the dedicated 0xEF block and be compliant, so instead
		 * device IDs are placed in the last measurement block on the device.  Cerberus will first
		 * get the number of measurement blocks, then update measurement_operation to the index of
		 * the last measurement block on the device.  Starting from SPDM 1.2.x, measurement blocks
		 * no longer have the contiguity requirement so instead use index 0xEF which is dedicated to
		 * device IDs. */
		if ((attestation->state->txn.protocol != ATTESTATION_PROTOCOL_CERBERUS) &&
			(attestation->state->txn.spdm_minor_version <= ATTESTATION_PROTOCOL_DMTF_SPDM_1_1)) {
			rq_len = spdm_generate_get_measurements_request (attestation->state->spdm_msg_buffer,
				ATTESTATION_REQUESTER_MAX_SPDM_REQUEST, attestation->state->txn.slot_num,
				SPDM_MEASUREMENT_OPERATION_GET_NUM_BLOCKS, false, raw_bitstream_requested, NULL,
				attestation->state->txn.spdm_minor_version);
			if (ROT_IS_ERROR (rq_len)) {
				return rq_len;
			}

			attestation->state->txn.raw_bitstream_requested = raw_bitstream_requested;
			attestation->state->txn.measurement_operation_requested =
				SPDM_MEASUREMENT_OPERATION_GET_NUM_BLOCKS;

			status = attestation_requester_send_spdm_request_and_get_response (attestation, rq_len,
				device_addr, eid, true, SPDM_REQUEST_GET_MEASUREMENTS);
			if (status != 0) {
				return status;
			}

			status =
				attestation_requester_spdm_process_get_measurements_response (attestation, eid);
			if (status != 0) {
				device_manager_update_device_state_by_eid (attestation->device_mgr, eid,
					DEVICE_MANAGER_ATTESTATION_INVALID_MEASUREMENT);

				return status;
			}

			measurement_operation = attestation->state->txn.msg_buffer[0];
		}

		rq_len = spdm_generate_get_measurements_request (attestation->state->spdm_msg_buffer,
			ATTESTATION_REQUESTER_MAX_SPDM_REQUEST, attestation->state->txn.slot_num,
			measurement_operation, false, raw_bitstream_requested, NULL,
			attestation->state->txn.spdm_minor_version);
		if (ROT_IS_ERROR (rq_len)) {
			return rq_len;
		}
	}

	attestation->state->txn.raw_bitstream_requested = raw_bitstream_requested;
	attestation->state->txn.measurement_operation_requested = measurement_operation;

	status = attestation_requester_send_spdm_request_and_get_response (attestation, rq_len,
		device_addr, eid, true, SPDM_REQUEST_GET_MEASUREMENTS);
	if (status != 0) {
		return status;
	}

	status = attestation_requester_spdm_process_get_measurements_response (attestation, eid);
	if (status != 0) {
		device_manager_update_device_state_by_eid (attestation->device_mgr, eid,
			DEVICE_MANAGER_ATTESTATION_INVALID_MEASUREMENT);
	}

	return status;
}