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