static int spdm_negotiate_algorithms_construct_response()

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