in core/spdm/spdm_commands.c [1981:2161]
static int spdm_negotiate_algorithms_construct_response (struct spdm_state *state,
const struct spdm_device_capability *local_capabilities,
const struct spdm_local_device_algorithms *local_device_algorithms,
struct spdm_negotiate_algorithms_request *rq,
struct spdm_negotiate_algorithms_response_no_ext_alg *resp_no_ext_alg, int *spdm_error)
{
int status = CMD_HANDLER_SPDM_RESPONDER_INVALID_REQUEST;
size_t response_size;
uint8_t spdm_version;
struct spdm_algorithm_request *algstruct_table;
size_t i_algstruct;
struct spdm_negotiate_algorithms_response *resp =
(struct spdm_negotiate_algorithms_response*) resp_no_ext_alg;
const struct spdm_device_algorithms *local_algorithms;
const struct spdm_local_device_algorithms_priority_table *local_algo_priority_table;
uint32_t measurement_hash_algo;
*spdm_error = SPDM_ERROR_INVALID_REQUEST;
local_algorithms = &local_device_algorithms->device_algorithms;
local_algo_priority_table = &local_device_algorithms->algorithms_priority_table;
/* Construct the response. */
memset (resp, 0, sizeof (struct spdm_negotiate_algorithms_response_no_ext_alg));
resp->header.spdm_major_version = rq->header.spdm_major_version;
resp->header.spdm_minor_version = rq->header.spdm_minor_version;
resp->num_alg_structure_tables = rq->num_alg_structure_tables;
/* Respond with the same number of Algorithms Structure Tables as requested. */
response_size = spdm_negotiate_algorithms_rsp_size (rq);
resp->header.req_rsp_code = SPDM_RESPONSE_NEGOTIATE_ALGORITHMS;
resp->reserved = 0;
resp->length = (uint16_t) response_size;
/* Save requester algorithms in connection info. */
state->connection_info.peer_algorithms.measurement_spec = rq->measurement_specification;
if (rq->measurement_specification != 0) {
/* Measurement hash algorithm is a responder selected value. It is not negotiated. */
measurement_hash_algo = local_algorithms->measurement_hash_algo;
}
else {
measurement_hash_algo = 0;
}
state->connection_info.peer_algorithms.base_asym_algo = rq->base_asym_algo;
state->connection_info.peer_algorithms.base_hash_algo = rq->base_hash_algo;
/* Process the request algorithm structures. */
spdm_version = SPDM_MAKE_VERSION (rq->header.spdm_major_version, rq->header.spdm_minor_version);
algstruct_table = spdm_negotiate_algorithms_req_algstruct_table (rq);
for (i_algstruct = 0; i_algstruct < rq->num_alg_structure_tables; ++i_algstruct) {
switch (algstruct_table->alg_type) {
case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_DHE:
if (algstruct_table->alg_supported == 0) {
goto exit;
}
resp_no_ext_alg->algstruct_table[i_algstruct].alg_type = algstruct_table->alg_type;
resp_no_ext_alg->algstruct_table[i_algstruct].fixed_alg_count = 2;
resp_no_ext_alg->algstruct_table[i_algstruct].ext_alg_count = 0;
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported =
(uint16_t) spdm_prioritize_algorithm (
local_algo_priority_table->dhe_priority_table,
local_algo_priority_table->dhe_priority_table_count,
local_algorithms->dhe_named_group, algstruct_table->alg_supported);
state->connection_info.peer_algorithms.dhe_named_group =
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported;
break;
case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_AEAD:
if (algstruct_table->alg_supported == 0) {
goto exit;
}
resp_no_ext_alg->algstruct_table[i_algstruct].alg_type = algstruct_table->alg_type;
resp_no_ext_alg->algstruct_table[i_algstruct].fixed_alg_count = 2;
resp_no_ext_alg->algstruct_table[i_algstruct].ext_alg_count = 0;
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported =
(uint16_t) spdm_prioritize_algorithm (
local_algo_priority_table->aead_priority_table,
local_algo_priority_table->aead_priority_table_count,
local_algorithms->aead_cipher_suite, algstruct_table->alg_supported);
state->connection_info.peer_algorithms.aead_cipher_suite =
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported;
break;
case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_REQ_BASE_ASYM_ALG:
if (algstruct_table->alg_supported == 0) {
goto exit;
}
resp_no_ext_alg->algstruct_table[i_algstruct].alg_type = algstruct_table->alg_type;
resp_no_ext_alg->algstruct_table[i_algstruct].fixed_alg_count = 2;
resp_no_ext_alg->algstruct_table[i_algstruct].ext_alg_count = 0;
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported =
(uint16_t) spdm_prioritize_algorithm (
local_algo_priority_table->req_asym_priority_table,
local_algo_priority_table->req_asym_priority_table_count,
local_algorithms->req_base_asym_alg, algstruct_table->alg_supported);
state->connection_info.peer_algorithms.req_base_asym_alg =
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported;
break;
case SPDM_NEGOTIATE_ALGORITHMS_STRUCT_TABLE_ALG_TYPE_KEY_SCHEDULE:
if (algstruct_table->alg_supported == 0) {
goto exit;
}
resp_no_ext_alg->algstruct_table[i_algstruct].alg_type = algstruct_table->alg_type;
resp_no_ext_alg->algstruct_table[i_algstruct].fixed_alg_count = 2;
resp_no_ext_alg->algstruct_table[i_algstruct].ext_alg_count = 0;
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported =
(uint16_t) spdm_prioritize_algorithm (
local_algo_priority_table->key_schedule_priority_table,
local_algo_priority_table->key_schedule_priority_table_count,
local_algorithms->key_schedule, algstruct_table->alg_supported);
state->connection_info.peer_algorithms.key_schedule =
resp_no_ext_alg->algstruct_table[i_algstruct].alg_supported;
break;
}
/* Go to the next algstruct_table entry. */
algstruct_table =
spdm_negotiate_algorithms_get_next_alg_struct_table_entry (algstruct_table);
}
if ((local_capabilities->flags.meas_cap == SPDM_MEASUREMENT_RSP_CAP_MEASUREMENTS_WITHOUT_SIG) ||
(local_capabilities->flags.meas_cap == SPDM_MEASUREMENT_RSP_CAP_MEASUREMENTS_WITH_SIG)) {
resp->measurement_specification =
(uint8_t) spdm_prioritize_algorithm (
local_algo_priority_table->measurement_spec_priority_table,
local_algo_priority_table->measurement_spec_priority_table_count,
local_algorithms->measurement_spec,
state->connection_info.peer_algorithms.measurement_spec);
/* Measurement hash algorithm is not negotiated but rather selected by the responder.
* Thus, there is no priority table for measurement hash algorithm. */
resp->measurement_hash_algo = spdm_prioritize_algorithm (NULL, 0,
local_algorithms->measurement_hash_algo, measurement_hash_algo);
}
else {
resp->measurement_specification = 0;
resp->measurement_hash_algo = 0;
}
state->connection_info.peer_algorithms.measurement_spec = resp->measurement_specification;
state->connection_info.peer_algorithms.measurement_hash_algo = resp->measurement_hash_algo;
resp->base_asym_sel = spdm_prioritize_algorithm (local_algo_priority_table->asym_priority_table,
local_algo_priority_table->asym_priority_table_count, local_algorithms->base_asym_algo,
state->connection_info.peer_algorithms.base_asym_algo);
state->connection_info.peer_algorithms.base_asym_algo = resp->base_asym_sel;
resp->base_hash_sel = spdm_prioritize_algorithm (local_algo_priority_table->hash_priority_table,
local_algo_priority_table->hash_priority_table_count, local_algorithms->base_hash_algo,
state->connection_info.peer_algorithms.base_hash_algo);
state->connection_info.peer_algorithms.base_hash_algo = resp->base_hash_sel;
if (spdm_version >= SPDM_VERSION_1_2) {
resp->other_params_selection.opaque_data_format =
(uint8_t) spdm_prioritize_algorithm (
local_algo_priority_table->other_params_support_priority_table,
local_algo_priority_table->other_params_support_priority_table_count,
local_algorithms->other_params_support.opaque_data_format,
rq->other_params_support.opaque_data_format);
state->connection_info.peer_algorithms.other_params_support.opaque_data_format =
resp->other_params_selection.opaque_data_format;
}
status = 0;
*spdm_error = SPDM_ERROR_RESERVED;
exit:
return status;
}