Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2026 DMTF. All rights reserved.
4 : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : **/
6 :
7 : #include "internal/libspdm_responder_lib.h"
8 : #include "internal/libspdm_secured_message_lib.h"
9 :
10 : #if LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP
11 :
12 9 : bool libspdm_generate_key_exchange_rsp_hmac(libspdm_context_t *spdm_context,
13 : libspdm_session_info_t *session_info,
14 : uint8_t *hmac)
15 : {
16 : uint8_t hmac_data[LIBSPDM_MAX_HASH_SIZE];
17 : size_t hash_size;
18 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
19 : uint8_t slot_id;
20 : uint8_t *cert_chain_buffer;
21 : size_t cert_chain_buffer_size;
22 : uint8_t *th_curr_data;
23 : size_t th_curr_data_size;
24 : libspdm_th_managed_buffer_t th_curr;
25 : uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
26 : #endif /* LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT */
27 : bool result;
28 :
29 9 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
30 :
31 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
32 : slot_id = session_info->local_used_cert_chain_slot_id;
33 : LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
34 : if (slot_id == 0xFF) {
35 : result = libspdm_get_local_public_key_buffer(
36 : spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
37 : if (!result) {
38 : return false;
39 : }
40 : } else {
41 : libspdm_get_local_cert_chain_buffer(
42 : spdm_context, slot_id, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
43 : }
44 :
45 : result = libspdm_calculate_th_for_exchange(
46 : spdm_context, session_info, cert_chain_buffer, cert_chain_buffer_size, &th_curr);
47 : if (!result) {
48 : return false;
49 : }
50 : th_curr_data = libspdm_get_managed_buffer(&th_curr);
51 : th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
52 :
53 : result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
54 : th_curr_data, th_curr_data_size, hash_data);
55 : if (!result) {
56 : return false;
57 : }
58 :
59 : result = libspdm_hmac_all_with_response_finished_key(
60 : session_info->secured_message_context, hash_data, hash_size, hmac_data);
61 : if (!result) {
62 : return false;
63 : }
64 : #else
65 9 : result = libspdm_calculate_th_hmac_for_exchange_rsp(
66 : spdm_context, session_info, &hash_size, hmac_data);
67 9 : if (!result) {
68 0 : return false;
69 : }
70 : #endif /* LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT */
71 9 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hmac - "));
72 9 : LIBSPDM_INTERNAL_DUMP_DATA(hmac_data, hash_size);
73 9 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
74 9 : libspdm_copy_mem(hmac, hash_size, hmac_data, hash_size);
75 :
76 9 : return true;
77 : }
78 :
79 12 : bool libspdm_generate_key_exchange_rsp_signature(libspdm_context_t *spdm_context,
80 : libspdm_session_info_t *session_info,
81 : uint8_t slot_id,
82 : uint8_t *signature)
83 : {
84 : bool result;
85 : size_t signature_size;
86 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
87 : uint8_t *th_curr_data;
88 : size_t th_curr_data_size;
89 : libspdm_th_managed_buffer_t th_curr;
90 : const uint8_t *cert_chain_buffer;
91 : size_t cert_chain_buffer_size;
92 : #endif /* LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT */
93 : #if ((LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT) && (LIBSPDM_DEBUG_BLOCK_ENABLE)) || \
94 : !(LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT)
95 : uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
96 : #endif
97 : #if !(LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT) || (LIBSPDM_DEBUG_PRINT_ENABLE)
98 : size_t hash_size;
99 :
100 12 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
101 : #endif
102 :
103 12 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
104 0 : signature_size = libspdm_get_pqc_asym_signature_size(
105 : spdm_context->connection_info.algorithm.pqc_asym_algo);
106 : } else {
107 12 : signature_size = libspdm_get_asym_signature_size(
108 : spdm_context->connection_info.algorithm.base_asym_algo);
109 : }
110 :
111 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
112 : LIBSPDM_ASSERT((slot_id < SPDM_MAX_SLOT_COUNT) || (slot_id == 0xFF));
113 : if (slot_id == 0xFF) {
114 : result = libspdm_get_local_public_key_buffer(
115 : spdm_context, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
116 : if (!result) {
117 : return false;
118 : }
119 : } else {
120 : libspdm_get_local_cert_chain_buffer(
121 : spdm_context, slot_id, (const void **)&cert_chain_buffer, &cert_chain_buffer_size);
122 : }
123 :
124 : result = libspdm_calculate_th_for_exchange(
125 : spdm_context, session_info, cert_chain_buffer, cert_chain_buffer_size, &th_curr);
126 : if (!result) {
127 : return false;
128 : }
129 : th_curr_data = libspdm_get_managed_buffer(&th_curr);
130 : th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
131 :
132 : /* Debug code only - required for debug print of th_curr hash below*/
133 : LIBSPDM_DEBUG_CODE(
134 : if (!libspdm_hash_all(
135 : spdm_context->connection_info.algorithm.base_hash_algo,
136 : th_curr_data, th_curr_data_size, hash_data)) {
137 : return false;
138 : }
139 : );
140 : #else
141 12 : result = libspdm_calculate_th_hash_for_exchange(
142 : spdm_context, session_info, &hash_size, hash_data);
143 12 : if (!result) {
144 0 : return false;
145 : }
146 : #endif /* LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT */
147 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "th_curr hash - "));
148 12 : LIBSPDM_INTERNAL_DUMP_DATA(hash_data, hash_size);
149 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
150 :
151 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
152 : result = libspdm_responder_data_sign(
153 : spdm_context,
154 : spdm_context->connection_info.version,
155 : libspdm_slot_id_to_key_pair_id(spdm_context, slot_id, false),
156 : SPDM_KEY_EXCHANGE_RSP,
157 : spdm_context->connection_info.algorithm.base_asym_algo,
158 : spdm_context->connection_info.algorithm.pqc_asym_algo,
159 : spdm_context->connection_info.algorithm.base_hash_algo,
160 : false, th_curr_data, th_curr_data_size, signature, &signature_size);
161 : #else
162 24 : result = libspdm_responder_data_sign(
163 : spdm_context,
164 12 : spdm_context->connection_info.version,
165 12 : libspdm_slot_id_to_key_pair_id(spdm_context, slot_id, false),
166 : SPDM_KEY_EXCHANGE_RSP,
167 : spdm_context->connection_info.algorithm.base_asym_algo,
168 : spdm_context->connection_info.algorithm.pqc_asym_algo,
169 : spdm_context->connection_info.algorithm.base_hash_algo,
170 : true, hash_data, hash_size, signature, &signature_size);
171 : #endif /* LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT */
172 12 : if (result) {
173 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature - "));
174 12 : LIBSPDM_INTERNAL_DUMP_DATA(signature, signature_size);
175 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
176 : }
177 12 : return result;
178 : }
179 :
180 24 : libspdm_return_t libspdm_get_response_key_exchange(libspdm_context_t *spdm_context,
181 : size_t request_size,
182 : const void *request,
183 : size_t *response_size,
184 : void *response)
185 : {
186 : const spdm_key_exchange_request_t *spdm_request;
187 : spdm_key_exchange_response_t *spdm_response;
188 : size_t dhe_key_size;
189 : size_t kem_encap_key_size;
190 : size_t kem_cipher_text_size;
191 : size_t req_key_exchange_size;
192 : size_t rsp_key_exchange_size;
193 : uint32_t measurement_summary_hash_size;
194 : uint32_t signature_size;
195 : uint32_t hmac_size;
196 : uint8_t *ptr;
197 : const uint8_t *req_opaque_data;
198 : uint8_t *rsp_opaque_data;
199 : uint16_t opaque_data_length;
200 : bool result;
201 : uint8_t slot_id;
202 : uint32_t session_id;
203 : void *dhe_context;
204 : void *kem_context;
205 : libspdm_session_info_t *session_info;
206 : size_t total_size;
207 : uint16_t req_session_id;
208 : uint16_t rsp_session_id;
209 : libspdm_return_t status;
210 : size_t opaque_key_exchange_rsp_size;
211 : bool use_default_opaque_data;
212 : uint8_t th1_hash_data[LIBSPDM_MAX_HASH_SIZE];
213 : spdm_version_number_t secured_message_version;
214 24 : uint8_t peer_aead_limit_exponent = SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_DEFAULT;
215 : #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
216 : uint8_t req_slot_id;
217 : uint8_t mut_auth_requested;
218 : bool mandatory_mut_auth;
219 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
220 :
221 24 : spdm_request = request;
222 :
223 : /* -=[Check Parameters Phase]=- */
224 24 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_KEY_EXCHANGE);
225 :
226 24 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
227 0 : return libspdm_generate_error_response(spdm_context,
228 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
229 : SPDM_KEY_EXCHANGE,
230 : response_size, response);
231 : }
232 :
233 24 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
234 0 : return libspdm_generate_error_response(spdm_context,
235 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
236 : response_size, response);
237 : }
238 24 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
239 3 : return libspdm_responder_handle_response_state(
240 : spdm_context,
241 3 : spdm_request->header.request_response_code,
242 : response_size, response);
243 : }
244 21 : if (!libspdm_is_capabilities_flag_supported(
245 : spdm_context, false,
246 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
247 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)) {
248 0 : return libspdm_generate_error_response(
249 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
250 : SPDM_KEY_EXCHANGE, response_size, response);
251 : }
252 :
253 : /* While clearing MAC_CAP and setting ENCRYPT_CAP is legal according to DSP0274, libspdm
254 : * also implements DSP0277 secure messages, which requires at least MAC_CAP to be set.
255 : */
256 21 : if (!libspdm_is_capabilities_flag_supported(
257 : spdm_context, false,
258 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP,
259 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP)) {
260 0 : return libspdm_generate_error_response(
261 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
262 : SPDM_KEY_EXCHANGE, response_size, response);
263 : }
264 :
265 21 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
266 1 : return libspdm_generate_error_response(spdm_context,
267 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
268 : 0, response_size, response);
269 : }
270 20 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
271 7 : if ((spdm_context->connection_info.algorithm.other_params_support &
272 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) != SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
273 0 : return libspdm_generate_error_response(
274 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
275 : 0, response_size, response);
276 : }
277 : }
278 20 : if (spdm_context->last_spdm_request_session_id_valid) {
279 0 : return libspdm_generate_error_response(spdm_context,
280 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
281 : 0, response_size, response);
282 : }
283 :
284 20 : if (spdm_request->header.param1 > 0) {
285 4 : if (!libspdm_is_capabilities_flag_supported(
286 : spdm_context, false,
287 3 : 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) ||
288 3 : (spdm_context->connection_info.algorithm.measurement_spec == 0) ||
289 3 : (spdm_context->connection_info.algorithm.measurement_hash_algo == 0) ) {
290 1 : return libspdm_generate_error_response(
291 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
292 : 0, response_size, response);
293 : }
294 : }
295 :
296 19 : slot_id = spdm_request->header.param2;
297 :
298 19 : if (libspdm_is_capabilities_flag_supported(
299 : spdm_context, false,
300 : 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
301 17 : if (slot_id >= SPDM_MAX_SLOT_COUNT) {
302 1 : return libspdm_generate_error_response(spdm_context,
303 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
304 : response_size, response);
305 : }
306 16 : if (spdm_context->local_context.local_cert_chain_provision[slot_id] == NULL) {
307 0 : return libspdm_generate_error_response(spdm_context,
308 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
309 : response_size, response);
310 : }
311 : } else {
312 2 : if (slot_id != 0xff) {
313 1 : return libspdm_generate_error_response(spdm_context,
314 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
315 : response_size, response);
316 : }
317 1 : if (spdm_context->local_context.local_public_key_provision == NULL) {
318 0 : return libspdm_generate_error_response(spdm_context,
319 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
320 : response_size, response);
321 : }
322 : }
323 :
324 17 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
325 3 : if (spdm_context->connection_info.multi_key_conn_rsp && (slot_id != 0xff)) {
326 1 : if ((spdm_context->local_context.local_key_usage_bit_mask[slot_id] &
327 : SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE) == 0) {
328 1 : return libspdm_generate_error_response(
329 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
330 : }
331 : }
332 :
333 2 : if ((spdm_request->session_policy &
334 : SPDM_KEY_EXCHANGE_REQUEST_SESSION_POLICY_EVENT_ALL_POLICY) != 0) {
335 2 : if (!libspdm_is_capabilities_flag_supported(
336 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP)) {
337 0 : return libspdm_generate_error_response(spdm_context,
338 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
339 : response_size, response);
340 : }
341 : }
342 : }
343 :
344 16 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
345 0 : signature_size = libspdm_get_pqc_asym_signature_size(
346 : spdm_context->connection_info.algorithm.pqc_asym_algo);
347 : } else {
348 16 : signature_size = libspdm_get_asym_signature_size(
349 : spdm_context->connection_info.algorithm.base_asym_algo);
350 : }
351 16 : hmac_size = libspdm_get_hash_size(
352 : spdm_context->connection_info.algorithm.base_hash_algo);
353 16 : if (spdm_context->connection_info.algorithm.kem_alg != 0) {
354 0 : kem_encap_key_size = libspdm_get_kem_encap_key_size(
355 : spdm_context->connection_info.algorithm.kem_alg);
356 0 : kem_cipher_text_size = libspdm_get_kem_cipher_text_size(
357 : spdm_context->connection_info.algorithm.kem_alg);
358 0 : req_key_exchange_size = kem_encap_key_size;
359 0 : rsp_key_exchange_size = kem_cipher_text_size;
360 : } else {
361 32 : dhe_key_size = libspdm_get_dhe_pub_key_size(
362 16 : spdm_context->connection_info.algorithm.dhe_named_group);
363 16 : req_key_exchange_size = dhe_key_size;
364 16 : rsp_key_exchange_size = dhe_key_size;
365 : }
366 16 : measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
367 16 : spdm_context, false, spdm_request->header.param1);
368 :
369 16 : if ((measurement_summary_hash_size == 0) &&
370 14 : (spdm_request->header.param1 != SPDM_KEY_EXCHANGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH)) {
371 1 : return libspdm_generate_error_response(spdm_context,
372 : SPDM_ERROR_CODE_INVALID_REQUEST,
373 : 0, response_size, response);
374 : }
375 15 : if (request_size < sizeof(spdm_key_exchange_request_t) + req_key_exchange_size +
376 : sizeof(uint16_t)) {
377 1 : return libspdm_generate_error_response(spdm_context,
378 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
379 : response_size, response);
380 : }
381 14 : opaque_data_length = libspdm_read_uint16((const uint8_t *)request +
382 14 : sizeof(spdm_key_exchange_request_t) +
383 : req_key_exchange_size);
384 14 : if (request_size < sizeof(spdm_key_exchange_request_t) + req_key_exchange_size +
385 14 : sizeof(uint16_t) + opaque_data_length) {
386 0 : return libspdm_generate_error_response(spdm_context,
387 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
388 : response_size, response);
389 : }
390 14 : request_size = sizeof(spdm_key_exchange_request_t) + req_key_exchange_size +
391 14 : sizeof(uint16_t) + opaque_data_length;
392 :
393 14 : if (opaque_data_length != 0) {
394 14 : req_opaque_data = (const uint8_t *)request + sizeof(spdm_key_exchange_request_t) +
395 14 : req_key_exchange_size + sizeof(uint16_t);
396 :
397 : /*
398 : * Here allows integrator generate own opaque data for Key Exchange Response.
399 : * If libspdm_key_exchange_rsp_opaque_data() returns false,
400 : * libspdm will generate version selection opaque data.
401 : */
402 14 : opaque_key_exchange_rsp_size = *response_size - sizeof(spdm_key_exchange_response_t) -
403 14 : rsp_key_exchange_size - measurement_summary_hash_size -
404 14 : sizeof(uint16_t) - signature_size - hmac_size;
405 :
406 14 : use_default_opaque_data = false;
407 14 : result = libspdm_key_exchange_rsp_opaque_data(
408 14 : spdm_context, spdm_request->header.spdm_version,
409 14 : spdm_request->header.param1, slot_id, spdm_request->session_policy,
410 : req_opaque_data, opaque_data_length, NULL,
411 : &opaque_key_exchange_rsp_size);
412 14 : if (!result) {
413 13 : use_default_opaque_data = true;
414 13 : opaque_key_exchange_rsp_size =
415 13 : libspdm_get_opaque_data_version_selection_data_size(spdm_context);
416 : }
417 :
418 14 : if (use_default_opaque_data) {
419 13 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_data_length,
420 : req_opaque_data);
421 13 : if (!result) {
422 0 : return libspdm_generate_error_response(spdm_context,
423 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
424 : response_size, response);
425 : }
426 13 : status = libspdm_process_opaque_data_supported_version_data(
427 : spdm_context, opaque_data_length, req_opaque_data, &secured_message_version);
428 13 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
429 0 : return libspdm_generate_error_response(spdm_context,
430 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
431 : response_size, response);
432 : }
433 : /* DSP0277 1.3: reserve room for this Responder's AEADlimitOE. The size helper returns 0
434 : * unless the negotiated secured message version is 1.3 or later. */
435 13 : opaque_key_exchange_rsp_size +=
436 13 : libspdm_get_opaque_data_aead_limit_element_size(spdm_context,
437 : secured_message_version);
438 : } else {
439 : /* use response buffer to temporarily store opaque data */
440 1 : rsp_opaque_data = (uint8_t *)response;
441 1 : result = libspdm_key_exchange_rsp_opaque_data(
442 1 : spdm_context, spdm_request->header.spdm_version,
443 1 : spdm_request->header.param1, slot_id, spdm_request->session_policy,
444 : req_opaque_data, opaque_data_length, rsp_opaque_data,
445 : &opaque_key_exchange_rsp_size);
446 1 : if (!result) {
447 0 : return libspdm_generate_error_response(spdm_context,
448 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
449 : response_size, response);
450 : }
451 : /*
452 : * parse responder opaque data from integrator
453 : * to get secured_message_version.
454 : */
455 1 : status = libspdm_process_opaque_data_version_selection_data(
456 : spdm_context, opaque_key_exchange_rsp_size,
457 : rsp_opaque_data, &secured_message_version);
458 1 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
459 0 : return libspdm_generate_error_response(spdm_context,
460 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
461 : response_size, response);
462 : }
463 : }
464 : /* DSP0277 1.3: read the Requester's AEAD limit from the request (absent -> default 64).
465 : * This is independent of whether the Responder builds default or custom response opaque
466 : * data, so it runs for both paths. */
467 14 : status = libspdm_process_opaque_data_aead_limit(
468 : spdm_context, secured_message_version, opaque_data_length, req_opaque_data,
469 : &peer_aead_limit_exponent);
470 14 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
471 0 : return libspdm_generate_error_response(spdm_context,
472 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
473 : response_size, response);
474 : }
475 : } else {
476 0 : secured_message_version = 0;
477 0 : opaque_key_exchange_rsp_size = 0;
478 0 : req_opaque_data = NULL;
479 : }
480 :
481 14 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
482 14 : spdm_request->header.request_response_code);
483 :
484 14 : if (libspdm_is_capabilities_flag_supported(
485 : spdm_context, false,
486 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
487 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
488 3 : hmac_size = 0;
489 : }
490 :
491 14 : req_session_id = spdm_request->req_session_id;
492 14 : rsp_session_id = libspdm_allocate_rsp_session_id(spdm_context, false);
493 14 : if (rsp_session_id == ((INVALID_SESSION_ID & 0xFFFF0000) >> 16)) {
494 0 : return libspdm_generate_error_response(
495 : spdm_context, SPDM_ERROR_CODE_SESSION_LIMIT_EXCEEDED, 0,
496 : response_size, response);
497 : }
498 14 : session_id = libspdm_generate_session_id(req_session_id, rsp_session_id);
499 14 : session_info = libspdm_assign_session_id(spdm_context, session_id, secured_message_version,
500 : false);
501 14 : if (session_info == NULL) {
502 0 : return libspdm_generate_error_response(
503 : spdm_context, SPDM_ERROR_CODE_SESSION_LIMIT_EXCEEDED, 0,
504 : response_size, response);
505 : }
506 :
507 : /* DSP0277 1.3: program the session's AEAD limit (min of local and peer) when secured message
508 : * version 1.3 was negotiated. */
509 14 : if (libspdm_get_version_from_version_number(secured_message_version) >=
510 : SECURED_SPDM_VERSION_13) {
511 1 : libspdm_apply_aead_limit_to_session(spdm_context, session_info,
512 : peer_aead_limit_exponent);
513 : }
514 :
515 14 : total_size = sizeof(spdm_key_exchange_response_t) + rsp_key_exchange_size +
516 14 : measurement_summary_hash_size + sizeof(uint16_t) +
517 14 : opaque_key_exchange_rsp_size + signature_size + hmac_size;
518 :
519 14 : LIBSPDM_ASSERT(*response_size >= total_size);
520 14 : *response_size = total_size;
521 14 : libspdm_zero_mem(response, *response_size);
522 14 : spdm_response = response;
523 :
524 14 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
525 14 : spdm_response->header.request_response_code = SPDM_KEY_EXCHANGE_RSP;
526 :
527 14 : if (libspdm_is_capabilities_flag_supported(
528 : spdm_context, false,
529 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
530 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
531 0 : spdm_response->header.param1 = spdm_context->local_context.heartbeat_period;
532 : } else {
533 14 : spdm_response->header.param1 = 0x00;
534 : }
535 :
536 14 : session_info->local_used_cert_chain_slot_id = slot_id;
537 :
538 14 : if (libspdm_is_capabilities_flag_supported(
539 : spdm_context, false,
540 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
541 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
542 0 : session_info->heartbeat_period = spdm_context->local_context.heartbeat_period;
543 : } else {
544 14 : session_info->heartbeat_period = 0x00;
545 : }
546 :
547 14 : spdm_response->rsp_session_id = rsp_session_id;
548 14 : spdm_response->mut_auth_requested = 0;
549 14 : spdm_response->req_slot_id_param = 0;
550 :
551 : #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
552 14 : if (libspdm_is_capabilities_flag_supported(
553 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP)) {
554 3 : req_slot_id = 0;
555 :
556 : mut_auth_requested =
557 3 : libspdm_key_exchange_start_mut_auth(spdm_context,
558 : session_id,
559 3 : spdm_context->connection_info.version,
560 : slot_id,
561 : &req_slot_id,
562 3 : spdm_request->session_policy,
563 : opaque_data_length,
564 : req_opaque_data,
565 : &mandatory_mut_auth);
566 3 : if (mut_auth_requested != 0) {
567 2 : const bool req_mut_auth_cap = libspdm_is_capabilities_flag_supported(
568 : spdm_context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP, 0);
569 2 : const bool req_encap_cap = libspdm_is_capabilities_flag_supported(
570 : spdm_context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCAP_CAP, 0);
571 2 : const bool need_encap =
572 : (mut_auth_requested ==
573 2 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST) ||
574 : (mut_auth_requested ==
575 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS);
576 :
577 : /* If Integrator requires mutual authentication but Requester does not support mutual
578 : * authentication, or Integrator requires the encapsulated mutual authentication flow
579 : * and Requester does not support encapsulated messages, then return an error to
580 : * Requester. */
581 2 : if (mandatory_mut_auth && (!req_mut_auth_cap || (need_encap && !req_encap_cap))) {
582 2 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_13) {
583 1 : libspdm_free_session_id(spdm_context, session_id);
584 1 : return libspdm_generate_error_response(spdm_context,
585 : SPDM_ERROR_CODE_INVALID_POLICY, 0,
586 : response_size, response);
587 : } else {
588 1 : libspdm_free_session_id(spdm_context, session_id);
589 1 : return libspdm_generate_error_response(spdm_context,
590 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
591 : response_size, response);
592 : }
593 : }
594 :
595 0 : if (!need_encap) {
596 0 : spdm_response->mut_auth_requested = mut_auth_requested;
597 0 : spdm_response->req_slot_id_param = req_slot_id;
598 0 : } else if (need_encap && req_encap_cap) {
599 0 : spdm_response->mut_auth_requested = mut_auth_requested;
600 0 : session_info->peer_used_cert_chain_slot_id = req_slot_id;
601 0 : libspdm_init_mut_auth_encap_state(spdm_context, mut_auth_requested);
602 : }
603 : }
604 : }
605 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
606 :
607 12 : if (!libspdm_get_random_number(SPDM_RANDOM_DATA_SIZE, spdm_response->random_data)) {
608 0 : libspdm_free_session_id(spdm_context, session_id);
609 0 : return libspdm_generate_error_response(spdm_context,
610 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
611 : response_size, response);
612 : }
613 :
614 12 : ptr = (void *)(spdm_response + 1);
615 12 : if (spdm_context->connection_info.algorithm.kem_alg != 0) {
616 0 : kem_context = libspdm_secured_message_kem_new(
617 0 : spdm_context->connection_info.version,
618 : spdm_context->connection_info.algorithm.kem_alg, false);
619 0 : if (kem_context == NULL) {
620 0 : libspdm_free_session_id(spdm_context, session_id);
621 0 : return libspdm_generate_error_response(spdm_context,
622 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
623 : response_size, response);
624 : }
625 :
626 0 : result = libspdm_secured_message_kem_encapsulate(
627 : spdm_context->connection_info.algorithm.kem_alg,
628 : kem_context,
629 : (const uint8_t *)request + sizeof(spdm_key_exchange_request_t),
630 : kem_encap_key_size, ptr, &kem_cipher_text_size, session_info->secured_message_context);
631 0 : libspdm_secured_message_kem_free(
632 : spdm_context->connection_info.algorithm.kem_alg,
633 : kem_context);
634 0 : if (!result) {
635 0 : libspdm_free_session_id(spdm_context, session_id);
636 0 : return libspdm_generate_error_response(spdm_context,
637 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
638 : response_size, response);
639 : }
640 :
641 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc Self cipher_text (0x%zx):\n", kem_cipher_text_size));
642 0 : LIBSPDM_INTERNAL_DUMP_HEX(ptr, kem_cipher_text_size);
643 :
644 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc peer encap_key (0x%zx):\n", kem_encap_key_size));
645 0 : LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)request +
646 : sizeof(spdm_key_exchange_request_t),
647 : kem_encap_key_size);
648 :
649 0 : ptr += kem_cipher_text_size;
650 : } else {
651 12 : dhe_context = libspdm_secured_message_dhe_new(
652 12 : spdm_context->connection_info.version,
653 12 : spdm_context->connection_info.algorithm.dhe_named_group, false);
654 12 : if (dhe_context == NULL) {
655 0 : libspdm_free_session_id(spdm_context, session_id);
656 0 : return libspdm_generate_error_response(spdm_context,
657 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
658 : response_size, response);
659 : }
660 :
661 12 : result = libspdm_secured_message_dhe_generate_key(
662 12 : spdm_context->connection_info.algorithm.dhe_named_group,
663 : dhe_context, ptr, &dhe_key_size);
664 12 : if (!result) {
665 0 : libspdm_secured_message_dhe_free(
666 0 : spdm_context->connection_info.algorithm.dhe_named_group,
667 : dhe_context);
668 0 : libspdm_free_session_id(spdm_context, session_id);
669 0 : return libspdm_generate_error_response(spdm_context,
670 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
671 : response_size, response);
672 : }
673 :
674 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc SelfKey (0x%zx):\n", dhe_key_size));
675 12 : LIBSPDM_INTERNAL_DUMP_HEX(ptr, dhe_key_size);
676 :
677 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc peer_key (0x%zx):\n", dhe_key_size));
678 12 : LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)request +
679 : sizeof(spdm_key_exchange_request_t),
680 : dhe_key_size);
681 :
682 12 : result = libspdm_secured_message_dhe_compute_key(
683 12 : spdm_context->connection_info.algorithm.dhe_named_group,
684 : dhe_context,
685 : (const uint8_t *)request + sizeof(spdm_key_exchange_request_t),
686 : dhe_key_size, session_info->secured_message_context);
687 12 : libspdm_secured_message_dhe_free(
688 12 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
689 12 : if (!result) {
690 0 : libspdm_free_session_id(spdm_context, session_id);
691 0 : return libspdm_generate_error_response(spdm_context,
692 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
693 : response_size, response);
694 : }
695 :
696 12 : ptr += dhe_key_size;
697 : }
698 :
699 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
700 12 : if (libspdm_is_capabilities_flag_supported(
701 2 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) &&
702 2 : ((spdm_request->header.param1 == SPDM_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH) ||
703 1 : (spdm_request->header.param1 == SPDM_REQUEST_ALL_MEASUREMENTS_HASH))) {
704 2 : result = libspdm_generate_measurement_summary_hash(
705 : spdm_context,
706 2 : spdm_context->connection_info.version,
707 : spdm_context->connection_info.algorithm.base_hash_algo,
708 2 : spdm_context->connection_info.algorithm.measurement_spec,
709 : spdm_context->connection_info.algorithm.measurement_hash_algo,
710 2 : spdm_request->header.param1,
711 : ptr,
712 : measurement_summary_hash_size);
713 :
714 2 : if (!result) {
715 0 : libspdm_free_session_id(spdm_context, session_id);
716 0 : return libspdm_generate_error_response(spdm_context,
717 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
718 : response_size, response);
719 : }
720 : }
721 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP */
722 :
723 12 : ptr += measurement_summary_hash_size;
724 :
725 12 : libspdm_write_uint16(ptr, (uint16_t)opaque_key_exchange_rsp_size);
726 12 : ptr += sizeof(uint16_t);
727 :
728 12 : if (opaque_key_exchange_rsp_size != 0) {
729 12 : if (use_default_opaque_data) {
730 11 : size_t version_selection_size =
731 11 : libspdm_get_opaque_data_version_selection_data_size(spdm_context);
732 11 : libspdm_build_opaque_data_version_selection_data(
733 : spdm_context, secured_message_version, &version_selection_size, ptr);
734 : /* DSP0277 1.3: advertise this Responder's own AEAD limit. opaque_key_exchange_rsp_size
735 : * is the reserved opaque data capacity (version selection + AEAD limit); the append is a
736 : * no-op unless the negotiated secured message version is 1.3 or later. */
737 11 : libspdm_build_opaque_data_aead_limit_element(
738 : spdm_context, secured_message_version, &opaque_key_exchange_rsp_size, ptr);
739 : } else {
740 1 : result = libspdm_key_exchange_rsp_opaque_data(
741 1 : spdm_context, spdm_request->header.spdm_version,
742 1 : spdm_request->header.param1, slot_id, spdm_request->session_policy,
743 : req_opaque_data, opaque_data_length, ptr,
744 : &opaque_key_exchange_rsp_size);
745 1 : if (!result) {
746 0 : libspdm_free_session_id(spdm_context, session_id);
747 0 : return libspdm_generate_error_response(spdm_context,
748 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
749 : response_size, response);
750 : }
751 : }
752 12 : ptr += opaque_key_exchange_rsp_size;
753 : }
754 :
755 12 : status = libspdm_append_message_k(spdm_context, session_info, false, request, request_size);
756 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
757 0 : libspdm_free_session_id(spdm_context, session_id);
758 0 : return libspdm_generate_error_response(spdm_context,
759 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
760 : response_size, response);
761 : }
762 :
763 12 : status = libspdm_append_message_k(spdm_context, session_info, false, spdm_response,
764 12 : (size_t)ptr - (size_t)spdm_response);
765 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
766 0 : libspdm_free_session_id(spdm_context, session_id);
767 0 : return libspdm_generate_error_response(spdm_context,
768 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
769 : response_size, response);
770 : }
771 12 : result = libspdm_generate_key_exchange_rsp_signature(
772 : spdm_context, session_info, slot_id, ptr);
773 12 : if (!result) {
774 0 : libspdm_free_session_id(spdm_context, session_id);
775 0 : return libspdm_generate_error_response(
776 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
777 : 0, response_size, response);
778 : }
779 :
780 12 : status = libspdm_append_message_k(spdm_context, session_info, false, ptr, signature_size);
781 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
782 0 : libspdm_free_session_id(spdm_context, session_id);
783 0 : return libspdm_generate_error_response(spdm_context,
784 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
785 : response_size, response);
786 : }
787 :
788 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_handshake_key[%x]\n", session_id));
789 12 : result = libspdm_calculate_th1_hash(spdm_context, session_info, false, th1_hash_data);
790 12 : if (!result) {
791 0 : libspdm_free_session_id(spdm_context, session_id);
792 0 : return libspdm_generate_error_response(spdm_context,
793 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
794 : response_size, response);
795 : }
796 12 : result = libspdm_generate_session_handshake_key(
797 : session_info->secured_message_context, th1_hash_data);
798 12 : if (!result) {
799 0 : libspdm_free_session_id(spdm_context, session_id);
800 0 : return libspdm_generate_error_response(spdm_context,
801 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
802 : response_size, response);
803 : }
804 :
805 12 : ptr += signature_size;
806 :
807 12 : if (!libspdm_is_capabilities_flag_supported(
808 : spdm_context, false,
809 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
810 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
811 9 : result = libspdm_generate_key_exchange_rsp_hmac(spdm_context, session_info, ptr);
812 9 : if (!result) {
813 0 : libspdm_free_session_id(spdm_context, session_id);
814 0 : return libspdm_generate_error_response(
815 : spdm_context,
816 : SPDM_ERROR_CODE_UNSPECIFIED,
817 : 0, response_size, response);
818 : }
819 9 : status = libspdm_append_message_k(spdm_context, session_info, false, ptr, hmac_size);
820 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
821 0 : libspdm_free_session_id(spdm_context, session_id);
822 0 : return libspdm_generate_error_response(
823 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
824 : 0, response_size, response);
825 : }
826 :
827 9 : ptr += hmac_size;
828 : }
829 :
830 : #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP
831 12 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
832 1 : if ((spdm_request->session_policy &
833 : SPDM_KEY_EXCHANGE_REQUEST_SESSION_POLICY_EVENT_ALL_POLICY) != 0) {
834 1 : if (!libspdm_event_subscribe(spdm_context, spdm_context->connection_info.version,
835 : session_id, LIBSPDM_EVENT_SUBSCRIBE_ALL, 0, 0, NULL)) {
836 0 : libspdm_free_session_id(spdm_context, session_id);
837 0 : return libspdm_generate_error_response(spdm_context,
838 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
839 : response_size, response);
840 : }
841 : }
842 : }
843 : #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */
844 :
845 12 : session_info->mut_auth_requested = spdm_response->mut_auth_requested;
846 12 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
847 4 : session_info->session_policy = spdm_request->session_policy;
848 : }
849 12 : libspdm_set_session_state(spdm_context, session_id, LIBSPDM_SESSION_STATE_HANDSHAKING);
850 :
851 12 : return LIBSPDM_STATUS_SUCCESS;
852 : }
853 :
854 : #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */
|