in core/spdm/spdm_commands.c [2447:2600]
int spdm_get_digests (const struct cmd_interface_spdm_responder *spdm_responder,
struct cmd_interface_msg *request)
{
int status;
int spdm_error;
struct spdm_get_digests_request *spdm_request;
struct spdm_get_digests_response *spdm_response;
uint8_t spdm_version;
uint32_t response_size;
int hash_size;
const struct spdm_transcript_manager *transcript_manager;
struct spdm_state *state;
const struct spdm_device_capability *local_capabilities;
const struct riot_key_manager *key_manager;
const struct hash_engine *hash_engine;
enum hash_type hash_type;
struct spdm_secure_session_manager *session_manager;
struct spdm_secure_session *session = NULL;
if ((spdm_responder == NULL) || (request == NULL)) {
return CMD_HANDLER_SPDM_RESPONDER_INVALID_ARGUMENT;
}
transcript_manager = spdm_responder->transcript_manager;
state = spdm_responder->state;
local_capabilities = spdm_responder->local_capabilities;
key_manager = spdm_responder->key_manager;
hash_engine = spdm_responder->hash_engine[0];
hash_type = spdm_get_hash_type (state->connection_info.peer_algorithms.base_hash_algo);
session_manager = spdm_responder->session_manager;
/* Validate the request. */
if (request->payload_length < sizeof (struct spdm_get_digests_request)) {
status = CMD_HANDLER_SPDM_RESPONDER_INVALID_REQUEST;
spdm_error = SPDM_ERROR_INVALID_REQUEST;
goto exit;
}
spdm_request = (struct spdm_get_digests_request*) request->payload;
spdm_version = SPDM_MAKE_VERSION (spdm_request->header.spdm_major_version,
spdm_request->header.spdm_minor_version);
if (spdm_version != spdm_get_connection_version (state)) {
status = CMD_HANDLER_SPDM_RESPONDER_VERSION_MISMATCH;
spdm_error = SPDM_ERROR_VERSION_MISMATCH;
goto exit;
}
/* Verify SPDM state. */
if (state->response_state != SPDM_RESPONSE_STATE_NORMAL) {
spdm_handle_response_state (state, &spdm_error);
status = CMD_HANDLER_SPDM_RESPONDER_INTERNAL_ERROR;
goto exit;
}
if (state->connection_info.connection_state < SPDM_CONNECTION_STATE_NEGOTIATED) {
status = CMD_HANDLER_SPDM_RESPONDER_UNEXPECTED_REQUEST;
spdm_error = SPDM_ERROR_UNEXPECTED_REQUEST;
goto exit;
}
/* Check if the certificate capability is supported. */
if (local_capabilities->flags.cert_cap == 0) {
status = CMD_HANDLER_SPDM_RESPONDER_UNSUPPORTED_CAPABILITY;
spdm_error = SPDM_ERROR_UNSUPPORTED_REQUEST;
goto exit;
}
/* Check if a session is ongoing. */
if ((session_manager != NULL) &&
(session_manager->is_last_session_id_valid (session_manager) == true)) {
session = session_manager->get_session (session_manager,
session_manager->get_last_session_id (session_manager));
if (session == NULL) {
status = CMD_HANDLER_SPDM_RESPONDER_INVALID_SESSION_STATE;
spdm_error = SPDM_ERROR_UNEXPECTED_REQUEST;
goto exit;
}
/* Check session state. */
if (session->session_state != SPDM_SESSION_STATE_ESTABLISHED) {
status = CMD_HANDLER_SPDM_RESPONDER_INVALID_SESSION_STATE;
spdm_error = SPDM_ERROR_UNEXPECTED_REQUEST;
goto exit;
}
}
/* Reset transcript manager state as per request code. */
spdm_reset_transcript_via_request_code (state, transcript_manager, SPDM_REQUEST_GET_DIGESTS);
/* Add request to M1M2 hash context. */
if (session == NULL) {
status = transcript_manager->update (transcript_manager, TRANSCRIPT_CONTEXT_TYPE_M1M2,
request->payload, sizeof (struct spdm_get_digests_request), false,
SPDM_MAX_SESSION_COUNT);
if (status != 0) {
spdm_error = SPDM_ERROR_UNSPECIFIED;
goto exit;
}
}
/* Construct the response. */
hash_size = hash_get_hash_length (hash_type);
if (hash_size == HASH_ENGINE_UNKNOWN_HASH) {
status = HASH_ENGINE_UNKNOWN_HASH;
spdm_error = SPDM_ERROR_UNSPECIFIED;
goto exit;
}
response_size = sizeof (struct spdm_get_digests_response) + hash_size;
if (response_size > cmd_interface_msg_get_max_response (request)) {
status = CMD_HANDLER_SPDM_RESPONDER_RESPONSE_TOO_LARGE;
spdm_error = SPDM_ERROR_UNSPECIFIED;
goto exit;
}
spdm_response = (struct spdm_get_digests_response*) request->payload;
memset (spdm_response, 0, response_size);
spdm_populate_header (&spdm_response->header, SPDM_RESPONSE_GET_DIGESTS,
SPDM_GET_MINOR_VERSION (spdm_version));
spdm_response->slot_mask = 1;
/* Get the digest of the certificate chain. */
status = spdm_get_certificate_chain_digest (key_manager, hash_engine, hash_type,
(uint8_t*) (spdm_response + 1));
if (status != 0) {
spdm_error = SPDM_ERROR_UNSPECIFIED;
goto exit;
}
/* Add response to M1M2 hash context. */
if (session == NULL) {
status = transcript_manager->update (transcript_manager, TRANSCRIPT_CONTEXT_TYPE_M1M2,
(uint8_t*) spdm_response, response_size, false, SPDM_MAX_SESSION_COUNT);
if (status != 0) {
spdm_error = SPDM_ERROR_UNSPECIFIED;
goto exit;
}
}
/* Set the payload length. */
cmd_interface_msg_set_message_payload_length (request, response_size);
/* Update connection state */
if (state->connection_info.connection_state < SPDM_CONNECTION_STATE_AFTER_DIGESTS) {
spdm_set_connection_state (state, SPDM_CONNECTION_STATE_AFTER_DIGESTS);
}
exit:
if (status != 0) {
spdm_generate_error_response (request, state->connection_info.version.minor_version,
spdm_error, 0x00, NULL, 0, SPDM_REQUEST_GET_DIGESTS, status);
}
return 0;
}