static int attestation_requester_attest_device_spdm()

in core/attestation/attestation_requester.c [3138:3258]


static int attestation_requester_attest_device_spdm (
	const struct attestation_requester *attestation, uint8_t eid, int device_addr,
	const struct cfm *active_cfm, uint32_t component_id)
{
	const struct device_manager_key *alias_key;
	uint8_t nonce[SPDM_NONCE_LEN];
	int rq_len;
	int status;

	if (!hash_is_alg_supported (attestation->state->txn.transcript_hash_type) ||
		!hash_is_alg_supported (attestation->state->txn.measurement_hash_type)) {
		return ATTESTATION_UNSUPPORTED_ALGORITHM;
	}

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

	// Start off assuming 1.0 then update based on response from device to the Get Version request
	attestation->state->txn.protocol = ATTESTATION_PROTOCOL_DMTF_SPDM;
	attestation->state->txn.spdm_minor_version = ATTESTATION_PROTOCOL_DMTF_SPDM_1_0;

	status = attestation_requester_setup_spdm_device (attestation, eid, device_addr);
	if (status != 0) {
		goto hash_cancel;
	}

	if (attestation->state->txn.cert_supported) {
		rq_len = spdm_generate_get_digests_request (attestation->state->spdm_msg_buffer,
			ATTESTATION_REQUESTER_MAX_SPDM_REQUEST, attestation->state->txn.spdm_minor_version);
		if (ROT_IS_ERROR (rq_len)) {
			status = rq_len;
			goto hash_cancel;
		}

		status = attestation_requester_send_spdm_request_and_get_response (attestation, rq_len,
			device_addr, eid, true, SPDM_REQUEST_GET_DIGESTS);
		if (status != 0) {
			goto hash_cancel;
		}

		// If certificate chain digest retrieved does not match cached certificate, refresh chain
		alias_key = device_manager_get_alias_key (attestation->device_mgr, eid);
		if (alias_key == NULL) {
			status = attestation_requester_verify_and_load_leaf_key_spdm (attestation, device_addr,
				eid, active_cfm, component_id);
			if (status != 0) {
				goto clear_cert_chain;
			}
		}
	}

	/* Perform PMR0 check. If device supports Challenge command, then use that. Otherwise, get all
	 * measurement blocks which make up PMR0 using the Get Measurement command */
	if (attestation->state->txn.challenge_supported) {
		status = attestation->rng->generate_random_buffer (attestation->rng, SPDM_NONCE_LEN, nonce);
		if (status != 0) {
			goto hash_cancel;
		}

		rq_len = spdm_generate_challenge_request (attestation->state->spdm_msg_buffer,
			ATTESTATION_REQUESTER_MAX_SPDM_REQUEST, attestation->state->txn.slot_num,
			SPDM_MEASUREMENT_SUMMARY_HASH_ALL, nonce, attestation->state->txn.spdm_minor_version);
		if (ROT_IS_ERROR (rq_len)) {
			status = rq_len;
			goto hash_cancel;
		}

		status = attestation_requester_send_spdm_request_and_get_response (attestation, rq_len,
			device_addr, eid, true, SPDM_REQUEST_CHALLENGE);
		if (status != 0) {
			goto hash_cancel;
		}

		status = attestation_requester_spdm_process_challenge_response (attestation, eid);
		if (status != 0) {
			goto hash_cancel;
		}

		status = attestation_requester_verify_pmr (attestation, active_cfm, component_id, eid, 0);
		if ((status != 0) && (status != CFM_PMR_DIGEST_NOT_FOUND)) {
			goto hash_cancel;
		}
	}
	else {
		status = attestation_requester_get_and_verify_all_spdm_measurement_blocks (attestation, eid,
			device_addr, active_cfm, component_id);
		if ((status != 0) && (status != CFM_PMR_DIGEST_NOT_FOUND)) {
			goto hash_cancel;
		}
	}

	/* If PMR0 entry exists in CFM, then by getting here device has valid PMR0. Since PMR0 includes
	 * all measurement blocks, we dont have to check rest of the attestation rules. */
	if (status == CFM_PMR_DIGEST_NOT_FOUND) {
		status = attestation_requester_get_and_verify_cfm_contents (attestation, eid, device_addr,
			active_cfm, component_id);
		if (status != 0) {
			goto hash_cancel;
		}
	}

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

	return status;

clear_cert_chain:
	device_manager_clear_alias_key (attestation->device_mgr, eid);
	device_manager_clear_cert_chain_digest (attestation->device_mgr, eid);

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

	return status;
}