static int attestation_requester_attest_device_cerberus_protocol()

in core/attestation/attestation_requester.c [1967:2100]


static int attestation_requester_attest_device_cerberus_protocol (
	const struct attestation_requester *attestation, uint8_t eid, int device_addr,
	const struct cfm *active_cfm, uint32_t component_id)
{
	struct cerberus_protocol_challenge *challenge_rq =
		(struct cerberus_protocol_challenge*) attestation->state->txn.msg_buffer;
	struct cerberus_protocol_challenge_response *challenge_rsp =
		(struct cerberus_protocol_challenge_response*) attestation->state->txn.msg_buffer;
	const struct device_manager_key *alias_key;
	uint8_t digest[SHA256_HASH_LENGTH];
	int challenge_rq_len;
	int status;

	attestation->state->txn.protocol = ATTESTATION_PROTOCOL_CERBERUS;

	// TODO Get Cerberus Protocol version using the MCTP control Get VDM Support command

	status = cerberus_protocol_generate_get_device_capabilities_request (attestation->device_mgr,
		attestation->state->txn.msg_buffer, sizeof (attestation->state->txn.msg_buffer));
	if (ROT_IS_ERROR (status)) {
		return status;
	}

	status = attestation_requester_send_request_and_get_response (attestation, status, device_addr,
		eid, false, false, CERBERUS_PROTOCOL_GET_DEVICE_CAPABILITIES);
	if (status != 0) {
		return status;
	}

	status =
		cerberus_protocol_generate_get_certificate_digest_request (attestation->state->txn.slot_num,
		ATTESTATION_ECDHE_KEY_EXCHANGE, attestation->state->txn.msg_buffer,
		sizeof (attestation->state->txn.msg_buffer));
	if (ROT_IS_ERROR (status)) {
		return status;
	}

	status = attestation_requester_send_request_and_get_response (attestation, status, device_addr,
		eid, true, false, CERBERUS_PROTOCOL_GET_DIGEST);
	if (status != 0) {
		return status;
	}

	status = attestation->primary_hash->calculate_sha256 (attestation->primary_hash,
		attestation->state->txn.msg_buffer, attestation->state->txn.msg_buffer_len, digest,
		sizeof (digest));
	if (status != 0) {
		return status;
	}

	status = attestation_requester_update_cert_chain_digest (attestation, eid, digest,
		SHA256_HASH_LENGTH);
	if (status != 0) {
		return status;
	}

	attestation->state->txn.num_certs = attestation->state->txn.msg_buffer_len / SHA256_HASH_LENGTH;
	alias_key = device_manager_get_alias_key (attestation->device_mgr, eid);

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

	status = attestation->primary_hash->start_sha256 (attestation->primary_hash);
	if (status != 0) {
		return status;
	}

	challenge_rq_len = cerberus_protocol_generate_challenge_request (attestation->rng, eid,
		attestation->state->txn.slot_num, attestation->state->txn.msg_buffer,
		sizeof (attestation->state->txn.msg_buffer));
	if (ROT_IS_ERROR (challenge_rq_len)) {
		status = challenge_rq_len;
		goto hash_cancel;
	}

	status = attestation->primary_hash->update (attestation->primary_hash,
		(uint8_t*) &challenge_rq->challenge, sizeof (struct attestation_challenge));
	if (ROT_IS_ERROR (status)) {
		goto hash_cancel;
	}

	status = attestation_requester_send_request_and_get_response (attestation, challenge_rq_len,
		device_addr, eid, true, false, CERBERUS_PROTOCOL_ATTESTATION_CHALLENGE);
	if (status != 0) {
		goto hash_cancel;
	}

	status = attestation->primary_hash->update (attestation->primary_hash,
		(uint8_t*) &challenge_rsp->challenge,
		sizeof (struct attestation_response) + challenge_rsp->challenge.digests_size);
	if (status != 0) {
		goto hash_cancel;
	}

	status = attestation_requester_verify_signature (attestation, attestation->primary_hash, eid,
		cerberus_protocol_challenge_get_signature (challenge_rsp),
		cerberus_protocol_challenge_get_signature_len (challenge_rsp,
		attestation->state->txn.msg_buffer_len), NULL);
	if (status != 0) {
		goto hash_cancel;
	}

	memmove (attestation->state->txn.msg_buffer,
		cerberus_protocol_challenge_get_pmr (challenge_rsp), SHA256_HASH_LENGTH);
	attestation->state->txn.msg_buffer_len = SHA256_HASH_LENGTH;

	status = attestation_requester_verify_pmr (attestation, active_cfm, component_id, eid, 0);

	/* TODO Implement additional Cerberus Challenge Protocol attestation flows
	 *	1) PMR(n) attestation using the Get PMR command
	 *	2) PMR measurement attestation using the Get Log and Get PMR commands
	 *	3) PMR measurement data attestation using the Get Attestation Data, Get Log, and Get PMR
	 *		commands
	 *	4) Manifest IDs attestation using the Get Config IDs command */

hash_cancel:
	if (!attestation->state->txn.hash_finish) {
		attestation->primary_hash->cancel (attestation->primary_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);

	return status;
}