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